+2009-06-20 Sampo Niskanen
+
+ * New edit motor configurations dialog
+ * Changed FreeformFinSet to throw checked exceptions
+
+2009-06-11 Sampo Niskanen
+
+ * Added search field to motor chooser dialog
+
+2009-06-09 Sampo Niskanen
+
+ * Release 0.9.1
+
2009-06-08 Sampo Niskanen
* Fixed loading of icons from JAR
+OpenRocket 0.9.2 (future):
+---------------------------
+
+- a new and enhanced "Edit motor configurations" dialog
+- a search field in the motor selection dialog
+
+
OpenRocket 0.9.1 (2009-06-09):
-------------------------------
-GUI:
+Feature roadmap for OpenRocket 1.0
-- Preferences dialog
+Must-have:
-BUGS:
+- Exporting flight data
+- Store custom materials
+- Read more thrust curve formats / go through thrust curves and correct errors
+- Create application icon and take into use
+- Fix engine block icons
+- Progress and error dialogs when reading/writing files
-COMPUTATION:
+Maybe:
-
-FILE/STORAGE:
-
-
-OTHER:
-
-- web-sivut
-
-
-DIPPA:
-
-
-
-
--------------------
-
-LATER:
-
-- Simulation delete/copy/paste hotkeys
- (either component or simulation selected, but not both)
-- Add BodyComponent at end of rocket when no component is selected
-- Showing events in plot (maybe future)
-- Search field in motor selection dialog
+- Reading (writing) .RKT format
+- Showing events in plots
- Through-the-wall fins
-- Store materials
-
-- Streamer CD estimation
-
-- exporting (maybe later)
-
- Make ThicknessRingComponent implement RadialParent and allow
attaching components to a TubeCoupler
+- Reading thrust curves from external directory
+Postponed:
+- Importing flight data
-DONE:
-- Automatic diameters of body components
-- Copy/paste
+Done:
-18.4.:
-- Esc, Ctrl-Z and Y etc.
-- Look and feel
-
-19.4.:
-- Nose cone and transition shoulders in GUI
-- zoom, cut/copy/paste etc. icons
-
-23.4.:
-- Figure or rocket not updating when using a new BasicFrame
-
-24.4.:
-- File save and load
-- Motor configuration editing (pre-alpha)
-- Save simulations
-
-25.4.:
-- Multi-stages simulation (pre-alpha)
-- Make sure simulations end
-- Mass and CG overrides (pre-alpha)
-- General loader
-
-26.4.:
-- Centering ring inner diameter automatics (pre-alpha)
-- Landing simulation (pre-alpha ??)
-- Parachute/Streamer editing in GUI (pre-alpha)
-- Launch lug editing in GUI (pre-alpha)
-
-29.4.:
-- Actual plotting done
-- Refactored source code packages
-
-2.5.:
-- Plotting (pre-alpha)
-- Gravity model
-- More units and specific custom units (angle, temperature, ...)
-- Transition/Nose cone description text wrapping
-- Fin set CP jumps at Mach 0.9
-
-- Error dialogs for load/save/etc
-
-3.5.:
-- More materials (pre-alpha)
-- File opening from command line
-
-9.5.:
-- Rocket configuration dialog
-- Warnings in poor conditions (transition supersonic)
-- New or old fin-body interference?
-- poista tiedot laminaarisesta vastuksesta
-- vertailuosio
-
-11.5.:
-- Better default values for components
-- Component analysis dialog show zero total mass and CG
-- Compression support in save
-- Simulation storage options
-
-12.5.:
-- Load simulations
-- Update file version to 1.0
-
-13.5.:
-- statistiikat softasta
-
-17.5.:
-- jonkin verran TODOja
-- conclusion
-- viitteet
-- Draw the component icons
-- splashscreen
+- Search field in motor selection dialog
+- Motor selection/editing from Edit configurations dialog
+- Change FreeformFinSet to throw checked exceptions
-18.5.:
-- About dialog + version number
# The OpenRocket build version
-build.version=0.9.1
+build.version=0.9.2pre
# The source of the package. When building a package for a specific
# distribution (Debian, Fedora etc.), this should be changed appropriately!
private LinkedList<String> undoDescription = new LinkedList<String>();
private String nextDescription = null;
+ private String storedDescription = null;
private File file = null;
this.configuration = configuration;
this.rocket = configuration.getRocket();
- undoHistory.add(rocket.copy());
- undoDescription.add(null);
- undoPosition = 0;
+ clearUndo();
undoAction = new UndoRedoAction(UndoRedoAction.UNDO);
redoAction = new UndoRedoAction(UndoRedoAction.REDO);
}
+ /**
+ * Start a time-limited undoable operation. After the operation {@link #stopUndo()}
+ * must be called, which will restore the previous undo description into effect.
+ * Only one level of start-stop undo descriptions is supported, i.e. start-stop
+ * undo cannot be nested, and no other undo operations may be called between
+ * the start and stop calls.
+ *
+ * @param description Description of the following undoable operations.
+ */
+ public void startUndo(String description) {
+ storedDescription = nextDescription;
+ addUndoPosition(description);
+ }
+
+ /**
+ * End the previous time-limited undoable operation. This must be called after
+ * {@link #startUndo(String)} has been called before any other undo operations are
+ * performed.
+ */
+ public void stopUndo() {
+ addUndoPosition(storedDescription);
+ storedDescription = null;
+ }
+
+
public Action getUndoAction() {
return undoAction;
}
}
+ /**
+ * Clear the undo history.
+ */
+ public void clearUndo() {
+ undoHistory.clear();
+ undoDescription.clear();
+
+ undoHistory.add(rocket.copy());
+ undoDescription.add(null);
+ undoPosition = 0;
+
+ if (undoAction != null)
+ undoAction.setAllValues();
+ if (redoAction != null)
+ redoAction.setAllValues();
+ }
+
+
@Override
public void componentChanged(ComponentChangeEvent e) {
import net.sf.openrocket.rocketcomponent.ExternalComponent;
import net.sf.openrocket.rocketcomponent.FinSet;
import net.sf.openrocket.rocketcomponent.FreeformFinSet;
+import net.sf.openrocket.rocketcomponent.IllegalFinPointException;
import net.sf.openrocket.rocketcomponent.InnerTube;
import net.sf.openrocket.rocketcomponent.InternalComponent;
import net.sf.openrocket.rocketcomponent.LaunchLug;
doc.getDefaultStorageOptions().setSimulationTimeSkip(timeSkip);
doc.getDefaultStorageOptions().setCompressionEnabled(false); // Set by caller if compressed
doc.getDefaultStorageOptions().setExplicitlySet(false);
+
+ doc.clearUndo();
return doc;
}
String content, WarningSet warnings) {
try {
finset.setPoints(coordinates.toArray(new Coordinate[0]));
- } catch (IllegalArgumentException e) {
+ } catch (IllegalFinPointException e) {
warnings.add(Warning.fromString("Freeform fin set point definitions illegal, ignoring."));
}
}
package net.sf.openrocket.file;
+import java.awt.Component;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import javax.swing.ProgressMonitorInputStream;
+
import net.sf.openrocket.aerodynamics.WarningSet;
import net.sf.openrocket.document.OpenRocketDocument;
public abstract class RocketLoader {
protected final WarningSet warnings = new WarningSet();
+
+ public final OpenRocketDocument load(File source, Component parent)
+ throws RocketLoadException {
+ warnings.clear();
+
+ try {
+ return load(new BufferedInputStream(new ProgressMonitorInputStream(
+ parent, "Loading " + source.getName(),
+ new FileInputStream(source))));
+ } catch (FileNotFoundException e) {
+ throw new RocketLoadException("File not found: " + source);
+ }
+ }
/**
* Loads a rocket from the specified File object.
+++ /dev/null
-package net.sf.openrocket.gui;
-
-import static net.sf.openrocket.unit.Unit.NOUNIT2;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Vector;
-
-import javax.swing.BorderFactory;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTabbedPane;
-import javax.swing.JTable;
-import javax.swing.JToggleButton;
-import javax.swing.ListSelectionModel;
-import javax.swing.SwingConstants;
-import javax.swing.SwingUtilities;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.table.TableCellRenderer;
-
-import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
-import net.sf.openrocket.aerodynamics.AerodynamicForces;
-import net.sf.openrocket.aerodynamics.FlightConditions;
-import net.sf.openrocket.aerodynamics.Warning;
-import net.sf.openrocket.aerodynamics.WarningSet;
-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;
-import net.sf.openrocket.rocketcomponent.Rocket;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.unit.Unit;
-import net.sf.openrocket.unit.UnitGroup;
-import net.sf.openrocket.util.GUIUtil;
-import net.sf.openrocket.util.MathUtil;
-import net.sf.openrocket.util.Prefs;
-
-public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
-
- private static ComponentAnalysisDialog singletonDialog = null;
-
-
- private final FlightConditions conditions;
- private final Configuration configuration;
- private final DoubleModel theta, aoa, mach, roll;
- private final JToggleButton worstToggle;
- private boolean fakeChange = false;
- private AerodynamicCalculator calculator;
-
- private final ColumnTableModel cpTableModel;
- private final ColumnTableModel dragTableModel;
- private final ColumnTableModel rollTableModel;
-
- private final JList warningList;
-
-
- private final List<AerodynamicForces> cpData = new ArrayList<AerodynamicForces>();
- private final List<AerodynamicForces> dragData = new ArrayList<AerodynamicForces>();
- private double totalCD = 0;
- private final List<AerodynamicForces> rollData = new ArrayList<AerodynamicForces>();
-
-
- public ComponentAnalysisDialog(final RocketPanel rocketPanel) {
- super(SwingUtilities.getWindowAncestor(rocketPanel), "Component analysis");
-
- JTable table;
-
- JPanel panel = new JPanel(new MigLayout("fill","[][35lp::][fill][fill]"));
- add(panel);
-
- this.configuration = rocketPanel.getConfiguration();
- this.calculator = rocketPanel.getCalculator().newInstance();
- this.calculator.setConfiguration(configuration);
-
-
- conditions = new FlightConditions(configuration);
-
- rocketPanel.setCPAOA(0);
- aoa = new DoubleModel(rocketPanel, "CPAOA", UnitGroup.UNITS_ANGLE, 0, Math.PI);
- rocketPanel.setCPMach(Prefs.getDefaultMach());
- mach = new DoubleModel(rocketPanel, "CPMach", UnitGroup.UNITS_COEFFICIENT, 0);
- rocketPanel.setCPTheta(rocketPanel.getFigure().getRotation());
- theta = new DoubleModel(rocketPanel, "CPTheta", UnitGroup.UNITS_ANGLE, 0, 2*Math.PI);
- rocketPanel.setCPRoll(0);
- roll = new DoubleModel(rocketPanel, "CPRoll", UnitGroup.UNITS_ROLL);
-
-
- panel.add(new JLabel("Wind direction:"),"width 100lp!");
- panel.add(new UnitSelector(theta,true),"width 50lp!");
- BasicSlider slider = new BasicSlider(theta.getSliderModel(0, 2*Math.PI));
- panel.add(slider,"growx, split 2");
- worstToggle = new JToggleButton("Worst");
- worstToggle.setSelected(true);
- worstToggle.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- stateChanged(null);
- }
- });
- slider.addChangeListener(new ChangeListener() {
- @Override
- public void stateChanged(ChangeEvent e) {
- if (!fakeChange)
- worstToggle.setSelected(false);
- }
- });
- panel.add(worstToggle,"");
-
-
- warningList = new JList();
- JScrollPane scrollPane = new JScrollPane(warningList);
- scrollPane.setBorder(BorderFactory.createTitledBorder("Warnings:"));
- panel.add(scrollPane,"gap paragraph, spany 4, width 300lp!, growy 1, height :100lp:, wrap");
-
-
- panel.add(new JLabel("Angle of attack:"),"width 100lp!");
- panel.add(new UnitSelector(aoa,true),"width 50lp!");
- panel.add(new BasicSlider(aoa.getSliderModel(0, Math.PI)),"growx, wrap");
-
- panel.add(new JLabel("Mach number:"),"width 100lp!");
- panel.add(new UnitSelector(mach,true),"width 50lp!");
- panel.add(new BasicSlider(mach.getSliderModel(0, 3)),"growx, wrap");
-
- panel.add(new JLabel("Roll rate:"), "width 100lp!");
- panel.add(new UnitSelector(roll,true),"width 50lp!");
- panel.add(new BasicSlider(roll.getSliderModel(-20*2*Math.PI, 20*2*Math.PI)),
- "growx, wrap paragraph");
-
-
- // Stage and motor selection:
-
- panel.add(new JLabel("Active stages:"),"spanx, split, gapafter rel");
- panel.add(new StageSelector(configuration),"gapafter paragraph");
-
- JLabel label = new JLabel("Motor configuration:");
- label.setHorizontalAlignment(JLabel.RIGHT);
- panel.add(label,"growx, right");
- panel.add(new JComboBox(new MotorConfigurationModel(configuration)),"wrap");
-
-
-
- // Tabbed pane
-
- JTabbedPane tabbedPane = new JTabbedPane();
- panel.add(tabbedPane, "spanx, growx, growy");
-
-
- // Create the CP data table
- cpTableModel = new ColumnTableModel(
-
- new Column("Component") {
- @Override public Object getValueAt(int row) {
- RocketComponent c = cpData.get(row).component;
- if (c instanceof Rocket) {
- return "Total";
- }
- return c.toString();
- }
- @Override public int getDefaultWidth() {
- return 200;
- }
- },
- new Column("CG / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit()) {
- private Unit unit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
- @Override public Object getValueAt(int row) {
- return unit.toString(cpData.get(row).cg.x);
- }
- },
- new Column("Mass / " + UnitGroup.UNITS_MASS.getDefaultUnit().getUnit()) {
- private Unit unit = UnitGroup.UNITS_MASS.getDefaultUnit();
- @Override
- public Object getValueAt(int row) {
- return unit.toString(cpData.get(row).cg.weight);
- }
- },
- new Column("CP / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit()) {
- private Unit unit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
- @Override public Object getValueAt(int row) {
- return unit.toString(cpData.get(row).cp.x);
- }
- },
- new Column("<html>C<sub>N<sub>\u03b1</sub></sub>") {
- @Override public Object getValueAt(int row) {
- return NOUNIT2.toString(cpData.get(row).cp.weight);
- }
- }
-
- ) {
- @Override public int getRowCount() {
- return cpData.size();
- }
- };
-
- table = new JTable(cpTableModel);
- table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- table.setSelectionBackground(Color.LIGHT_GRAY);
- table.setSelectionForeground(Color.BLACK);
- cpTableModel.setColumnWidths(table.getColumnModel());
-
- table.setDefaultRenderer(Object.class, new CustomCellRenderer());
-// table.setShowHorizontalLines(false);
-// table.setShowVerticalLines(true);
-
- JScrollPane scrollpane = new JScrollPane(table);
- scrollpane.setPreferredSize(new Dimension(600,200));
-
- tabbedPane.addTab("Stability", null, scrollpane, "Stability information");
-
-
-
- // Create the drag data table
- dragTableModel = new ColumnTableModel(
- new Column("Component") {
- @Override public Object getValueAt(int row) {
- RocketComponent c = dragData.get(row).component;
- if (c instanceof Rocket) {
- return "Total";
- }
- return c.toString();
- }
- @Override public int getDefaultWidth() {
- return 200;
- }
- },
- new Column("<html>Pressure C<sub>D</sub>") {
- @Override public Object getValueAt(int row) {
- return dragData.get(row).pressureCD;
- }
- },
- new Column("<html>Base C<sub>D</sub>") {
- @Override public Object getValueAt(int row) {
- return dragData.get(row).baseCD;
- }
- },
- new Column("<html>Friction C<sub>D</sub>") {
- @Override public Object getValueAt(int row) {
- return dragData.get(row).frictionCD;
- }
- },
- new Column("<html>Total C<sub>D</sub>") {
- @Override public Object getValueAt(int row) {
- return dragData.get(row).CD;
- }
- }
- ) {
- @Override public int getRowCount() {
- return dragData.size();
- }
- };
-
-
- table = new JTable(dragTableModel);
- table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- table.setSelectionBackground(Color.LIGHT_GRAY);
- table.setSelectionForeground(Color.BLACK);
- dragTableModel.setColumnWidths(table.getColumnModel());
-
- table.setDefaultRenderer(Object.class, new DragCellRenderer(new Color(0.5f,1.0f,0.5f)));
-// table.setShowHorizontalLines(false);
-// table.setShowVerticalLines(true);
-
- scrollpane = new JScrollPane(table);
- scrollpane.setPreferredSize(new Dimension(600,200));
-
- tabbedPane.addTab("Drag characteristics", null, scrollpane, "Drag characteristics");
-
-
-
-
- // Create the roll data table
- rollTableModel = new ColumnTableModel(
- new Column("Component") {
- @Override public Object getValueAt(int row) {
- RocketComponent c = rollData.get(row).component;
- if (c instanceof Rocket) {
- return "Total";
- }
- return c.toString();
- }
- },
- new Column("Roll forcing coefficient") {
- @Override public Object getValueAt(int row) {
- return rollData.get(row).CrollForce;
- }
- },
- new Column("Roll damping coefficient") {
- @Override public Object getValueAt(int row) {
- return rollData.get(row).CrollDamp;
- }
- },
- new Column("<html>Total C<sub>l</sub>") {
- @Override public Object getValueAt(int row) {
- return rollData.get(row).Croll;
- }
- }
- ) {
- @Override public int getRowCount() {
- return rollData.size();
- }
- };
-
-
- table = new JTable(rollTableModel);
- table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- table.setSelectionBackground(Color.LIGHT_GRAY);
- table.setSelectionForeground(Color.BLACK);
- rollTableModel.setColumnWidths(table.getColumnModel());
-
- scrollpane = new JScrollPane(table);
- scrollpane.setPreferredSize(new Dimension(600,200));
-
- tabbedPane.addTab("Roll dynamics", null, scrollpane, "Roll dynamics");
-
-
-
-
-
-
- // Add the data updater to listen to changes in aoa and theta
- mach.addChangeListener(this);
- theta.addChangeListener(this);
- aoa.addChangeListener(this);
- roll.addChangeListener(this);
- configuration.addChangeListener(this);
- this.stateChanged(null);
-
-
-
- // Remove listeners when closing window
- this.addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosed(WindowEvent e) {
- System.out.println("Closing method called: "+this);
- theta.removeChangeListener(ComponentAnalysisDialog.this);
- aoa.removeChangeListener(ComponentAnalysisDialog.this);
- mach.removeChangeListener(ComponentAnalysisDialog.this);
- roll.removeChangeListener(ComponentAnalysisDialog.this);
- configuration.removeChangeListener(ComponentAnalysisDialog.this);
- System.out.println("SETTING NAN VALUES");
- rocketPanel.setCPAOA(Double.NaN);
- rocketPanel.setCPTheta(Double.NaN);
- rocketPanel.setCPMach(Double.NaN);
- rocketPanel.setCPRoll(Double.NaN);
- singletonDialog = null;
- }
- });
-
-
- panel.add(new ResizeLabel("Reference length: ", -1),
- "span, split, gapleft para, gapright rel");
- DoubleModel dm = new DoubleModel(conditions, "RefLength", UnitGroup.UNITS_LENGTH);
- UnitSelector sel = new UnitSelector(dm, true);
- sel.resizeFont(-1);
- panel.add(sel, "gapright para");
-
- panel.add(new ResizeLabel("Reference area: ", -1), "gapright rel");
- dm = new DoubleModel(conditions, "RefArea", UnitGroup.UNITS_AREA);
- sel = new UnitSelector(dm, true);
- sel.resizeFont(-1);
- panel.add(sel, "wrap");
-
-
-
- // Buttons
- JButton button;
-
- // TODO: LOW: printing
-// button = new JButton("Print");
-// button.addActionListener(new ActionListener() {
-// public void actionPerformed(ActionEvent e) {
-// try {
-// table.print();
-// } catch (PrinterException e1) {
-// JOptionPane.showMessageDialog(ComponentAnalysisDialog.this,
-// "An error occurred while printing.", "Print error",
-// JOptionPane.ERROR_MESSAGE);
-// }
-// }
-// });
-// panel.add(button,"tag ok");
-
- button = new JButton("Close");
- button.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- ComponentAnalysisDialog.this.dispose();
- }
- });
- panel.add(button,"span, split, tag cancel");
-
-
- setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
- GUIUtil.installEscapeCloseOperation(this);
- pack();
- }
-
-
-
- /**
- * Updates the data in the table and fires a table data change event.
- */
- @Override
- public void stateChanged(ChangeEvent e) {
- AerodynamicForces forces;
- WarningSet set = new WarningSet();
- conditions.setAOA(aoa.getValue());
- conditions.setTheta(theta.getValue());
- conditions.setMach(mach.getValue());
- conditions.setRollRate(roll.getValue());
- conditions.setReference(configuration);
-
- if (worstToggle.isSelected()) {
- calculator.getWorstCP(conditions, null);
- if (!MathUtil.equals(conditions.getTheta(), theta.getValue())) {
- fakeChange = true;
- theta.setValue(conditions.getTheta()); // Fires a stateChanged event
- fakeChange = false;
- return;
- }
- }
-
- Map<RocketComponent, AerodynamicForces> data = calculator.getForceAnalysis(conditions, set);
-
- cpData.clear();
- dragData.clear();
- rollData.clear();
- for (RocketComponent c: configuration) {
- forces = data.get(c);
- if (forces == null)
- continue;
- if (forces.cp != null) {
- cpData.add(forces);
- }
- if (!Double.isNaN(forces.CD)) {
- dragData.add(forces);
- }
- if (c instanceof FinSet) {
- rollData.add(forces);
- }
- }
- forces = data.get(configuration.getRocket());
- if (forces != null) {
- cpData.add(forces);
- dragData.add(forces);
- rollData.add(forces);
- totalCD = forces.CD;
- } else {
- totalCD = 0;
- }
-
- // Set warnings
- if (set.isEmpty()) {
- warningList.setListData(new String[] {
- "<html><i><font color=\"gray\">No warnings.</font></i>"
- });
- } else {
- warningList.setListData(new Vector<Warning>(set));
- }
-
- cpTableModel.fireTableDataChanged();
- dragTableModel.fireTableDataChanged();
- rollTableModel.fireTableDataChanged();
- }
-
-
- private class CustomCellRenderer extends JLabel implements TableCellRenderer {
- private final Font normalFont;
- private final Font boldFont;
-
- public CustomCellRenderer() {
- super();
- normalFont = getFont();
- boldFont = normalFont.deriveFont(Font.BOLD);
- }
- @Override
- public Component getTableCellRendererComponent(JTable table, Object value,
- boolean isSelected, boolean hasFocus, int row, int column) {
-
- this.setText(value.toString());
-
- if ((row < 0) || (row >= cpData.size()))
- return this;
-
- if (cpData.get(row).component instanceof Rocket) {
- this.setFont(boldFont);
- } else {
- this.setFont(normalFont);
- }
- return this;
- }
- }
-
-
-
- private class DragCellRenderer extends JLabel implements TableCellRenderer {
- private final Font normalFont;
- private final Font boldFont;
-
- private final float[] start = { 0.3333f, 0.2f, 1.0f };
- private final float[] end = { 0.0f, 0.8f, 1.0f };
-
-
- public DragCellRenderer(Color baseColor) {
- super();
- normalFont = getFont();
- boldFont = normalFont.deriveFont(Font.BOLD);
- }
- @Override
- public Component getTableCellRendererComponent(JTable table, Object value,
- boolean isSelected, boolean hasFocus, int row, int column) {
-
- if (value instanceof Double) {
-
- // A drag coefficient
- double cd = (Double)value;
- this.setText(String.format("%.2f (%.0f%%)", cd, 100*cd/totalCD));
-
- float r = (float)(cd/1.5);
-
- float hue = MathUtil.clamp(0.3333f * (1-2.0f*r), 0, 0.3333f);
- float sat = MathUtil.clamp(0.8f*r + 0.1f*(1-r), 0, 1);
- float val = 1.0f;
-
- this.setBackground(Color.getHSBColor(hue, sat, val));
- this.setOpaque(true);
- this.setHorizontalAlignment(SwingConstants.CENTER);
-
- } else {
-
- // Other
- this.setText(value.toString());
- this.setOpaque(false);
- this.setHorizontalAlignment(SwingConstants.LEFT);
-
- }
-
- if ((row < 0) || (row >= dragData.size()))
- return this;
-
- if ((dragData.get(row).component instanceof Rocket) || (column == 4)){
- this.setFont(boldFont);
- } else {
- this.setFont(normalFont);
- }
- return this;
- }
- }
-
-
- ///////// Singleton implementation
-
- public static void showDialog(RocketPanel rocketpanel) {
- if (singletonDialog != null)
- singletonDialog.dispose();
- singletonDialog = new ComponentAnalysisDialog(rocketpanel);
- singletonDialog.setVisible(true);
- }
-
- public static void hideDialog() {
- if (singletonDialog != null)
- singletonDialog.dispose();
- }
-
-}
+++ /dev/null
-package net.sf.openrocket.gui;
-
-import java.awt.Component;
-
-import javax.swing.JOptionPane;
-
-public class DetailDialog {
-
- public static void showDetailedMessageDialog(Component parentComponent, Object message,
- String details, String title, int messageType) {
-
- // TODO: HIGH: Detailed dialog
- JOptionPane.showMessageDialog(parentComponent, message, title, messageType, null);
-
- }
-
-
-}
+++ /dev/null
-package net.sf.openrocket.gui;
-
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.AbstractListModel;
-import javax.swing.ComboBoxModel;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-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;
-import net.sf.openrocket.util.Prefs;
-
-public class PreferencesDialog extends JDialog {
-
- private final List<DefaultUnitSelector> unitSelectors = new ArrayList<DefaultUnitSelector>();
-
- private PreferencesDialog() {
- super((JFrame)null, "Preferences", true);
-
- JPanel panel = new JPanel(new MigLayout("fill, gap unrel","[grow]","[grow][]"));
-
- JTabbedPane tabbedPane = new JTabbedPane();
- panel.add(tabbedPane,"grow, wrap");
-
-
- tabbedPane.addTab("Units", null, unitsPane(), "Default units");
- tabbedPane.addTab("Confirmation", null, confirmationPane(), "Confirmation dialog settings");
-
-
-
- JButton close = new JButton("Close");
- close.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent arg0) {
- PreferencesDialog.this.setVisible(false);
- PreferencesDialog.this.dispose();
- }
- });
- panel.add(close,"span, right, tag close");
-
- this.setContentPane(panel);
- pack();
- setAlwaysOnTop(true);
- this.setLocationRelativeTo(null);
-
- this.addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosed(WindowEvent e) {
- Prefs.storeDefaultUnits();
- }
- });
-
- GUIUtil.setDefaultButton(close);
- GUIUtil.installEscapeCloseOperation(this);
- }
-
-
- private JPanel confirmationPane() {
- JPanel panel = new JPanel(new MigLayout("fill"));
-
- panel.add(new JLabel("Position to insert new body components:"));
- panel.add(new JComboBox(new PrefChoiseSelector(Prefs.BODY_COMPONENT_INSERT_POSITION_KEY,
- "Always ask", "Insert in middle", "Add to end")), "wrap para, sg combos");
-
- panel.add(new JLabel("Confirm deletion of simulations:"));
- panel.add(new JComboBox(new PrefBooleanSelector(Prefs.CONFIRM_DELETE_SIMULATION,
- "Delete", "Confirm", true)), "wrap para, sg combos");
-
- return panel;
- }
-
- private JPanel unitsPane() {
- JPanel panel = new JPanel(new MigLayout("", "[][]40lp[][]"));
- JComboBox combo;
-
- panel.add(new JLabel("Select your preferred units:"), "span, wrap paragraph");
-
-/*
- public static final UnitGroup UNITS_LENGTH;
- public static final UnitGroup UNITS_MOTOR_DIMENSIONS;
- public static final UnitGroup UNITS_DISTANCE;
-
- public static final UnitGroup UNITS_VELOCITY;
- public static final UnitGroup UNITS_ACCELERATION;
- public static final UnitGroup UNITS_MASS;
- public static final UnitGroup UNITS_FORCE;
- public static final UnitGroup UNITS_IMPULSE;
-
- public static final UnitGroup UNITS_STABILITY;
- public static final UnitGroup UNITS_FLIGHT_TIME;
- public static final UnitGroup UNITS_ROLL;
-
- public static final UnitGroup UNITS_AREA;
- public static final UnitGroup UNITS_DENSITY_LINE;
- public static final UnitGroup UNITS_DENSITY_SURFACE;
- public static final UnitGroup UNITS_DENSITY_BULK;
- public static final UnitGroup UNITS_ROUGHNESS;
-
- public static final UnitGroup UNITS_TEMPERATURE;
- public static final UnitGroup UNITS_PRESSURE;
- public static final UnitGroup UNITS_ANGLE;
-*/
-
- panel.add(new JLabel("Rocket dimensions:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_LENGTH));
- panel.add(combo, "sizegroup boxes");
-
- panel.add(new JLabel("Line density:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_LINE));
- panel.add(combo, "sizegroup boxes, wrap");
-
-
-
- panel.add(new JLabel("Motor dimensions:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_MOTOR_DIMENSIONS));
- panel.add(combo, "sizegroup boxes");
-
- panel.add(new JLabel("Surface density:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_SURFACE));
- panel.add(combo, "sizegroup boxes, wrap");
-
-
-
- panel.add(new JLabel("Distance:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DISTANCE));
- panel.add(combo, "sizegroup boxes");
-
- panel.add(new JLabel("Bulk density::"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_BULK));
- panel.add(combo, "sizegroup boxes, wrap");
-
-
-
- panel.add(new JLabel("Velocity:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_VELOCITY));
- panel.add(combo, "sizegroup boxes");
-
- panel.add(new JLabel("Surface roughness:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ROUGHNESS));
- panel.add(combo, "sizegroup boxes, wrap");
-
-
-
- panel.add(new JLabel("Acceleration:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ACCELERATION));
- panel.add(combo, "sizegroup boxes");
-
- panel.add(new JLabel("Area:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_AREA));
- panel.add(combo, "sizegroup boxes, wrap");
-
-
-
- panel.add(new JLabel("Mass:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_MASS));
- panel.add(combo, "sizegroup boxes");
-
- panel.add(new JLabel("Angle:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ANGLE));
- panel.add(combo, "sizegroup boxes, wrap");
-
-
-
- panel.add(new JLabel("Force:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_FORCE));
- panel.add(combo, "sizegroup boxes");
-
- panel.add(new JLabel("Roll rate:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ROLL));
- panel.add(combo, "sizegroup boxes, wrap");
-
-
-
- panel.add(new JLabel("Total impulse:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_IMPULSE));
- panel.add(combo, "sizegroup boxes");
-
- panel.add(new JLabel("Temperature:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_TEMPERATURE));
- panel.add(combo, "sizegroup boxes, wrap");
-
-
-
- panel.add(new JLabel("Stability:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_STABILITY));
- panel.add(combo, "sizegroup boxes");
-
- panel.add(new JLabel("Pressure:"));
- combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_PRESSURE));
- panel.add(combo, "sizegroup boxes, wrap para");
-
-
-
- JButton button = new JButton("Default metric");
- button.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- UnitGroup.setDefaultMetricUnits();
- for (DefaultUnitSelector s: unitSelectors)
- s.fireChange();
- }
- });
- panel.add(button, "spanx, split 2, grow");
-
- button = new JButton("Default imperial");
- button.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- UnitGroup.setDefaultImperialUnits();
- for (DefaultUnitSelector s: unitSelectors)
- s.fireChange();
- }
- });
- panel.add(button, "grow, wrap para");
-
-
- panel.add(new ResizeLabel("The effects will take place the next time you open a window.",-2),
- "spanx, wrap");
-
-
- return panel;
- }
-
-
-
-
- private class DefaultUnitSelector extends AbstractListModel implements ComboBoxModel {
-
- private final UnitGroup group;
- public DefaultUnitSelector(UnitGroup group) {
- this.group = group;
- unitSelectors.add(this);
- }
-
- @Override
- public Object getSelectedItem() {
- return group.getDefaultUnit();
- }
- @Override
- public void setSelectedItem(Object item) {
- if (!(item instanceof Unit)) {
- throw new IllegalArgumentException("Illegal argument "+item);
- }
- group.setDefaultUnit(group.getUnitIndex((Unit)item));
- }
- @Override
- public Object getElementAt(int index) {
- return group.getUnit(index);
- }
- @Override
- public int getSize() {
- return group.getUnitCount();
- }
-
-
- public void fireChange() {
- this.fireContentsChanged(this, 0, this.getSize());
- }
- }
-
-
-
- private class PrefChoiseSelector extends AbstractListModel implements ComboBoxModel {
- private final String preference;
- private final String[] descriptions;
-
- public PrefChoiseSelector(String preference, String ... descriptions) {
- this.preference = preference;
- this.descriptions = descriptions;
- }
-
- @Override
- public Object getSelectedItem() {
- return descriptions[Prefs.getChoise(preference, descriptions.length, 0)];
- }
-
- @Override
- public void setSelectedItem(Object item) {
- if (!(item instanceof String)) {
- throw new IllegalArgumentException("Illegal argument "+item);
- }
- int index;
- for (index = 0; index < descriptions.length; index++) {
- if (((String)item).equalsIgnoreCase(descriptions[index]))
- break;
- }
- if (index >= descriptions.length) {
- throw new IllegalArgumentException("Illegal argument "+item);
- }
-
- Prefs.putChoise(preference, index);
- }
-
- @Override
- public Object getElementAt(int index) {
- return descriptions[index];
- }
- @Override
- public int getSize() {
- return descriptions.length;
- }
- }
-
-
- private class PrefBooleanSelector extends AbstractListModel implements ComboBoxModel {
- private final String preference;
- private final String trueDesc, falseDesc;
- private final boolean def;
-
- public PrefBooleanSelector(String preference, String falseDescription,
- String trueDescription, boolean defaultState) {
- this.preference = preference;
- this.trueDesc = trueDescription;
- this.falseDesc = falseDescription;
- this.def = defaultState;
- }
-
- @Override
- public Object getSelectedItem() {
- if (Prefs.NODE.getBoolean(preference, def)) {
- return trueDesc;
- } else {
- return falseDesc;
- }
- }
-
- @Override
- public void setSelectedItem(Object item) {
- if (!(item instanceof String)) {
- throw new IllegalArgumentException("Illegal argument "+item);
- }
-
- if (trueDesc.equals(item)) {
- Prefs.NODE.putBoolean(preference, true);
- } else if (falseDesc.equals(item)) {
- Prefs.NODE.putBoolean(preference, false);
- } else {
- throw new IllegalArgumentException("Illegal argument "+item);
- }
- }
-
- @Override
- public Object getElementAt(int index) {
- switch (index) {
- case 0:
- return def ? trueDesc : falseDesc;
-
- case 1:
- return def ? falseDesc: trueDesc;
-
- default:
- throw new IndexOutOfBoundsException("Boolean asked for index="+index);
- }
- }
- @Override
- public int getSize() {
- return 2;
- }
- }
-
-
-
- //////// Singleton implementation ////////
-
- private static PreferencesDialog dialog = null;
-
- public static void showPreferences() {
- if (dialog != null) {
- dialog.dispose();
- }
- dialog = new PreferencesDialog();
- dialog.setVisible(true);
- }
-
-
-}
package net.sf.openrocket.gui.adaptors;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
import javax.swing.ComboBoxModel;
-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.JTable;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.TextFieldListener;
-import net.sf.openrocket.gui.components.ResizeLabel;
+import net.sf.openrocket.gui.dialogs.EditMotorConfigurationDialog;
+import net.sf.openrocket.gui.main.BasicFrame;
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
import net.sf.openrocket.rocketcomponent.Configuration;
-import net.sf.openrocket.rocketcomponent.Motor;
-import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.Rocket;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.util.GUIUtil;
public class MotorConfigurationModel implements ComboBoxModel, ChangeListener {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
- EditConfigurationDialog dialog = new EditConfigurationDialog();
- dialog.setVisible(true);
-
- if (dialog.isRowSelected()) {
- rocket.getDefaultConfiguration().setMotorConfigurationID(
- dialog.getSelectedID());
- }
+ new EditMotorConfigurationDialog(rocket, BasicFrame.findFrame(rocket))
+ .setVisible(true);
}
});
}
}
-
- private class EditConfigurationDialog extends JDialog {
- private final ColumnTableModel tableModel;
- private String[] ids;
- int selection = -1;
-
- private final JButton addButton;
- private final JButton removeButton;
- private final JTextField nameField;
-
- private final JTable table;
-
-
- public boolean isRowSelected() {
- return selection >= 0;
- }
-
- public String getSelectedID() {
- if (selection >= 0)
- return ids[selection];
- return null;
- }
-
-
- public EditConfigurationDialog() {
- super((JFrame)null, "Edit configurations", true);
-
- ids = rocket.getMotorConfigurationIDs();
-
- // Create columns
- ArrayList<Column> columnList = new ArrayList<Column>();
- columnList.add(new Column("Name") {
- @Override
- public Object getValueAt(int row) {
- return rocket.getMotorConfigurationNameOrDescription(ids[row]);
- }
- });
-
- // Create columns from the motor mounts
- Iterator<RocketComponent> iterator = rocket.deepIterator();
- while (iterator.hasNext()) {
- RocketComponent c = iterator.next();
- if (!(c instanceof MotorMount))
- continue;
-
- final MotorMount mount = (MotorMount)c;
- if (!mount.isMotorMount())
- continue;
-
- Column col = new Column(c.getName()) {
- @Override
- public Object getValueAt(int row) {
- Motor motor = mount.getMotor(ids[row]);
- if (motor == null)
- return "";
- return motor.getDesignation(mount.getMotorDelay(ids[row]));
- }
- };
- columnList.add(col);
- }
- tableModel = new ColumnTableModel(columnList.toArray(new Column[0])) {
- @Override
- public int getRowCount() {
- return ids.length;
- }
- };
-
-
-
- // Create the panel
- JPanel panel = new JPanel(new MigLayout("fill","[shrink][grow]"));
-
-
- panel.add(new JLabel("Configuration name:"), "gapright para");
- nameField = new JTextField();
- new TextFieldListener() {
- @Override
- public void setText(String text) {
- if (selection < 0 || ids[selection] == null)
- return;
- rocket.setMotorConfigurationName(ids[selection], text);
- fireChange();
- }
- }.listenTo(nameField);
- panel.add(nameField, "growx, wrap");
-
- panel.add(new ResizeLabel("Leave empty for default description", -2),
- "skip, growx, wrap para");
-
-
- table = new JTable(tableModel);
- table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
- @Override
- public void valueChanged(ListSelectionEvent e) {
- updateSelection();
- }
- });
-
- // Mouse listener to act on double-clicks
- table.addMouseListener(new MouseAdapter() {
- @Override
- public void mouseClicked(MouseEvent e) {
- if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
- EditConfigurationDialog.this.dispose();
- }
- }
- });
-
-
-
- JScrollPane scrollpane = new JScrollPane(table);
- panel.add(scrollpane, "spanx, height 150lp, width 400lp, grow, wrap");
-
-
- addButton = new JButton("New");
- addButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- String id = rocket.newMotorConfigurationID();
- ids = rocket.getMotorConfigurationIDs();
- tableModel.fireTableDataChanged();
- int sel;
- for (sel=0; sel < ids.length; sel++) {
- if (id.equals(ids[sel]))
- break;
- }
- table.getSelectionModel().addSelectionInterval(sel, sel);
- }
- });
- panel.add(addButton, "growx, spanx, split 2");
-
- removeButton = new JButton("Remove");
- removeButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- int sel = table.getSelectedRow();
- if (sel < 0 || sel >= ids.length || ids[sel] == null)
- return;
- rocket.removeMotorConfigurationID(ids[sel]);
- ids = rocket.getMotorConfigurationIDs();
- tableModel.fireTableDataChanged();
- if (sel >= ids.length)
- sel--;
- table.getSelectionModel().addSelectionInterval(sel, sel);
- }
- });
- panel.add(removeButton, "growx, wrap para");
-
-
- JButton close = new JButton("Close");
- close.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- EditConfigurationDialog.this.dispose();
- }
- });
- panel.add(close, "spanx, alignx 100%");
-
- this.getRootPane().setDefaultButton(close);
-
-
- this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
- GUIUtil.installEscapeCloseOperation(this);
- this.setLocationByPlatform(true);
-
- updateSelection();
-
- this.add(panel);
- this.validate();
- this.pack();
- }
-
- private void fireChange() {
- int sel = table.getSelectedRow();
- tableModel.fireTableDataChanged();
- table.getSelectionModel().addSelectionInterval(sel, sel);
- }
-
- private void updateSelection() {
- selection = table.getSelectedRow();
- if (selection < 0 || ids[selection] == null) {
- removeButton.setEnabled(false);
- nameField.setEnabled(false);
- nameField.setText("");
- } else {
- removeButton.setEnabled(true);
- nameField.setEnabled(true);
- nameField.setText(rocket.getMotorConfigurationName(ids[selection]));
- }
- }
- }
-
}
import net.sf.openrocket.material.Material;
import net.sf.openrocket.rocketcomponent.FinSet;
import net.sf.openrocket.rocketcomponent.FreeformFinSet;
+import net.sf.openrocket.rocketcomponent.IllegalFinPointException;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.Coordinate;
finset.addPoint(index);
try {
finset.setPoint(index, point.x, point.y);
- } catch (IllegalArgumentException ignore) { }
+ } catch (IllegalFinPointException ignore) { }
dragIndex = index;
return;
try {
finset.setPoint(dragIndex, point.x, point.y);
- } catch (IllegalArgumentException ignore) {
+ } catch (IllegalFinPointException ignore) {
System.out.println("IAE:"+ignore);
}
}
try {
finset.removePoint(index);
- } catch (IllegalArgumentException ignore) {
+ } catch (IllegalFinPointException ignore) {
}
}
finset.setPoint(rowIndex, c.x, c.y);
} catch (NumberFormatException ignore) {
+ } catch (IllegalFinPointException ignore) {
}
}
tab = positionTab();
tabbedPane.insertTab("Radial position", null, tab, "Radial position", 1);
- tab = clusterTab();
- tabbedPane.insertTab("Cluster", null, tab, "Cluster configuration", 2);
-
tab = new MotorConfig((MotorMount)c);
- tabbedPane.insertTab("Motor", null, tab, "Motor mount configuration", 3);
+ tabbedPane.insertTab("Motor", null, tab, "Motor mount configuration", 2);
+ tab = clusterTab();
+ tabbedPane.insertTab("Cluster", null, tab, "Cluster configuration", 3);
+
tabbedPane.setSelectedIndex(0);
}
--- /dev/null
+package net.sf.openrocket.gui.dialogs;
+
+import static net.sf.openrocket.unit.Unit.NOUNIT2;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTable;
+import javax.swing.JToggleButton;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.table.TableCellRenderer;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
+import net.sf.openrocket.aerodynamics.AerodynamicForces;
+import net.sf.openrocket.aerodynamics.FlightConditions;
+import net.sf.openrocket.aerodynamics.Warning;
+import net.sf.openrocket.aerodynamics.WarningSet;
+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;
+import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.unit.Unit;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.GUIUtil;
+import net.sf.openrocket.util.MathUtil;
+import net.sf.openrocket.util.Prefs;
+
+public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
+
+ private static ComponentAnalysisDialog singletonDialog = null;
+
+
+ private final FlightConditions conditions;
+ private final Configuration configuration;
+ private final DoubleModel theta, aoa, mach, roll;
+ private final JToggleButton worstToggle;
+ private boolean fakeChange = false;
+ private AerodynamicCalculator calculator;
+
+ private final ColumnTableModel cpTableModel;
+ private final ColumnTableModel dragTableModel;
+ private final ColumnTableModel rollTableModel;
+
+ private final JList warningList;
+
+
+ private final List<AerodynamicForces> cpData = new ArrayList<AerodynamicForces>();
+ private final List<AerodynamicForces> dragData = new ArrayList<AerodynamicForces>();
+ private double totalCD = 0;
+ private final List<AerodynamicForces> rollData = new ArrayList<AerodynamicForces>();
+
+
+ public ComponentAnalysisDialog(final RocketPanel rocketPanel) {
+ super(SwingUtilities.getWindowAncestor(rocketPanel), "Component analysis");
+
+ JTable table;
+
+ JPanel panel = new JPanel(new MigLayout("fill","[][35lp::][fill][fill]"));
+ add(panel);
+
+ this.configuration = rocketPanel.getConfiguration();
+ this.calculator = rocketPanel.getCalculator().newInstance();
+ this.calculator.setConfiguration(configuration);
+
+
+ conditions = new FlightConditions(configuration);
+
+ rocketPanel.setCPAOA(0);
+ aoa = new DoubleModel(rocketPanel, "CPAOA", UnitGroup.UNITS_ANGLE, 0, Math.PI);
+ rocketPanel.setCPMach(Prefs.getDefaultMach());
+ mach = new DoubleModel(rocketPanel, "CPMach", UnitGroup.UNITS_COEFFICIENT, 0);
+ rocketPanel.setCPTheta(rocketPanel.getFigure().getRotation());
+ theta = new DoubleModel(rocketPanel, "CPTheta", UnitGroup.UNITS_ANGLE, 0, 2*Math.PI);
+ rocketPanel.setCPRoll(0);
+ roll = new DoubleModel(rocketPanel, "CPRoll", UnitGroup.UNITS_ROLL);
+
+
+ panel.add(new JLabel("Wind direction:"),"width 100lp!");
+ panel.add(new UnitSelector(theta,true),"width 50lp!");
+ BasicSlider slider = new BasicSlider(theta.getSliderModel(0, 2*Math.PI));
+ panel.add(slider,"growx, split 2");
+ worstToggle = new JToggleButton("Worst");
+ worstToggle.setSelected(true);
+ worstToggle.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ stateChanged(null);
+ }
+ });
+ slider.addChangeListener(new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ if (!fakeChange)
+ worstToggle.setSelected(false);
+ }
+ });
+ panel.add(worstToggle,"");
+
+
+ warningList = new JList();
+ JScrollPane scrollPane = new JScrollPane(warningList);
+ scrollPane.setBorder(BorderFactory.createTitledBorder("Warnings:"));
+ panel.add(scrollPane,"gap paragraph, spany 4, width 300lp!, growy 1, height :100lp:, wrap");
+
+
+ panel.add(new JLabel("Angle of attack:"),"width 100lp!");
+ panel.add(new UnitSelector(aoa,true),"width 50lp!");
+ panel.add(new BasicSlider(aoa.getSliderModel(0, Math.PI)),"growx, wrap");
+
+ panel.add(new JLabel("Mach number:"),"width 100lp!");
+ panel.add(new UnitSelector(mach,true),"width 50lp!");
+ panel.add(new BasicSlider(mach.getSliderModel(0, 3)),"growx, wrap");
+
+ panel.add(new JLabel("Roll rate:"), "width 100lp!");
+ panel.add(new UnitSelector(roll,true),"width 50lp!");
+ panel.add(new BasicSlider(roll.getSliderModel(-20*2*Math.PI, 20*2*Math.PI)),
+ "growx, wrap paragraph");
+
+
+ // Stage and motor selection:
+
+ panel.add(new JLabel("Active stages:"),"spanx, split, gapafter rel");
+ panel.add(new StageSelector(configuration),"gapafter paragraph");
+
+ JLabel label = new JLabel("Motor configuration:");
+ label.setHorizontalAlignment(JLabel.RIGHT);
+ panel.add(label,"growx, right");
+ panel.add(new JComboBox(new MotorConfigurationModel(configuration)),"wrap");
+
+
+
+ // Tabbed pane
+
+ JTabbedPane tabbedPane = new JTabbedPane();
+ panel.add(tabbedPane, "spanx, growx, growy");
+
+
+ // Create the CP data table
+ cpTableModel = new ColumnTableModel(
+
+ new Column("Component") {
+ @Override public Object getValueAt(int row) {
+ RocketComponent c = cpData.get(row).component;
+ if (c instanceof Rocket) {
+ return "Total";
+ }
+ return c.toString();
+ }
+ @Override public int getDefaultWidth() {
+ return 200;
+ }
+ },
+ new Column("CG / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit()) {
+ private Unit unit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
+ @Override public Object getValueAt(int row) {
+ return unit.toString(cpData.get(row).cg.x);
+ }
+ },
+ new Column("Mass / " + UnitGroup.UNITS_MASS.getDefaultUnit().getUnit()) {
+ private Unit unit = UnitGroup.UNITS_MASS.getDefaultUnit();
+ @Override
+ public Object getValueAt(int row) {
+ return unit.toString(cpData.get(row).cg.weight);
+ }
+ },
+ new Column("CP / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit()) {
+ private Unit unit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
+ @Override public Object getValueAt(int row) {
+ return unit.toString(cpData.get(row).cp.x);
+ }
+ },
+ new Column("<html>C<sub>N<sub>\u03b1</sub></sub>") {
+ @Override public Object getValueAt(int row) {
+ return NOUNIT2.toString(cpData.get(row).cp.weight);
+ }
+ }
+
+ ) {
+ @Override public int getRowCount() {
+ return cpData.size();
+ }
+ };
+
+ table = new JTable(cpTableModel);
+ table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ table.setSelectionBackground(Color.LIGHT_GRAY);
+ table.setSelectionForeground(Color.BLACK);
+ cpTableModel.setColumnWidths(table.getColumnModel());
+
+ table.setDefaultRenderer(Object.class, new CustomCellRenderer());
+// table.setShowHorizontalLines(false);
+// table.setShowVerticalLines(true);
+
+ JScrollPane scrollpane = new JScrollPane(table);
+ scrollpane.setPreferredSize(new Dimension(600,200));
+
+ tabbedPane.addTab("Stability", null, scrollpane, "Stability information");
+
+
+
+ // Create the drag data table
+ dragTableModel = new ColumnTableModel(
+ new Column("Component") {
+ @Override public Object getValueAt(int row) {
+ RocketComponent c = dragData.get(row).component;
+ if (c instanceof Rocket) {
+ return "Total";
+ }
+ return c.toString();
+ }
+ @Override public int getDefaultWidth() {
+ return 200;
+ }
+ },
+ new Column("<html>Pressure C<sub>D</sub>") {
+ @Override public Object getValueAt(int row) {
+ return dragData.get(row).pressureCD;
+ }
+ },
+ new Column("<html>Base C<sub>D</sub>") {
+ @Override public Object getValueAt(int row) {
+ return dragData.get(row).baseCD;
+ }
+ },
+ new Column("<html>Friction C<sub>D</sub>") {
+ @Override public Object getValueAt(int row) {
+ return dragData.get(row).frictionCD;
+ }
+ },
+ new Column("<html>Total C<sub>D</sub>") {
+ @Override public Object getValueAt(int row) {
+ return dragData.get(row).CD;
+ }
+ }
+ ) {
+ @Override public int getRowCount() {
+ return dragData.size();
+ }
+ };
+
+
+ table = new JTable(dragTableModel);
+ table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ table.setSelectionBackground(Color.LIGHT_GRAY);
+ table.setSelectionForeground(Color.BLACK);
+ dragTableModel.setColumnWidths(table.getColumnModel());
+
+ table.setDefaultRenderer(Object.class, new DragCellRenderer(new Color(0.5f,1.0f,0.5f)));
+// table.setShowHorizontalLines(false);
+// table.setShowVerticalLines(true);
+
+ scrollpane = new JScrollPane(table);
+ scrollpane.setPreferredSize(new Dimension(600,200));
+
+ tabbedPane.addTab("Drag characteristics", null, scrollpane, "Drag characteristics");
+
+
+
+
+ // Create the roll data table
+ rollTableModel = new ColumnTableModel(
+ new Column("Component") {
+ @Override public Object getValueAt(int row) {
+ RocketComponent c = rollData.get(row).component;
+ if (c instanceof Rocket) {
+ return "Total";
+ }
+ return c.toString();
+ }
+ },
+ new Column("Roll forcing coefficient") {
+ @Override public Object getValueAt(int row) {
+ return rollData.get(row).CrollForce;
+ }
+ },
+ new Column("Roll damping coefficient") {
+ @Override public Object getValueAt(int row) {
+ return rollData.get(row).CrollDamp;
+ }
+ },
+ new Column("<html>Total C<sub>l</sub>") {
+ @Override public Object getValueAt(int row) {
+ return rollData.get(row).Croll;
+ }
+ }
+ ) {
+ @Override public int getRowCount() {
+ return rollData.size();
+ }
+ };
+
+
+ table = new JTable(rollTableModel);
+ table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ table.setSelectionBackground(Color.LIGHT_GRAY);
+ table.setSelectionForeground(Color.BLACK);
+ rollTableModel.setColumnWidths(table.getColumnModel());
+
+ scrollpane = new JScrollPane(table);
+ scrollpane.setPreferredSize(new Dimension(600,200));
+
+ tabbedPane.addTab("Roll dynamics", null, scrollpane, "Roll dynamics");
+
+
+
+
+
+
+ // Add the data updater to listen to changes in aoa and theta
+ mach.addChangeListener(this);
+ theta.addChangeListener(this);
+ aoa.addChangeListener(this);
+ roll.addChangeListener(this);
+ configuration.addChangeListener(this);
+ this.stateChanged(null);
+
+
+
+ // Remove listeners when closing window
+ this.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosed(WindowEvent e) {
+ System.out.println("Closing method called: "+this);
+ theta.removeChangeListener(ComponentAnalysisDialog.this);
+ aoa.removeChangeListener(ComponentAnalysisDialog.this);
+ mach.removeChangeListener(ComponentAnalysisDialog.this);
+ roll.removeChangeListener(ComponentAnalysisDialog.this);
+ configuration.removeChangeListener(ComponentAnalysisDialog.this);
+ System.out.println("SETTING NAN VALUES");
+ rocketPanel.setCPAOA(Double.NaN);
+ rocketPanel.setCPTheta(Double.NaN);
+ rocketPanel.setCPMach(Double.NaN);
+ rocketPanel.setCPRoll(Double.NaN);
+ singletonDialog = null;
+ }
+ });
+
+
+ panel.add(new ResizeLabel("Reference length: ", -1),
+ "span, split, gapleft para, gapright rel");
+ DoubleModel dm = new DoubleModel(conditions, "RefLength", UnitGroup.UNITS_LENGTH);
+ UnitSelector sel = new UnitSelector(dm, true);
+ sel.resizeFont(-1);
+ panel.add(sel, "gapright para");
+
+ panel.add(new ResizeLabel("Reference area: ", -1), "gapright rel");
+ dm = new DoubleModel(conditions, "RefArea", UnitGroup.UNITS_AREA);
+ sel = new UnitSelector(dm, true);
+ sel.resizeFont(-1);
+ panel.add(sel, "wrap");
+
+
+
+ // Buttons
+ JButton button;
+
+ // TODO: LOW: printing
+// button = new JButton("Print");
+// button.addActionListener(new ActionListener() {
+// public void actionPerformed(ActionEvent e) {
+// try {
+// table.print();
+// } catch (PrinterException e1) {
+// JOptionPane.showMessageDialog(ComponentAnalysisDialog.this,
+// "An error occurred while printing.", "Print error",
+// JOptionPane.ERROR_MESSAGE);
+// }
+// }
+// });
+// panel.add(button,"tag ok");
+
+ button = new JButton("Close");
+ button.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ ComponentAnalysisDialog.this.dispose();
+ }
+ });
+ panel.add(button,"span, split, tag cancel");
+
+
+ setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+ GUIUtil.installEscapeCloseOperation(this);
+ pack();
+ }
+
+
+
+ /**
+ * Updates the data in the table and fires a table data change event.
+ */
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ AerodynamicForces forces;
+ WarningSet set = new WarningSet();
+ conditions.setAOA(aoa.getValue());
+ conditions.setTheta(theta.getValue());
+ conditions.setMach(mach.getValue());
+ conditions.setRollRate(roll.getValue());
+ conditions.setReference(configuration);
+
+ if (worstToggle.isSelected()) {
+ calculator.getWorstCP(conditions, null);
+ if (!MathUtil.equals(conditions.getTheta(), theta.getValue())) {
+ fakeChange = true;
+ theta.setValue(conditions.getTheta()); // Fires a stateChanged event
+ fakeChange = false;
+ return;
+ }
+ }
+
+ Map<RocketComponent, AerodynamicForces> data = calculator.getForceAnalysis(conditions, set);
+
+ cpData.clear();
+ dragData.clear();
+ rollData.clear();
+ for (RocketComponent c: configuration) {
+ forces = data.get(c);
+ if (forces == null)
+ continue;
+ if (forces.cp != null) {
+ cpData.add(forces);
+ }
+ if (!Double.isNaN(forces.CD)) {
+ dragData.add(forces);
+ }
+ if (c instanceof FinSet) {
+ rollData.add(forces);
+ }
+ }
+ forces = data.get(configuration.getRocket());
+ if (forces != null) {
+ cpData.add(forces);
+ dragData.add(forces);
+ rollData.add(forces);
+ totalCD = forces.CD;
+ } else {
+ totalCD = 0;
+ }
+
+ // Set warnings
+ if (set.isEmpty()) {
+ warningList.setListData(new String[] {
+ "<html><i><font color=\"gray\">No warnings.</font></i>"
+ });
+ } else {
+ warningList.setListData(new Vector<Warning>(set));
+ }
+
+ cpTableModel.fireTableDataChanged();
+ dragTableModel.fireTableDataChanged();
+ rollTableModel.fireTableDataChanged();
+ }
+
+
+ private class CustomCellRenderer extends JLabel implements TableCellRenderer {
+ private final Font normalFont;
+ private final Font boldFont;
+
+ public CustomCellRenderer() {
+ super();
+ normalFont = getFont();
+ boldFont = normalFont.deriveFont(Font.BOLD);
+ }
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value,
+ boolean isSelected, boolean hasFocus, int row, int column) {
+
+ this.setText(value.toString());
+
+ if ((row < 0) || (row >= cpData.size()))
+ return this;
+
+ if (cpData.get(row).component instanceof Rocket) {
+ this.setFont(boldFont);
+ } else {
+ this.setFont(normalFont);
+ }
+ return this;
+ }
+ }
+
+
+
+ private class DragCellRenderer extends JLabel implements TableCellRenderer {
+ private final Font normalFont;
+ private final Font boldFont;
+
+ private final float[] start = { 0.3333f, 0.2f, 1.0f };
+ private final float[] end = { 0.0f, 0.8f, 1.0f };
+
+
+ public DragCellRenderer(Color baseColor) {
+ super();
+ normalFont = getFont();
+ boldFont = normalFont.deriveFont(Font.BOLD);
+ }
+ @Override
+ public Component getTableCellRendererComponent(JTable table, Object value,
+ boolean isSelected, boolean hasFocus, int row, int column) {
+
+ if (value instanceof Double) {
+
+ // A drag coefficient
+ double cd = (Double)value;
+ this.setText(String.format("%.2f (%.0f%%)", cd, 100*cd/totalCD));
+
+ float r = (float)(cd/1.5);
+
+ float hue = MathUtil.clamp(0.3333f * (1-2.0f*r), 0, 0.3333f);
+ float sat = MathUtil.clamp(0.8f*r + 0.1f*(1-r), 0, 1);
+ float val = 1.0f;
+
+ this.setBackground(Color.getHSBColor(hue, sat, val));
+ this.setOpaque(true);
+ this.setHorizontalAlignment(SwingConstants.CENTER);
+
+ } else {
+
+ // Other
+ this.setText(value.toString());
+ this.setOpaque(false);
+ this.setHorizontalAlignment(SwingConstants.LEFT);
+
+ }
+
+ if ((row < 0) || (row >= dragData.size()))
+ return this;
+
+ if ((dragData.get(row).component instanceof Rocket) || (column == 4)){
+ this.setFont(boldFont);
+ } else {
+ this.setFont(normalFont);
+ }
+ return this;
+ }
+ }
+
+
+ ///////// Singleton implementation
+
+ public static void showDialog(RocketPanel rocketpanel) {
+ if (singletonDialog != null)
+ singletonDialog.dispose();
+ singletonDialog = new ComponentAnalysisDialog(rocketpanel);
+ singletonDialog.setVisible(true);
+ }
+
+ public static void hideDialog() {
+ if (singletonDialog != null)
+ singletonDialog.dispose();
+ }
+
+}
--- /dev/null
+package net.sf.openrocket.gui.dialogs;
+
+import java.awt.Component;
+
+import javax.swing.JOptionPane;
+
+public class DetailDialog {
+
+ public static void showDetailedMessageDialog(Component parentComponent, Object message,
+ String details, String title, int messageType) {
+
+ // TODO: HIGH: Detailed dialog
+ JOptionPane.showMessageDialog(parentComponent, message, title, messageType, null);
+
+ }
+
+
+}
--- /dev/null
+package net.sf.openrocket.gui.dialogs;
+
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableColumnModel;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.gui.main.BasicFrame;
+import net.sf.openrocket.gui.main.MotorChooserDialog;
+import net.sf.openrocket.rocketcomponent.Motor;
+import net.sf.openrocket.rocketcomponent.MotorMount;
+import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.util.GUIUtil;
+
+public class EditMotorConfigurationDialog extends JDialog {
+
+ private final Rocket rocket;
+
+ private final MotorMount[] mounts;
+
+ private final JTable configurationTable;
+ private final MotorConfigurationTableModel configurationTableModel;
+
+
+ private final JButton newConfButton, removeConfButton;
+ private final JButton selectMotorButton, removeMotorButton;
+ private final JTextField configurationNameField;
+
+
+ private String currentID = null;
+ private MotorMount currentMount = null;
+
+ public EditMotorConfigurationDialog(final Rocket rocket, Window parent) {
+ super(parent, "Edit motor configurations");
+
+ if (parent != null)
+ this.setModalityType(ModalityType.DOCUMENT_MODAL);
+ else
+ this.setModalityType(ModalityType.APPLICATION_MODAL);
+
+ this.rocket = rocket;
+
+ ArrayList<MotorMount> mountList = new ArrayList<MotorMount>();
+ Iterator<RocketComponent> iterator = rocket.deepIterator();
+ while (iterator.hasNext()) {
+ RocketComponent c = iterator.next();
+ if (c instanceof MotorMount) {
+ mountList.add((MotorMount)c);
+ }
+ }
+ mounts = mountList.toArray(new MotorMount[0]);
+
+
+
+ JPanel panel = new JPanel(new MigLayout("fill, flowy"));
+
+
+ //// Motor mount selection
+
+ JLabel label = new JLabel("<html><b>Motor mounts:</b>");
+ panel.add(label, "gapbottom para");
+
+ label = new JLabel("<html>Select which components function as motor mounts:");
+ panel.add(label,"ay 100%, w 1px, growx");
+
+
+ JTable table = new JTable(new MotorMountTableModel());
+ table.setTableHeader(null);
+ table.setShowVerticalLines(false);
+ table.setRowSelectionAllowed(false);
+ table.setColumnSelectionAllowed(false);
+
+ TableColumnModel columnModel = table.getColumnModel();
+ TableColumn col0 = columnModel.getColumn(0);
+ int w = table.getRowHeight() + 2;
+ col0.setMinWidth(w);
+ col0.setPreferredWidth(w);
+ col0.setMaxWidth(w);
+
+ JScrollPane scroll = new JScrollPane(table);
+ panel.add(scroll, "w 200lp, h 150lp, grow, wrap 20lp");
+
+
+
+
+
+ //// Motor selection
+
+ label = new JLabel("<html><b>Motor configurations:</b>");
+ panel.add(label, "spanx, gapbottom para");
+
+
+ label = new JLabel("Configuration name:");
+ String tip = "Leave name empty for default.";
+ label.setToolTipText(tip);
+ panel.add(label, "");
+
+ configurationNameField = new JTextField(10);
+ configurationNameField.setToolTipText(tip);
+ configurationNameField.getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ update();
+ }
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ update();
+ }
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ update();
+ }
+ private void update() {
+ String text = configurationNameField.getText();
+ if (currentID != null) {
+ rocket.setMotorConfigurationName(currentID, text);
+ int row = configurationTable.getSelectedRow();
+ configurationTableModel.fireTableCellUpdated(row, 0);
+ updateEnabled();
+ }
+ }
+ });
+ panel.add(configurationNameField, "cell 2 1, gapright para");
+
+ newConfButton = new JButton("New configuration");
+ newConfButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ String id = rocket.newMotorConfigurationID();
+ rocket.getDefaultConfiguration().setMotorConfigurationID(id);
+ configurationTableModel.fireTableDataChanged();
+ updateEnabled();
+ }
+ });
+ panel.add(newConfButton, "cell 3 1");
+
+ removeConfButton = new JButton("Remove configuration");
+ removeConfButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (currentID == null)
+ return;
+ rocket.removeMotorConfigurationID(currentID);
+ rocket.getDefaultConfiguration().setMotorConfigurationID(null);
+ configurationTableModel.fireTableDataChanged();
+ updateEnabled();
+ }
+ });
+ panel.add(removeConfButton, "cell 4 1");
+
+
+
+
+ configurationTableModel = new MotorConfigurationTableModel();
+ configurationTable = new JTable(configurationTableModel);
+ configurationTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ configurationTable.setCellSelectionEnabled(true);
+
+ configurationTable.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+
+ if (e.getClickCount() == 1) {
+
+ // Single click updates selection
+ updateEnabled();
+
+ } else if (e.getClickCount() == 2) {
+
+ // Double-click edits motor
+ selectMotor();
+
+ }
+
+ }
+ });
+
+
+ scroll = new JScrollPane(configurationTable);
+ panel.add(scroll, "cell 1 2, spanx, w 500lp, h 150lp, grow");
+
+
+ selectMotorButton = new JButton("Select motor");
+ selectMotorButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ selectMotor();
+ }
+ });
+ panel.add(selectMotorButton, "spanx, flowx, split 2, ax 50%");
+
+
+ removeMotorButton = new JButton("Remove motor");
+ removeMotorButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ removeMotor();
+ }
+ });
+ panel.add(removeMotorButton, "ax 50%");
+
+
+
+ //// Close button
+
+ JButton close = new JButton("Close");
+ close.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ EditMotorConfigurationDialog.this.dispose();
+ }
+ });
+ panel.add(close, "spanx, right");
+
+ this.add(panel);
+ this.validate();
+ this.pack();
+
+ updateEnabled();
+
+ GUIUtil.installEscapeCloseOperation(this);
+ GUIUtil.setDefaultButton(close);
+
+ // Undo description
+ final OpenRocketDocument document = BasicFrame.findDocument(rocket);
+ if (document != null) {
+ document.startUndo("Edit motor configurations");
+ this.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosed(WindowEvent e) {
+ document.stopUndo();
+ }
+ });
+ }
+ }
+
+
+
+
+ private void updateEnabled() {
+ int column = configurationTable.getSelectedColumn();
+ int row = configurationTable.getSelectedRow();
+
+ if (column < 0 || row < 0) {
+ currentID = null;
+ currentMount = null;
+ } else {
+
+ currentID = findID(row);
+ if (column == 0) {
+ currentMount = null;
+ } else {
+ currentMount = findMount(column);
+ }
+ rocket.getDefaultConfiguration().setMotorConfigurationID(currentID);
+
+ }
+
+ configurationNameField.setEnabled(currentID != null);
+ if (currentID == null) {
+ configurationNameField.setText("");
+ } else {
+ configurationNameField.setText(rocket.getMotorConfigurationName(currentID));
+ }
+ removeConfButton.setEnabled(currentID != null);
+ selectMotorButton.setEnabled(currentMount != null && currentID != null);
+ removeMotorButton.setEnabled(currentMount != null && currentID != null);
+ }
+
+
+
+
+ private void selectMotor() {
+ if (currentID == null || currentMount == null)
+ return;
+
+ MotorChooserDialog dialog = new MotorChooserDialog(currentMount.getMotor(currentID),
+ currentMount.getMotorDelay(currentID), currentMount.getMotorMountDiameter());
+ dialog.setVisible(true);
+ Motor m = dialog.getSelectedMotor();
+ double d = dialog.getSelectedDelay();
+
+ if (m != null) {
+ currentMount.setMotor(currentID, m);
+ currentMount.setMotorDelay(currentID, d);
+ }
+
+ int row = configurationTable.getSelectedRow();
+ configurationTableModel.fireTableRowsUpdated(row, row);
+ updateEnabled();
+ }
+
+
+ private void removeMotor() {
+ if (currentID == null || currentMount == null)
+ return;
+
+ currentMount.setMotor(currentID, null);
+
+ int row = configurationTable.getSelectedRow();
+ configurationTableModel.fireTableRowsUpdated(row, row);
+ updateEnabled();
+ }
+
+
+ private String findID(int row) {
+ return rocket.getMotorConfigurationIDs()[row+1];
+ }
+
+
+ private MotorMount findMount(int column) {
+ MotorMount mount = null;
+
+ int count = column;
+ for (MotorMount m: mounts) {
+ if (m.isMotorMount())
+ count--;
+ if (count <= 0) {
+ mount = m;
+ break;
+ }
+ }
+
+ if (mount == null) {
+ throw new IndexOutOfBoundsException("motor mount not found, column="+column);
+ }
+ return mount;
+ }
+
+
+ /**
+ * The table model for selecting whether components are motor mounts or not.
+ */
+ private class MotorMountTableModel extends AbstractTableModel {
+
+ @Override
+ public int getColumnCount() {
+ return 2;
+ }
+
+ @Override
+ public int getRowCount() {
+ return mounts.length;
+ }
+
+ @Override
+ public Class<?> getColumnClass(int column) {
+ switch (column) {
+ case 0:
+ return Boolean.class;
+
+ case 1:
+ return String.class;
+
+ default:
+ throw new IndexOutOfBoundsException("column="+column);
+ }
+ }
+
+ @Override
+ public Object getValueAt(int row, int column) {
+ switch (column) {
+ case 0:
+ return new Boolean(mounts[row].isMotorMount());
+
+ case 1:
+ return mounts[row].toString();
+
+ default:
+ throw new IndexOutOfBoundsException("column="+column);
+ }
+ }
+
+ @Override
+ public boolean isCellEditable(int row, int column) {
+ return column == 0;
+ }
+
+ @Override
+ public void setValueAt(Object value, int row, int column) {
+ if (column != 0 || !(value instanceof Boolean)) {
+ throw new IllegalArgumentException("column="+column+", value="+value);
+ }
+
+ mounts[row].setMotorMount((Boolean)value);
+ configurationTableModel.fireTableStructureChanged();
+ updateEnabled();
+ }
+ }
+
+
+
+ /**
+ * The table model for selecting and editing the motor configurations.
+ */
+ private class MotorConfigurationTableModel extends AbstractTableModel {
+
+ @Override
+ public int getColumnCount() {
+ int count = 1;
+ for (MotorMount m: mounts) {
+ if (m.isMotorMount())
+ count++;
+ }
+ return count;
+ }
+
+ @Override
+ public int getRowCount() {
+ return rocket.getMotorConfigurationIDs().length-1;
+ }
+
+ @Override
+ public Object getValueAt(int row, int column) {
+
+ String id = findID(row);
+
+ if (column == 0) {
+ return rocket.getMotorConfigurationNameOrDescription(id);
+ }
+
+ MotorMount mount = findMount(column);
+ Motor motor = mount.getMotor(id);
+ if (motor == null)
+ return "None";
+
+ String str = motor.getDesignation(mount.getMotorDelay(id));
+ int count = mount.getMotorCount();
+ if (count > 1) {
+ str = "" + count + "\u00d7 " + str;
+ }
+ return str;
+ }
+
+
+ @Override
+ public String getColumnName(int column) {
+ if (column == 0) {
+ return "Configuration name";
+ }
+
+ MotorMount mount = findMount(column);
+ String name = mount.toString();
+ int count = mount.getMotorCount();
+ if (count > 1) {
+ name = name + " (\u00d7" + count + ")";
+ }
+ return name;
+ }
+
+
+ }
+
+
+
+
+}
--- /dev/null
+package net.sf.openrocket.gui.dialogs;
+
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.gui.components.ResizeLabel;
+import net.sf.openrocket.util.GUIUtil;
+
+public class LicenseDialog extends JDialog {
+ private static final String LICENSE_FILENAME = "LICENSE.TXT";
+
+ private static final String DEFAULT_LICENSE_TEXT =
+ "\n" +
+ "Error: Unable to load " + LICENSE_FILENAME + "!\n" +
+ "\n" +
+ "OpenRocket is licensed under the GNU GPL version 3, with additional permissions.\n" +
+ "See http://openrocket.sourceforge.net/ for details.";
+
+ public LicenseDialog(JFrame parent) {
+ super(parent, true);
+
+ JPanel panel = new JPanel(new MigLayout("fill"));
+
+ panel.add(new ResizeLabel("OpenRocket license", 10), "ax 50%, wrap para");
+
+ String licenseText;
+ try {
+
+ BufferedReader reader = new BufferedReader(
+ new InputStreamReader(ClassLoader.getSystemResourceAsStream(LICENSE_FILENAME)));
+ StringBuffer sb = new StringBuffer();
+ for (String s = reader.readLine(); s != null; s = reader.readLine()) {
+ sb.append(s);
+ sb.append('\n');
+ }
+ licenseText = sb.toString();
+
+ } catch (Exception e) {
+
+ licenseText = DEFAULT_LICENSE_TEXT;
+
+ }
+
+ JTextArea text = new JTextArea(licenseText);
+ text.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
+ text.setRows(20);
+ text.setColumns(80);
+ 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) {
+ LicenseDialog.this.dispose();
+ }
+ });
+ panel.add(close, "right");
+
+ this.add(panel);
+ this.setTitle("OpenRocket license");
+ this.pack();
+ this.setLocationByPlatform(true);
+ GUIUtil.setDefaultButton(close);
+ GUIUtil.installEscapeCloseOperation(this);
+ }
+
+}
--- /dev/null
+package net.sf.openrocket.gui.dialogs;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractListModel;
+import javax.swing.ComboBoxModel;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+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;
+import net.sf.openrocket.util.Prefs;
+
+public class PreferencesDialog extends JDialog {
+
+ private final List<DefaultUnitSelector> unitSelectors = new ArrayList<DefaultUnitSelector>();
+
+ private PreferencesDialog() {
+ super((JFrame)null, "Preferences", true);
+
+ JPanel panel = new JPanel(new MigLayout("fill, gap unrel","[grow]","[grow][]"));
+
+ JTabbedPane tabbedPane = new JTabbedPane();
+ panel.add(tabbedPane,"grow, wrap");
+
+
+ tabbedPane.addTab("Units", null, unitsPane(), "Default units");
+ tabbedPane.addTab("Confirmation", null, confirmationPane(), "Confirmation dialog settings");
+
+
+
+ JButton close = new JButton("Close");
+ close.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ PreferencesDialog.this.setVisible(false);
+ PreferencesDialog.this.dispose();
+ }
+ });
+ panel.add(close,"span, right, tag close");
+
+ this.setContentPane(panel);
+ pack();
+ setAlwaysOnTop(true);
+ this.setLocationRelativeTo(null);
+
+ this.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosed(WindowEvent e) {
+ Prefs.storeDefaultUnits();
+ }
+ });
+
+ GUIUtil.setDefaultButton(close);
+ GUIUtil.installEscapeCloseOperation(this);
+ }
+
+
+ private JPanel confirmationPane() {
+ JPanel panel = new JPanel(new MigLayout("fill"));
+
+ panel.add(new JLabel("Position to insert new body components:"));
+ panel.add(new JComboBox(new PrefChoiseSelector(Prefs.BODY_COMPONENT_INSERT_POSITION_KEY,
+ "Always ask", "Insert in middle", "Add to end")), "wrap para, sg combos");
+
+ panel.add(new JLabel("Confirm deletion of simulations:"));
+ panel.add(new JComboBox(new PrefBooleanSelector(Prefs.CONFIRM_DELETE_SIMULATION,
+ "Delete", "Confirm", true)), "wrap para, sg combos");
+
+ return panel;
+ }
+
+ private JPanel unitsPane() {
+ JPanel panel = new JPanel(new MigLayout("", "[][]40lp[][]"));
+ JComboBox combo;
+
+ panel.add(new JLabel("Select your preferred units:"), "span, wrap paragraph");
+
+/*
+ public static final UnitGroup UNITS_LENGTH;
+ public static final UnitGroup UNITS_MOTOR_DIMENSIONS;
+ public static final UnitGroup UNITS_DISTANCE;
+
+ public static final UnitGroup UNITS_VELOCITY;
+ public static final UnitGroup UNITS_ACCELERATION;
+ public static final UnitGroup UNITS_MASS;
+ public static final UnitGroup UNITS_FORCE;
+ public static final UnitGroup UNITS_IMPULSE;
+
+ public static final UnitGroup UNITS_STABILITY;
+ public static final UnitGroup UNITS_FLIGHT_TIME;
+ public static final UnitGroup UNITS_ROLL;
+
+ public static final UnitGroup UNITS_AREA;
+ public static final UnitGroup UNITS_DENSITY_LINE;
+ public static final UnitGroup UNITS_DENSITY_SURFACE;
+ public static final UnitGroup UNITS_DENSITY_BULK;
+ public static final UnitGroup UNITS_ROUGHNESS;
+
+ public static final UnitGroup UNITS_TEMPERATURE;
+ public static final UnitGroup UNITS_PRESSURE;
+ public static final UnitGroup UNITS_ANGLE;
+*/
+
+ panel.add(new JLabel("Rocket dimensions:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_LENGTH));
+ panel.add(combo, "sizegroup boxes");
+
+ panel.add(new JLabel("Line density:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_LINE));
+ panel.add(combo, "sizegroup boxes, wrap");
+
+
+
+ panel.add(new JLabel("Motor dimensions:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_MOTOR_DIMENSIONS));
+ panel.add(combo, "sizegroup boxes");
+
+ panel.add(new JLabel("Surface density:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_SURFACE));
+ panel.add(combo, "sizegroup boxes, wrap");
+
+
+
+ panel.add(new JLabel("Distance:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DISTANCE));
+ panel.add(combo, "sizegroup boxes");
+
+ panel.add(new JLabel("Bulk density::"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_DENSITY_BULK));
+ panel.add(combo, "sizegroup boxes, wrap");
+
+
+
+ panel.add(new JLabel("Velocity:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_VELOCITY));
+ panel.add(combo, "sizegroup boxes");
+
+ panel.add(new JLabel("Surface roughness:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ROUGHNESS));
+ panel.add(combo, "sizegroup boxes, wrap");
+
+
+
+ panel.add(new JLabel("Acceleration:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ACCELERATION));
+ panel.add(combo, "sizegroup boxes");
+
+ panel.add(new JLabel("Area:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_AREA));
+ panel.add(combo, "sizegroup boxes, wrap");
+
+
+
+ panel.add(new JLabel("Mass:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_MASS));
+ panel.add(combo, "sizegroup boxes");
+
+ panel.add(new JLabel("Angle:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ANGLE));
+ panel.add(combo, "sizegroup boxes, wrap");
+
+
+
+ panel.add(new JLabel("Force:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_FORCE));
+ panel.add(combo, "sizegroup boxes");
+
+ panel.add(new JLabel("Roll rate:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_ROLL));
+ panel.add(combo, "sizegroup boxes, wrap");
+
+
+
+ panel.add(new JLabel("Total impulse:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_IMPULSE));
+ panel.add(combo, "sizegroup boxes");
+
+ panel.add(new JLabel("Temperature:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_TEMPERATURE));
+ panel.add(combo, "sizegroup boxes, wrap");
+
+
+
+ panel.add(new JLabel("Stability:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_STABILITY));
+ panel.add(combo, "sizegroup boxes");
+
+ panel.add(new JLabel("Pressure:"));
+ combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_PRESSURE));
+ panel.add(combo, "sizegroup boxes, wrap para");
+
+
+
+ JButton button = new JButton("Default metric");
+ button.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ UnitGroup.setDefaultMetricUnits();
+ for (DefaultUnitSelector s: unitSelectors)
+ s.fireChange();
+ }
+ });
+ panel.add(button, "spanx, split 2, grow");
+
+ button = new JButton("Default imperial");
+ button.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ UnitGroup.setDefaultImperialUnits();
+ for (DefaultUnitSelector s: unitSelectors)
+ s.fireChange();
+ }
+ });
+ panel.add(button, "grow, wrap para");
+
+
+ panel.add(new ResizeLabel("The effects will take place the next time you open a window.",-2),
+ "spanx, wrap");
+
+
+ return panel;
+ }
+
+
+
+
+ private class DefaultUnitSelector extends AbstractListModel implements ComboBoxModel {
+
+ private final UnitGroup group;
+ public DefaultUnitSelector(UnitGroup group) {
+ this.group = group;
+ unitSelectors.add(this);
+ }
+
+ @Override
+ public Object getSelectedItem() {
+ return group.getDefaultUnit();
+ }
+ @Override
+ public void setSelectedItem(Object item) {
+ if (!(item instanceof Unit)) {
+ throw new IllegalArgumentException("Illegal argument "+item);
+ }
+ group.setDefaultUnit(group.getUnitIndex((Unit)item));
+ }
+ @Override
+ public Object getElementAt(int index) {
+ return group.getUnit(index);
+ }
+ @Override
+ public int getSize() {
+ return group.getUnitCount();
+ }
+
+
+ public void fireChange() {
+ this.fireContentsChanged(this, 0, this.getSize());
+ }
+ }
+
+
+
+ private class PrefChoiseSelector extends AbstractListModel implements ComboBoxModel {
+ private final String preference;
+ private final String[] descriptions;
+
+ public PrefChoiseSelector(String preference, String ... descriptions) {
+ this.preference = preference;
+ this.descriptions = descriptions;
+ }
+
+ @Override
+ public Object getSelectedItem() {
+ return descriptions[Prefs.getChoise(preference, descriptions.length, 0)];
+ }
+
+ @Override
+ public void setSelectedItem(Object item) {
+ if (!(item instanceof String)) {
+ throw new IllegalArgumentException("Illegal argument "+item);
+ }
+ int index;
+ for (index = 0; index < descriptions.length; index++) {
+ if (((String)item).equalsIgnoreCase(descriptions[index]))
+ break;
+ }
+ if (index >= descriptions.length) {
+ throw new IllegalArgumentException("Illegal argument "+item);
+ }
+
+ Prefs.putChoise(preference, index);
+ }
+
+ @Override
+ public Object getElementAt(int index) {
+ return descriptions[index];
+ }
+ @Override
+ public int getSize() {
+ return descriptions.length;
+ }
+ }
+
+
+ private class PrefBooleanSelector extends AbstractListModel implements ComboBoxModel {
+ private final String preference;
+ private final String trueDesc, falseDesc;
+ private final boolean def;
+
+ public PrefBooleanSelector(String preference, String falseDescription,
+ String trueDescription, boolean defaultState) {
+ this.preference = preference;
+ this.trueDesc = trueDescription;
+ this.falseDesc = falseDescription;
+ this.def = defaultState;
+ }
+
+ @Override
+ public Object getSelectedItem() {
+ if (Prefs.NODE.getBoolean(preference, def)) {
+ return trueDesc;
+ } else {
+ return falseDesc;
+ }
+ }
+
+ @Override
+ public void setSelectedItem(Object item) {
+ if (!(item instanceof String)) {
+ throw new IllegalArgumentException("Illegal argument "+item);
+ }
+
+ if (trueDesc.equals(item)) {
+ Prefs.NODE.putBoolean(preference, true);
+ } else if (falseDesc.equals(item)) {
+ Prefs.NODE.putBoolean(preference, false);
+ } else {
+ throw new IllegalArgumentException("Illegal argument "+item);
+ }
+ }
+
+ @Override
+ public Object getElementAt(int index) {
+ switch (index) {
+ case 0:
+ return def ? trueDesc : falseDesc;
+
+ case 1:
+ return def ? falseDesc: trueDesc;
+
+ default:
+ throw new IndexOutOfBoundsException("Boolean asked for index="+index);
+ }
+ }
+ @Override
+ public int getSize() {
+ return 2;
+ }
+ }
+
+
+
+ //////// Singleton implementation ////////
+
+ private static PreferencesDialog dialog = null;
+
+ public static void showPreferences() {
+ if (dialog != null) {
+ dialog.dispose();
+ }
+ dialog = new PreferencesDialog();
+ dialog.setVisible(true);
+ }
+
+
+}
--- /dev/null
+package net.sf.openrocket.gui.dialogs;
+
+import java.awt.Window;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.SwingWorker;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.util.Pair;
+
+
+/**
+ * A modal dialog that runs specific SwingWorkers and waits until they complete.
+ * A message and progress bar is provided and a cancel button. If the cancel button
+ * is pressed, the currently running worker is interrupted and the later workers are not
+ * executed.
+ *
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class SwingWorkerDialog extends JDialog implements PropertyChangeListener {
+
+ private final JLabel label;
+ private final JProgressBar progressBar;
+
+ private int position;
+ private Pair<String, SwingWorker<?,?>>[] workers;
+
+ private boolean cancelled = false;
+
+ public SwingWorkerDialog(Window parent, String title) {
+ super(parent, title, ModalityType.APPLICATION_MODAL);
+
+ JPanel panel = new JPanel(new MigLayout("fill"));
+
+ label = new JLabel("");
+ panel.add(label, "wrap para");
+
+ progressBar = new JProgressBar();
+ panel.add(progressBar, "growx, wrap para");
+
+ JButton cancel = new JButton("Cancel");
+ // TODO: CRITICAL: Implement cancel
+ panel.add(cancel, "right");
+
+ this.add(panel);
+ this.pack();
+ this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+ }
+
+
+ /**
+ * Execute the provided workers one after another. When this call returns
+ * the workers will all have completed.
+ *
+ * @param workers pairs of description texts and workers to run.
+ */
+ public void runWorkers(Pair<String, SwingWorker<?,?>> ... workers) {
+ if (workers.length == 0) {
+ throw new IllegalArgumentException("No workers provided.");
+ }
+
+ this.workers = workers;
+ position = -1;
+
+ for (int i=0; i < workers.length; i++) {
+ workers[i].getV().addPropertyChangeListener(this);
+ }
+
+ nextWorker();
+ this.setVisible(true); // Waits until all have ended
+ }
+
+
+
+ /**
+ * Starts the execution of the next worker in the queue. If the last worker
+ * has completed or the operation has been cancelled, closes the dialog.
+ */
+ private void nextWorker() {
+ if ((position >= workers.length-1) || cancelled) {
+ close();
+ return;
+ }
+
+ position++;
+
+ label.setText(workers[position].getU());
+ workers[position].getV().execute();
+ }
+
+
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (workers[position].getV().getState() == SwingWorker.StateValue.DONE) {
+ nextWorker();
+ }
+
+ int value = workers[position].getV().getProgress();
+ value = (value + position*100 ) / workers.length;
+ progressBar.setValue(value);
+ }
+
+
+
+ private void close() {
+ for (int i=0; i < workers.length; i++) {
+ workers[i].getV().removePropertyChangeListener(this);
+ }
+ this.setVisible(false);
+ }
+}
package net.sf.openrocket.gui.main;
+import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.LookAndFeel;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
+import javax.swing.SwingWorker;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.swing.border.TitledBorder;
import net.sf.openrocket.file.RocketLoadException;
import net.sf.openrocket.file.RocketLoader;
import net.sf.openrocket.file.RocketSaver;
-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.dialogs.ComponentAnalysisDialog;
+import net.sf.openrocket.gui.dialogs.LicenseDialog;
+import net.sf.openrocket.gui.dialogs.PreferencesDialog;
import net.sf.openrocket.gui.scalefigure.RocketPanel;
import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
import net.sf.openrocket.rocketcomponent.Rocket;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.Stage;
+import net.sf.openrocket.util.ConcurrentProgressMonitor;
+import net.sf.openrocket.util.ConcurrentProgressMonitorInputStream;
import net.sf.openrocket.util.Icons;
import net.sf.openrocket.util.Prefs;
for (File file: files) {
System.out.println("Opening file: " + file);
- if (open(file)) {
+ if (open(file, this)) {
opened = true;
}
}
* Open the specified file in a new design frame. If an error occurs, an error dialog
* is shown and <code>false</code> is returned.
*
- * @param file the file to open.
- * @return whether the file was successfully loaded and opened.
+ * @param file the file to open.
+ * @param parent the parent component for which a progress dialog is opened.
+ * @return whether the file was successfully loaded and opened.
*/
- private static boolean open(File file) {
+ private static boolean open(File file, Component parent) {
OpenRocketDocument doc = null;
+
+
try {
- doc = ROCKET_LOADER.load(file);
+ doc = ROCKET_LOADER.load(file, parent);
} catch (RocketLoadException e) {
JOptionPane.showMessageDialog(null, "Unable to open file '" + file.getName()
+"': " + e.getMessage(), "Error opening file", JOptionPane.ERROR_MESSAGE);
+ private static class OpenWorker extends SwingWorker<OpenRocketDocument, Void> {
+ private final File file;
+ private final Component parent;
+ private ConcurrentProgressMonitor monitor = null;
+
+ public OpenWorker(File file, Component parent) {
+ this.file = file;
+ this.parent = parent;
+ }
+
+ @Override
+ protected OpenRocketDocument doInBackground() throws Exception {
+ ConcurrentProgressMonitorInputStream is =
+ new ConcurrentProgressMonitorInputStream(parent,
+ "Loading " + file.getName(), new FileInputStream(file));
+ monitor = is.getProgressMonitor();
+ return ROCKET_LOADER.load(is);
+ }
+
+ public ConcurrentProgressMonitor getMonitor() {
+ return monitor;
+ }
+ }
+
+
+
+
private boolean saveAction() {
File file = document.getFile();
if (file==null) {
+ /**
+ * Find a currently open BasicFrame containing the specified rocket. This method
+ * can be used to map a Rocket to a BasicFrame from GUI methods.
+ *
+ * @param rocket the Rocket.
+ * @return the corresponding BasicFrame, or <code>null</code> if none found.
+ */
+ public static BasicFrame findFrame(Rocket rocket) {
+ for (BasicFrame f: frames) {
+ if (f.rocket == rocket)
+ return f;
+ }
+ return null;
+ }
+
+ /**
+ * Find a currently open document by the rocket object. This method can be used
+ * to map a Rocket to OpenRocketDocument from GUI methods.
+ *
+ * @param rocket the Rocket.
+ * @return the corresponding OpenRocketDocument, or <code>null</code> if not found.
+ */
+ public static OpenRocketDocument findDocument(Rocket rocket) {
+ for (BasicFrame f: frames) {
+ if (f.rocket == rocket)
+ return f.document;
+ }
+ return null;
+ }
// Check command-line for files
boolean opened = false;
for (String file: args) {
- if (open(new File(file))) {
+ if (open(new File(file), null)) {
opened = true;
}
}
+++ /dev/null
-package net.sf.openrocket.gui.main;
-
-import java.awt.Font;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
-
-import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.components.ResizeLabel;
-import net.sf.openrocket.util.GUIUtil;
-
-public class LicenseDialog extends JDialog {
- private static final String LICENSE_FILENAME = "LICENSE.TXT";
-
- private static final String DEFAULT_LICENSE_TEXT =
- "\n" +
- "Error: Unable to load " + LICENSE_FILENAME + "!\n" +
- "\n" +
- "OpenRocket is licensed under the GNU GPL version 3, with additional permissions.\n" +
- "See http://openrocket.sourceforge.net/ for details.";
-
- public LicenseDialog(JFrame parent) {
- super(parent, true);
-
- JPanel panel = new JPanel(new MigLayout("fill"));
-
- panel.add(new ResizeLabel("OpenRocket license", 10), "ax 50%, wrap para");
-
- String licenseText;
- try {
-
- BufferedReader reader = new BufferedReader(
- new InputStreamReader(ClassLoader.getSystemResourceAsStream(LICENSE_FILENAME)));
- StringBuffer sb = new StringBuffer();
- for (String s = reader.readLine(); s != null; s = reader.readLine()) {
- sb.append(s);
- sb.append('\n');
- }
- licenseText = sb.toString();
-
- } catch (Exception e) {
-
- licenseText = DEFAULT_LICENSE_TEXT;
-
- }
-
- JTextArea text = new JTextArea(licenseText);
- text.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
- text.setRows(20);
- text.setColumns(80);
- 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) {
- LicenseDialog.this.dispose();
- }
- });
- panel.add(close, "right");
-
- this.add(panel);
- this.setTitle("OpenRocket license");
- this.pack();
- this.setLocationByPlatform(true);
- GUIUtil.setDefaultButton(close);
- GUIUtil.installEscapeCloseOperation(this);
- }
-
-}
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.Collator;
+import java.util.ArrayList;
import java.util.Comparator;
import java.util.Locale;
import java.util.regex.Matcher;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
+import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
"Show motors with diameter equal to that of the motor mount"
};
private static final int SHOW_MAX = 2;
-
+
+ private final JTextField searchField;
+ private String[] searchTerms = new String[0];
private final double diameter;
this.selectedDelay = delay;
this.diameter = diameter;
- JPanel panel = new JPanel(new MigLayout("fill"));
+ JPanel panel = new JPanel(new MigLayout("fill", "[grow][]"));
// Label
JLabel label = new JLabel("Select a rocket motor:");
label.setFont(label.getFont().deriveFont(Font.BOLD));
- panel.add(label,"split 2, growx");
+ panel.add(label,"growx");
label = new JLabel("Motor mount diameter: " +
UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(diameter));
- panel.add(label,"alignx 100%, wrap paragraph");
+ panel.add(label,"gapleft para, wrap paragraph");
// Diameter selection
sel = SHOW_ALL;
switch (sel) {
case SHOW_ALL:
- System.out.println("Setting filter: all");
sorter.setRowFilter(new MotorRowFilterAll());
break;
case SHOW_SMALLER:
- System.out.println("Setting filter: smaller");
sorter.setRowFilter(new MotorRowFilterSmaller());
break;
case SHOW_EXACT:
- System.out.println("Setting filter: exact");
sorter.setRowFilter(new MotorRowFilterExact());
break;
setSelectionVisible();
}
});
- panel.add(combo,"growx, wrap");
+ panel.add(combo,"growx 1000");
+
+ label = new JLabel("Search:");
+ panel.add(label, "gapleft para, split 2");
+
+ searchField = new JTextField();
+ searchField.getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void changedUpdate(DocumentEvent e) {
+ update();
+ }
+ @Override
+ public void insertUpdate(DocumentEvent e) {
+ update();
+ }
+ @Override
+ public void removeUpdate(DocumentEvent e) {
+ update();
+ }
+
+ private void update() {
+ String text = searchField.getText().trim();
+ String[] split = text.split("\\s+");
+ ArrayList<String> list = new ArrayList<String>();
+ for (String s: split) {
+ s = s.trim().toLowerCase();
+ if (s.length() > 0) {
+ list.add(s);
+ }
+ }
+ searchTerms = list.toArray(new String[0]);
+ sorter.sort();
+ }
+ });
+ panel.add(searchField, "growx 1, wrap");
+
+
+
// Table, overridden to show meaningful tooltip texts
model = new MotorDatabaseModel(current);
table = new JTable(model) {
JScrollPane scrollpane = new JScrollPane();
scrollpane.setViewportView(table);
- panel.add(scrollpane,"grow, width :700:, height :300:, wrap paragraph");
+ panel.add(scrollpane,"spanx, grow, width :700:, height :300:, wrap paragraph");
// Ejection delay
- panel.add(new JLabel("Select ejection charge delay:"), "split 3, gap rel");
+ panel.add(new JLabel("Select ejection charge delay:"), "spanx, split 3, gap rel");
delayBox = new JComboBox();
delayBox.setEditable(true);
MotorChooserDialog.this.setVisible(false);
}
});
- panel.add(okButton,"split, tag ok");
+ panel.add(okButton,"spanx, split, tag ok");
button = new JButton("Cancel");
button.addActionListener(new ActionListener() {
// Table can be scrolled only after pack() has been called
setSelectionVisible();
+
+ // Focus the search field
+ searchField.grabFocus();
}
private void setSelectionVisible() {
*/
private abstract class MotorRowFilter extends RowFilter<TableModel,Integer> {
@Override
- public boolean include(
- RowFilter.Entry<? extends TableModel, ? extends Integer> entry) {
+ public boolean include(RowFilter.Entry<? extends TableModel, ? extends Integer> entry) {
int index = entry.getIdentifier();
Motor m = model.getMotor(index);
- return include(m);
+ return filterByDiameter(m) && filterByString(m);
}
- public abstract boolean include(Motor m);
+ public abstract boolean filterByDiameter(Motor m);
+
+
+ public boolean filterByString(Motor m) {
+ main: for (String s : searchTerms) {
+ for (MotorColumns col : MotorColumns.values()) {
+ String str = col.getValue(m).toLowerCase();
+ if (str.indexOf(s) >= 0)
+ continue main;
+ }
+ return false;
+ }
+ return true;
+ }
}
/**
*/
private class MotorRowFilterAll extends MotorRowFilter {
@Override
- public boolean include(Motor m) {
+ public boolean filterByDiameter(Motor m) {
return true;
}
}
*/
private class MotorRowFilterSmaller extends MotorRowFilter {
@Override
- public boolean include(Motor m) {
+ public boolean filterByDiameter(Motor m) {
return (m.getDiameter() <= diameter + 0.0004);
}
}
*/
private class MotorRowFilterExact extends MotorRowFilter {
@Override
- public boolean include(Motor m) {
+ public boolean filterByDiameter(Motor m) {
return ((m.getDiameter() <= diameter + 0.0004) &&
(m.getDiameter() >= diameter - 0.0015));
}
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.document.Simulation;
-import net.sf.openrocket.gui.DetailDialog;
+import net.sf.openrocket.gui.dialogs.DetailDialog;
import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.MotorMount;
import net.sf.openrocket.rocketcomponent.MotorMount.IgnitionEvent;
};
+
private final List<Double> points;
private final String xmlName;
+
private ClusterConfiguration(String xmlName, double... points) {
this.xmlName = xmlName;
if (points.length == 0 || points.length%2 == 1) {
}
return ret;
}
+
+
+ @Override
+ public String toString() {
+ return xmlName;
+ }
}
* if attempted.
*
* @param index the fin point index to remove
+ * @throws IllegalFinPointException if removing the first or last fin point was attempted.
*/
- public void removePoint(int index) {
+ public void removePoint(int index) throws IllegalFinPointException {
if (index == 0 || index == points.size()-1) {
- throw new IllegalArgumentException("cannot remove first or last point");
+ throw new IllegalFinPointException("cannot remove first or last point");
}
points.remove(index);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
return points.size();
}
- public void setPoints(Coordinate[] p) {
+ public void setPoints(Coordinate[] p) throws IllegalFinPointException {
if (p[0].x != 0 || p[0].y != 0 || p[p.length-1].y != 0) {
- throw new IllegalArgumentException("Start or end point illegal.");
+ throw new IllegalFinPointException("Start or end point illegal.");
}
for (int i=0; i < p.length-1; i++) {
for (int j=i+2; j < p.length-1; j++) {
if (intersects(p[i].x, p[i].y, p[i+1].x, p[i+1].y,
p[j].x, p[j].y, p[j+1].x, p[j+1].y)) {
- throw new IllegalArgumentException("segments intersect");
+ throw new IllegalFinPointException("segments intersect");
}
}
if (p[i].z != 0) {
- throw new IllegalArgumentException("z-coordinate not zero");
+ throw new IllegalFinPointException("z-coordinate not zero");
}
}
* @param index the point index to modify.
* @param x the x-coordinate.
* @param y the y-coordinate.
+ * @throws IllegalFinPointException if the specified fin point would cause intersecting
+ * segments
*/
- public void setPoint(int index, double x, double y) {
+ public void setPoint(int index, double x, double y) throws IllegalFinPointException {
if (y < 0)
y = 0;
if (i != index-1 && i != index && i != index+1) {
if (intersects(x0,y0,x,y,px0,py0,px1,py1)) {
- throw new IllegalArgumentException("segments intersect");
+ throw new IllegalFinPointException("segments intersect");
}
}
if (i != index && i != index+1 && i != index+2) {
if (intersects(x,y,x1,y1,px0,py0,px1,py1)) {
- throw new IllegalArgumentException("segments intersect");
+ throw new IllegalFinPointException("segments intersect");
}
}
--- /dev/null
+package net.sf.openrocket.rocketcomponent;
+
+/**
+ * An exception signifying that an operation on the freeform fin set points was
+ * illegal (segments intersect, removing first or last point, etc).
+ *
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class IllegalFinPointException extends Exception {
+
+ public IllegalFinPointException() {
+
+ }
+
+ public IllegalFinPointException(String message) {
+ super(message);
+ }
+
+ public IllegalFinPointException(Throwable cause) {
+ super(cause);
+ }
+
+ public IllegalFinPointException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
import java.util.UUID;
import javax.swing.event.ChangeListener;
// Motor configuration list
- private List<String> motorConfigurationIDs = new ArrayList<String>();
- private Map<String, String> motorConfigurationNames = new HashMap<String, String>();
+ private ArrayList<String> motorConfigurationIDs = new ArrayList<String>();
+ private HashMap<String, String> motorConfigurationNames = new HashMap<String, String>();
{
motorConfigurationIDs.add(null);
}
}
+
+
+
/**
* Make a deep copy of the Rocket structure. This is a helper method which simply
* casts the result of the superclass method to a Rocket.
*/
+ @SuppressWarnings("unchecked")
@Override
public Rocket copy() {
Rocket copy = (Rocket)super.copy();
+ copy.motorConfigurationIDs = (ArrayList<String>) this.motorConfigurationIDs.clone();
+ copy.motorConfigurationNames =
+ (HashMap<String, String>) this.motorConfigurationNames.clone();
copy.resetListeners();
+
return copy;
}
-
-
-
-
-
/**
* Load the rocket structure from the source. The method loads the fields of this
* Rocket object and copies the references to siblings from the <code>source</code>.
* and therefore fires an UNDO_EVENT, masked with all applicable mass/aerodynamic/tree
* changes.
*/
+ @SuppressWarnings("unchecked")
public void loadFrom(Rocket r) {
super.copyFrom(r);
this.refType = r.refType;
this.customReferenceLength = r.customReferenceLength;
- this.motorConfigurationIDs = r.motorConfigurationIDs;
- this.motorConfigurationNames = r.motorConfigurationNames;
+ this.motorConfigurationIDs = (ArrayList<String>) r.motorConfigurationIDs.clone();
+ this.motorConfigurationNames =
+ (HashMap<String, String>) r.motorConfigurationNames.clone();
this.perfectFinish = r.perfectFinish;
+ String id = defaultConfiguration.getMotorConfigurationID();
+ if (!this.motorConfigurationIDs.contains(id))
+ defaultConfiguration.setMotorConfigurationID(null);
+
fireComponentChangeEvent(type);
}
*/
public void setMotorConfigurationName(String id, String name) {
motorConfigurationNames.put(id,name);
- fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
+ fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
}
--- /dev/null
+package net.sf.openrocket.util;
+
+import java.awt.Component;
+
+import javax.swing.ProgressMonitor;
+import javax.swing.SwingUtilities;
+
+
+/**
+ * A thread-safe <code>ProgressMonitor</code>. This class may be instantiated
+ * and the method {@link #setProgress(int)} called safely from any thread.
+ * <p>
+ * Why the FSCK&!¤#&%¤ isn't the default API version thread-safe?!?!
+ *
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class ConcurrentProgressMonitor extends ProgressMonitor {
+
+ public ConcurrentProgressMonitor(Component parentComponent, Object message,
+ String note, int min, int max) {
+ super(parentComponent, message, note, min, max);
+ }
+
+ @Override
+ public void setProgress(final int nv) {
+
+ if (SwingUtilities.isEventDispatchThread()) {
+ super.setProgress(nv);
+ } else {
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+ ConcurrentProgressMonitor.super.setProgress(nv);
+ }
+
+ });
+
+ }
+ }
+
+
+
+}
--- /dev/null
+/*
+ * TODO: CRITICAL: Licensing
+ */
+
+package net.sf.openrocket.util;
+
+import java.awt.Component;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+
+
+/**
+ * A functional equivalent of <code>ProgressMonitorInputStream</code> which
+ * uses {@link ConcurrentProgressMonitor} and leaves the progress dialog open
+ * to be manually closed later on.
+ */
+
+public class ConcurrentProgressMonitorInputStream extends FilterInputStream {
+ private ConcurrentProgressMonitor monitor;
+ private int nread = 0;
+ private int size = 0;
+
+
+ /**
+ * Constructs an object to monitor the progress of an input stream.
+ *
+ * @param message Descriptive text to be placed in the dialog box
+ * if one is popped up.
+ * @param parentComponent The component triggering the operation
+ * being monitored.
+ * @param in The input stream to be monitored.
+ */
+ public ConcurrentProgressMonitorInputStream(Component parentComponent,
+ Object message, InputStream in) {
+ super(in);
+ try {
+ size = in.available();
+ } catch (IOException ioe) {
+ size = 0;
+ }
+ monitor = new ConcurrentProgressMonitor(parentComponent, message, null, 0,
+ size + 1);
+ }
+
+
+ /**
+ * Get the ProgressMonitor object being used by this stream. Normally
+ * this isn't needed unless you want to do something like change the
+ * descriptive text partway through reading the file.
+ * @return the ProgressMonitor object used by this object
+ */
+ public ConcurrentProgressMonitor getProgressMonitor() {
+ return monitor;
+ }
+
+
+ /**
+ * Overrides <code>FilterInputStream.read</code>
+ * to update the progress monitor after the read.
+ */
+ @Override
+ public int read() throws IOException {
+ int c = in.read();
+ if (c >= 0)
+ monitor.setProgress(++nread);
+ if (monitor.isCanceled()) {
+ InterruptedIOException exc = new InterruptedIOException("progress");
+ exc.bytesTransferred = nread;
+ throw exc;
+ }
+ return c;
+ }
+
+
+ /**
+ * Overrides <code>FilterInputStream.read</code>
+ * to update the progress monitor after the read.
+ */
+ @Override
+ public int read(byte b[]) throws IOException {
+ int nr = in.read(b);
+ if (nr > 0)
+ monitor.setProgress(nread += nr);
+ if (monitor.isCanceled()) {
+ InterruptedIOException exc = new InterruptedIOException("progress");
+ exc.bytesTransferred = nread;
+ throw exc;
+ }
+ return nr;
+ }
+
+
+ /**
+ * Overrides <code>FilterInputStream.read</code>
+ * to update the progress monitor after the read.
+ */
+ @Override
+ public int read(byte b[], int off, int len) throws IOException {
+ int nr = in.read(b, off, len);
+ if (nr > 0)
+ monitor.setProgress(nread += nr);
+ if (monitor.isCanceled()) {
+ InterruptedIOException exc = new InterruptedIOException("progress");
+ exc.bytesTransferred = nread;
+ throw exc;
+ }
+ return nr;
+ }
+
+
+ /**
+ * Overrides <code>FilterInputStream.skip</code>
+ * to update the progress monitor after the skip.
+ */
+ @Override
+ public long skip(long n) throws IOException {
+ long nr = in.skip(n);
+ if (nr > 0)
+ monitor.setProgress(nread += nr);
+ return nr;
+ }
+
+
+ /**
+ * Overrides <code>FilterInputStream.close</code>
+ * to close the progress monitor as well as the stream.
+ */
+ @Override
+ public void close() throws IOException {
+ in.close();
+ }
+
+
+ /**
+ * Overrides <code>FilterInputStream.reset</code>
+ * to reset the progress monitor as well as the stream.
+ */
+ @Override
+ public synchronized void reset() throws IOException {
+ in.reset();
+ nread = size - in.available();
+ monitor.setProgress(nread);
+ }
+}
import net.sf.openrocket.rocketcomponent.Bulkhead;
import net.sf.openrocket.rocketcomponent.CenteringRing;
import net.sf.openrocket.rocketcomponent.FreeformFinSet;
+import net.sf.openrocket.rocketcomponent.IllegalFinPointException;
import net.sf.openrocket.rocketcomponent.InnerTube;
import net.sf.openrocket.rocketcomponent.LaunchLug;
import net.sf.openrocket.rocketcomponent.MassComponent;
bodytube = new BodyTube(0.69,0.033,0.001);
finset = new FreeformFinSet();
- finset.setPoints(new Coordinate[] {
- new Coordinate(0, 0),
- new Coordinate(0.115, 0.072),
- new Coordinate(0.255, 0.072),
- new Coordinate(0.255, 0.037),
- new Coordinate(0.150, 0)
- });
+ try {
+ finset.setPoints(new Coordinate[] {
+ new Coordinate(0, 0),
+ new Coordinate(0.115, 0.072),
+ new Coordinate(0.255, 0.072),
+ new Coordinate(0.255, 0.037),
+ new Coordinate(0.150, 0)
+ });
+ } catch (IllegalFinPointException e) {
+ e.printStackTrace();
+ }
finset.setThickness(0.003);
finset.setFinCount(4);