diff --git a/core/src/net/sf/openrocket/simulation/FlightDataType.java b/core/src/net/sf/openrocket/simulation/FlightDataType.java
index 950b0c728..083cf8cbf 100644
--- a/core/src/net/sf/openrocket/simulation/FlightDataType.java
+++ b/core/src/net/sf/openrocket/simulation/FlightDataType.java
@@ -15,7 +15,7 @@ import net.sf.openrocket.util.StringUtils;
/**
* A class defining a storable simulation variable type. This class defined numerous ready
* types, and allows also creating new types with any name. When retrieving types based on
- * a name, you should use {@link #getType(String, UnitGroup)} to return the default unit type,
+ * a name, you should use {@link #getType(String, String, UnitGroup)} to return the default unit type,
* or a new type if the name does not currently exist.
*
* Each type has a type name (description), a unit group and a priority. The type is identified
@@ -42,37 +42,50 @@ public class FlightDataType implements Comparable {
//// Vertical position and motion
//// Altitude
- public static final FlightDataType TYPE_ALTITUDE = newType(trans.get("FlightDataType.TYPE_ALTITUDE"), "h", UnitGroup.UNITS_DISTANCE, 10);
+ public static final FlightDataType TYPE_ALTITUDE = newType(trans.get("FlightDataType.TYPE_ALTITUDE"), "h", UnitGroup.UNITS_DISTANCE,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 0);
//// Vertical velocity
- public static final FlightDataType TYPE_VELOCITY_Z = newType(trans.get("FlightDataType.TYPE_VELOCITY_Z"), "Vz", UnitGroup.UNITS_VELOCITY, 11);
+ public static final FlightDataType TYPE_VELOCITY_Z = newType(trans.get("FlightDataType.TYPE_VELOCITY_Z"), "Vz", UnitGroup.UNITS_VELOCITY,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 1);
//// Vertical acceleration
- public static final FlightDataType TYPE_ACCELERATION_Z = newType(trans.get("FlightDataType.TYPE_ACCELERATION_Z"), "Az", UnitGroup.UNITS_ACCELERATION, 12);
+ public static final FlightDataType TYPE_ACCELERATION_Z = newType(trans.get("FlightDataType.TYPE_ACCELERATION_Z"), "Az", UnitGroup.UNITS_ACCELERATION,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 2);
//// Total motion
//// Total velocity
- public static final FlightDataType TYPE_VELOCITY_TOTAL = newType(trans.get("FlightDataType.TYPE_VELOCITY_TOTAL"), "Vt", UnitGroup.UNITS_VELOCITY, 20);
+ public static final FlightDataType TYPE_VELOCITY_TOTAL = newType(trans.get("FlightDataType.TYPE_VELOCITY_TOTAL"), "Vt", UnitGroup.UNITS_VELOCITY,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 3);
//// Total acceleration
- public static final FlightDataType TYPE_ACCELERATION_TOTAL = newType(trans.get("FlightDataType.TYPE_ACCELERATION_TOTAL"), "At", UnitGroup.UNITS_ACCELERATION, 21);
+ public static final FlightDataType TYPE_ACCELERATION_TOTAL = newType(trans.get("FlightDataType.TYPE_ACCELERATION_TOTAL"), "At", UnitGroup.UNITS_ACCELERATION,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 4);
//// Lateral position and motion
//// Position East of launch
- public static final FlightDataType TYPE_POSITION_X = newType(trans.get("FlightDataType.TYPE_POSITION_X"), "Px", UnitGroup.UNITS_DISTANCE, 30);
+ public static final FlightDataType TYPE_POSITION_X = newType(trans.get("FlightDataType.TYPE_POSITION_X"), "Px", UnitGroup.UNITS_DISTANCE,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 5);
//// Position North of launch
- public static final FlightDataType TYPE_POSITION_Y = newType(trans.get("FlightDataType.TYPE_POSITION_Y"), "Py", UnitGroup.UNITS_DISTANCE, 31);
+ public static final FlightDataType TYPE_POSITION_Y = newType(trans.get("FlightDataType.TYPE_POSITION_Y"), "Py", UnitGroup.UNITS_DISTANCE,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 6);
//// Lateral distance
- public static final FlightDataType TYPE_POSITION_XY = newType(trans.get("FlightDataType.TYPE_POSITION_XY"), "Pl", UnitGroup.UNITS_DISTANCE, 32);
+ public static final FlightDataType TYPE_POSITION_XY = newType(trans.get("FlightDataType.TYPE_POSITION_XY"), "Pl", UnitGroup.UNITS_DISTANCE,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 7);
//// Lateral direction
- public static final FlightDataType TYPE_POSITION_DIRECTION = newType(trans.get("FlightDataType.TYPE_POSITION_DIRECTION"), "\u03b8l", UnitGroup.UNITS_ANGLE, 33);
+ public static final FlightDataType TYPE_POSITION_DIRECTION = newType(trans.get("FlightDataType.TYPE_POSITION_DIRECTION"), "\u03b8l", UnitGroup.UNITS_ANGLE,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 8);
//// Lateral velocity
- public static final FlightDataType TYPE_VELOCITY_XY = newType(trans.get("FlightDataType.TYPE_VELOCITY_XY"), "Vl", UnitGroup.UNITS_VELOCITY, 34);
+ public static final FlightDataType TYPE_VELOCITY_XY = newType(trans.get("FlightDataType.TYPE_VELOCITY_XY"), "Vl", UnitGroup.UNITS_VELOCITY,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 9);
//// Lateral acceleration
- public static final FlightDataType TYPE_ACCELERATION_XY = newType(trans.get("FlightDataType.TYPE_ACCELERATION_XY"), "Al", UnitGroup.UNITS_ACCELERATION, 35);
+ public static final FlightDataType TYPE_ACCELERATION_XY = newType(trans.get("FlightDataType.TYPE_ACCELERATION_XY"), "Al", UnitGroup.UNITS_ACCELERATION,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 10);
//// Latitude
- public static final FlightDataType TYPE_LATITUDE = newType(trans.get("FlightDataType.TYPE_LATITUDE"), "\u03c6", UnitGroup.UNITS_ANGLE, 36);
+ public static final FlightDataType TYPE_LATITUDE = newType(trans.get("FlightDataType.TYPE_LATITUDE"), "\u03c6", UnitGroup.UNITS_ANGLE,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 11);
//// Longitude
- public static final FlightDataType TYPE_LONGITUDE = newType(trans.get("FlightDataType.TYPE_LONGITUDE"), "\u03bb", UnitGroup.UNITS_ANGLE, 37);
+ public static final FlightDataType TYPE_LONGITUDE = newType(trans.get("FlightDataType.TYPE_LONGITUDE"), "\u03bb", UnitGroup.UNITS_ANGLE,
+ FlightDataTypeGroup.POSITION_AND_MOTION, 12);
//// Gravity
public static final FlightDataType TYPE_GRAVITY = newType(trans.get("FlightDataType.TYPE_GRAVITY"), "g", UnitGroup.UNITS_ACCELERATION, 38);
@@ -283,7 +296,7 @@ public class FlightDataType implements Comparable {
// otherwise, just return what we found
if ( !u.equals(type.getUnitGroup()) )
{
- oldPriority = type.priority;
+ oldPriority = type.groupPriority;
EXISTING_TYPES.remove(type);
log.info("Unitgroup of type "+type.getName() +
", has changed from "+type.getUnitGroup().toString() +
@@ -291,7 +304,7 @@ public class FlightDataType implements Comparable {
". Removing old version.");
}
else if (!s.equals(type.getName())) {
- oldPriority = type.priority;
+ oldPriority = type.groupPriority;
EXISTING_TYPES.remove(type);
log.info("Name of type "+type.getName()+", has changed to "+s+". Removing old version.");
}
@@ -326,9 +339,20 @@ public class FlightDataType implements Comparable {
/**
* Used while initializing the class.
+ * @param s the name of the type.
+ * @param symbol the mathematical symbol of the type.
+ * @param u the unit group of the type.
+ * @param group the group of the type.
+ * @param priority the priority of the type within the group.
*/
+ private static synchronized FlightDataType newType(String s, String symbol, UnitGroup u, FlightDataTypeGroup group, int priority) {
+ FlightDataType type = new FlightDataType(s, symbol, u, group, priority);
+ //EXISTING_TYPES.put(s.toLowerCase(Locale.ENGLISH), type);
+ EXISTING_TYPES.put(symbol, type);
+ return type;
+ }
private static synchronized FlightDataType newType(String s, String symbol, UnitGroup u, int priority) {
- FlightDataType type = new FlightDataType(s, symbol, u, priority);
+ FlightDataType type = new FlightDataType(s, symbol, u, FlightDataTypeGroup.CUSTOM, priority);
//EXISTING_TYPES.put(s.toLowerCase(Locale.ENGLISH), type);
EXISTING_TYPES.put(symbol, type);
return type;
@@ -338,11 +362,12 @@ public class FlightDataType implements Comparable {
private final String name;
private final String symbol;
private final UnitGroup units;
- private final int priority;
+ private final FlightDataTypeGroup group;
+ private final int groupPriority;
private final int hashCode;
- private FlightDataType(String typeName, String symbol, UnitGroup units, int priority) {
+ private FlightDataType(String typeName, String symbol, UnitGroup units, FlightDataTypeGroup group, int priority) {
if (typeName == null)
throw new IllegalArgumentException("typeName is null");
if (units == null)
@@ -350,16 +375,11 @@ public class FlightDataType implements Comparable {
this.name = typeName;
this.symbol = symbol;
this.units = units;
- this.priority = priority;
+ this.group = group;
+ this.groupPriority = priority;
this.hashCode = this.name.toLowerCase(Locale.ENGLISH).hashCode();
}
- /*
- public void setPriority(int p){
- this.priority = p;
- }
- */
-
public String getName() {
return name;
}
@@ -371,6 +391,14 @@ public class FlightDataType implements Comparable {
public UnitGroup getUnitGroup() {
return units;
}
+
+ public FlightDataTypeGroup getGroup() {
+ return group;
+ }
+
+ public int getGroupPriority() {
+ return groupPriority;
+ }
@Override
public String toString() {
@@ -391,8 +419,8 @@ public class FlightDataType implements Comparable {
@Override
public int compareTo(FlightDataType o) {
- if (this.priority != o.priority)
- return this.priority - o.priority;
+ if (this.groupPriority != o.groupPriority)
+ return this.groupPriority - o.groupPriority;
return this.name.compareToIgnoreCase(o.name);
}
}
diff --git a/core/src/net/sf/openrocket/simulation/FlightDataTypeGroup.java b/core/src/net/sf/openrocket/simulation/FlightDataTypeGroup.java
new file mode 100644
index 000000000..296374031
--- /dev/null
+++ b/core/src/net/sf/openrocket/simulation/FlightDataTypeGroup.java
@@ -0,0 +1,39 @@
+package net.sf.openrocket.simulation;
+
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.startup.Application;
+
+public class FlightDataTypeGroup {
+ private static final Translator trans = Application.getTranslator();
+
+ public static final FlightDataTypeGroup POSITION_AND_MOTION = new FlightDataTypeGroup("Position and motion", 0);
+
+ public static final FlightDataTypeGroup CUSTOM = new FlightDataTypeGroup("Custom", 100);
+
+ // An array of all the built-in groups
+ public static final FlightDataTypeGroup[] ALL_GROUPS = {
+ POSITION_AND_MOTION,
+ CUSTOM
+ };
+
+ private final String name;
+ private final int priority;
+
+ private FlightDataTypeGroup(String groupName, int priority) {
+ this.name = groupName;
+ this.priority = priority;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getPriority() {
+ return priority;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/swing/src/net/sf/openrocket/gui/simulation/FlightDataComboBox.java b/swing/src/net/sf/openrocket/gui/simulation/FlightDataComboBox.java
new file mode 100644
index 000000000..80931952e
--- /dev/null
+++ b/swing/src/net/sf/openrocket/gui/simulation/FlightDataComboBox.java
@@ -0,0 +1,105 @@
+package net.sf.openrocket.gui.simulation;
+
+import net.sf.openrocket.simulation.FlightDataType;
+import net.sf.openrocket.simulation.FlightDataTypeGroup;
+
+import javax.swing.JComboBox;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.plaf.basic.BasicArrowButton;
+import java.awt.Component;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+public class FlightDataComboBox extends JComboBox {
+ private final JPopupMenu mainMenu;
+ private final Hashtable subItems = new Hashtable<>();
+
+ public FlightDataComboBox(FlightDataType[] types) {
+ super(types);
+ setEditable(false);
+
+ for (FlightDataTypeGroup group : FlightDataTypeGroup.ALL_GROUPS) {
+ ArrayList listForGroup = new ArrayList<>();
+ for (FlightDataType type : types) {
+ if (type.getGroup().equals(group)) {
+ listForGroup.add(type);
+ }
+ }
+ subItems.put(group, listForGroup.toArray(new FlightDataType[0]));
+ }
+
+ mainMenu = createMainMenu();
+
+ // Override the mouse listeners to use our custom popup
+ for (MouseListener mouseListener : getMouseListeners()) {
+ removeMouseListener(mouseListener);
+ }
+
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ showCustomPopup();
+ }
+ });
+
+ Component arrowButton = getArrowButton();
+ if (arrowButton != null) {
+ for (MouseListener mouseListener : arrowButton.getMouseListeners()) {
+ arrowButton.removeMouseListener(mouseListener);
+ }
+ arrowButton.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ showCustomPopup();
+ }
+ });
+ }
+ }
+
+ private Component getArrowButton() {
+ for (Component child : getComponents()) {
+ if (child instanceof BasicArrowButton) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void showPopup() {
+ // Override the default JComboBox showPopup() to do nothing
+ // Our custom popup will be shown by the MouseListener
+ }
+
+ private JPopupMenu createMainMenu() {
+ JPopupMenu menu = new JPopupMenu();
+
+ for (FlightDataTypeGroup group : FlightDataTypeGroup.ALL_GROUPS) {
+ JMenu groupMenu = new JMenu(group.getName());
+ FlightDataType[] typesForGroup = subItems.get(group);
+
+ if (typesForGroup != null) {
+ for (FlightDataType type : typesForGroup) {
+ JMenuItem typeItem = new JMenuItem(type.getName());
+ typeItem.addActionListener(e -> {
+ setSelectedItem(type);
+ });
+ groupMenu.add(typeItem);
+ }
+ }
+
+ menu.add(groupMenu);
+ }
+
+ return menu;
+ }
+
+ private void showCustomPopup() {
+ mainMenu.show(this, 0, getHeight());
+ }
+}
diff --git a/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java b/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java
index 11fcbeb32..37e6620bb 100644
--- a/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java
+++ b/swing/src/net/sf/openrocket/gui/simulation/SimulationPlotPanel.java
@@ -497,7 +497,7 @@ public class SimulationPlotPanel extends JPanel {
this.index = plotIndex;
- typeSelector = new JComboBox(types);
+ typeSelector = new FlightDataComboBox(types);
typeSelector.setSelectedItem(type);
typeSelector.addItemListener(new ItemListener() {
@Override