Motor chooser search field and new edit motor config dialog
This commit is contained in:
parent
a65e061445
commit
6e14883374
13
ChangeLog
13
ChangeLog
@ -1,3 +1,16 @@
|
||||
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
|
||||
|
||||
@ -1,4 +1,11 @@
|
||||
|
||||
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):
|
||||
-------------------------------
|
||||
|
||||
|
||||
131
TODO
131
TODO
@ -1,126 +1,35 @@
|
||||
|
||||
GUI:
|
||||
|
||||
- Preferences dialog
|
||||
Feature roadmap for OpenRocket 1.0
|
||||
|
||||
|
||||
BUGS:
|
||||
Must-have:
|
||||
|
||||
- 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:
|
||||
Done:
|
||||
|
||||
- Automatic diameters of body components
|
||||
- Copy/paste
|
||||
- Search field in motor selection dialog
|
||||
- Motor selection/editing from Edit configurations dialog
|
||||
- Change FreeformFinSet to throw checked exceptions
|
||||
|
||||
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
|
||||
|
||||
18.5.:
|
||||
- About dialog + version number
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
|
||||
# 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!
|
||||
|
||||
@ -45,6 +45,7 @@ public class OpenRocketDocument implements ComponentChangeListener {
|
||||
private LinkedList<String> undoDescription = new LinkedList<String>();
|
||||
|
||||
private String nextDescription = null;
|
||||
private String storedDescription = null;
|
||||
|
||||
|
||||
private File file = null;
|
||||
@ -70,9 +71,7 @@ public class OpenRocketDocument implements ComponentChangeListener {
|
||||
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);
|
||||
@ -234,6 +233,31 @@ public class OpenRocketDocument implements ComponentChangeListener {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
@ -244,6 +268,24 @@ public class OpenRocketDocument implements ComponentChangeListener {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@ import net.sf.openrocket.rocketcomponent.EngineBlock;
|
||||
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;
|
||||
@ -137,6 +138,8 @@ public class OpenRocketLoader extends RocketLoader {
|
||||
doc.getDefaultStorageOptions().setSimulationTimeSkip(timeSkip);
|
||||
doc.getDefaultStorageOptions().setCompressionEnabled(false); // Set by caller if compressed
|
||||
doc.getDefaultStorageOptions().setExplicitlySet(false);
|
||||
|
||||
doc.clearUndo();
|
||||
return doc;
|
||||
}
|
||||
|
||||
@ -977,7 +980,7 @@ class FinSetPointHandler extends ElementHandler {
|
||||
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."));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package net.sf.openrocket.file;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@ -7,6 +8,8 @@ import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.swing.ProgressMonitorInputStream;
|
||||
|
||||
import net.sf.openrocket.aerodynamics.WarningSet;
|
||||
import net.sf.openrocket.document.OpenRocketDocument;
|
||||
|
||||
@ -14,6 +17,19 @@ 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.
|
||||
|
||||
@ -1,44 +1,22 @@
|
||||
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 {
|
||||
|
||||
@ -91,13 +69,8 @@ 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);
|
||||
}
|
||||
});
|
||||
|
||||
@ -185,198 +158,5 @@ public class MotorConfigurationModel implements ComboBoxModel, ChangeListener {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ import net.sf.openrocket.gui.scalefigure.ScaleSelector;
|
||||
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;
|
||||
@ -275,7 +276,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
finset.addPoint(index);
|
||||
try {
|
||||
finset.setPoint(index, point.x, point.y);
|
||||
} catch (IllegalArgumentException ignore) { }
|
||||
} catch (IllegalFinPointException ignore) { }
|
||||
dragIndex = index;
|
||||
|
||||
return;
|
||||
@ -299,7 +300,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
|
||||
try {
|
||||
finset.setPoint(dragIndex, point.x, point.y);
|
||||
} catch (IllegalArgumentException ignore) {
|
||||
} catch (IllegalFinPointException ignore) {
|
||||
System.out.println("IAE:"+ignore);
|
||||
}
|
||||
}
|
||||
@ -328,7 +329,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
|
||||
try {
|
||||
finset.removePoint(index);
|
||||
} catch (IllegalArgumentException ignore) {
|
||||
} catch (IllegalFinPointException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
@ -462,6 +463,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
|
||||
finset.setPoint(rowIndex, c.x, c.y);
|
||||
|
||||
} catch (NumberFormatException ignore) {
|
||||
} catch (IllegalFinPointException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -50,12 +50,12 @@ public class InnerTubeConfig extends ThicknessRingComponentConfig {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package net.sf.openrocket.gui;
|
||||
package net.sf.openrocket.gui.dialogs;
|
||||
|
||||
import static net.sf.openrocket.unit.Unit.NOUNIT2;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package net.sf.openrocket.gui;
|
||||
package net.sf.openrocket.gui.dialogs;
|
||||
|
||||
import java.awt.Component;
|
||||
|
||||
@ -0,0 +1,479 @@
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package net.sf.openrocket.gui.main;
|
||||
package net.sf.openrocket.gui.dialogs;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.event.ActionEvent;
|
||||
@ -1,4 +1,4 @@
|
||||
package net.sf.openrocket.gui;
|
||||
package net.sf.openrocket.gui.dialogs;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
118
src/net/sf/openrocket/gui/dialogs/SwingWorkerDialog.java
Normal file
118
src/net/sf/openrocket/gui/dialogs/SwingWorkerDialog.java
Normal file
@ -0,0 +1,118 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package net.sf.openrocket.gui.main;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Toolkit;
|
||||
@ -14,6 +15,7 @@ import java.awt.event.MouseListener;
|
||||
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;
|
||||
@ -38,6 +40,7 @@ import javax.swing.ListSelectionModel;
|
||||
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;
|
||||
@ -56,17 +59,20 @@ import net.sf.openrocket.file.OpenRocketSaver;
|
||||
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;
|
||||
|
||||
@ -588,7 +594,7 @@ public class BasicFrame extends JFrame {
|
||||
|
||||
for (File file: files) {
|
||||
System.out.println("Opening file: " + file);
|
||||
if (open(file)) {
|
||||
if (open(file, this)) {
|
||||
opened = true;
|
||||
}
|
||||
}
|
||||
@ -604,13 +610,16 @@ public class BasicFrame extends JFrame {
|
||||
* 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);
|
||||
@ -643,6 +652,33 @@ public class BasicFrame extends JFrame {
|
||||
|
||||
|
||||
|
||||
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) {
|
||||
@ -804,6 +840,35 @@ public class BasicFrame extends JFrame {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -861,7 +926,7 @@ public class BasicFrame extends JFrame {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import java.awt.event.ActionListener;
|
||||
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;
|
||||
@ -22,8 +23,11 @@ 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.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;
|
||||
@ -49,7 +53,9 @@ public class MotorChooserDialog extends JDialog {
|
||||
"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;
|
||||
|
||||
@ -81,16 +87,16 @@ public class MotorChooserDialog extends JDialog {
|
||||
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
|
||||
@ -104,17 +110,14 @@ public class MotorChooserDialog extends JDialog {
|
||||
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;
|
||||
|
||||
@ -125,9 +128,46 @@ public class MotorChooserDialog extends JDialog {
|
||||
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) {
|
||||
@ -186,11 +226,11 @@ public class MotorChooserDialog extends JDialog {
|
||||
|
||||
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);
|
||||
@ -222,7 +262,7 @@ public class MotorChooserDialog extends JDialog {
|
||||
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() {
|
||||
@ -248,6 +288,9 @@ public class MotorChooserDialog extends JDialog {
|
||||
|
||||
// Table can be scrolled only after pack() has been called
|
||||
setSelectionVisible();
|
||||
|
||||
// Focus the search field
|
||||
searchField.grabFocus();
|
||||
}
|
||||
|
||||
private void setSelectionVisible() {
|
||||
@ -567,14 +610,26 @@ public class MotorChooserDialog extends JDialog {
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -582,7 +637,7 @@ public class MotorChooserDialog extends JDialog {
|
||||
*/
|
||||
private class MotorRowFilterAll extends MotorRowFilter {
|
||||
@Override
|
||||
public boolean include(Motor m) {
|
||||
public boolean filterByDiameter(Motor m) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -592,7 +647,7 @@ public class MotorChooserDialog extends JDialog {
|
||||
*/
|
||||
private class MotorRowFilterSmaller extends MotorRowFilter {
|
||||
@Override
|
||||
public boolean include(Motor m) {
|
||||
public boolean filterByDiameter(Motor m) {
|
||||
return (m.getDiameter() <= diameter + 0.0004);
|
||||
}
|
||||
}
|
||||
@ -602,7 +657,7 @@ public class MotorChooserDialog extends JDialog {
|
||||
*/
|
||||
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));
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ import javax.swing.JProgressBar;
|
||||
|
||||
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;
|
||||
|
||||
@ -56,9 +56,11 @@ public class ClusterConfiguration {
|
||||
};
|
||||
|
||||
|
||||
|
||||
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) {
|
||||
@ -100,4 +102,10 @@ public class ClusterConfiguration {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return xmlName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,10 +59,11 @@ public class FreeformFinSet extends FinSet {
|
||||
* 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);
|
||||
@ -73,19 +74,19 @@ public class FreeformFinSet extends FinSet {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,8 +113,10 @@ public class FreeformFinSet extends FinSet {
|
||||
* @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;
|
||||
|
||||
@ -160,12 +163,12 @@ public class FreeformFinSet extends FinSet {
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -7,7 +7,6 @@ import java.util.HashMap;
|
||||
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;
|
||||
@ -72,8 +71,8 @@ public class Rocket extends RocketComponent {
|
||||
|
||||
|
||||
// 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);
|
||||
}
|
||||
@ -267,22 +266,25 @@ public class Rocket extends RocketComponent {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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>.
|
||||
@ -293,6 +295,7 @@ public class Rocket extends RocketComponent {
|
||||
* and therefore fires an UNDO_EVENT, masked with all applicable mass/aerodynamic/tree
|
||||
* changes.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void loadFrom(Rocket r) {
|
||||
super.copyFrom(r);
|
||||
|
||||
@ -312,10 +315,15 @@ public class Rocket extends RocketComponent {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -594,7 +602,7 @@ public class Rocket extends RocketComponent {
|
||||
*/
|
||||
public void setMotorConfigurationName(String id, String name) {
|
||||
motorConfigurationNames.put(id,name);
|
||||
fireComponentChangeEvent(ComponentChangeEvent.MOTOR_CHANGE);
|
||||
fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
45
src/net/sf/openrocket/util/ConcurrentProgressMonitor.java
Normal file
45
src/net/sf/openrocket/util/ConcurrentProgressMonitor.java
Normal file
@ -0,0 +1,45 @@
|
||||
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);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@ import net.sf.openrocket.rocketcomponent.BodyTube;
|
||||
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;
|
||||
@ -144,13 +145,17 @@ public class Test {
|
||||
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);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user