diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties
index 9a7f539f4..a10a1c412 100644
--- a/core/resources/l10n/messages.properties
+++ b/core/resources/l10n/messages.properties
@@ -289,6 +289,8 @@ pref.dlg.lbl.PositiontoinsertStages = Position to insert new stages:
pref.dlg.lbl.Confirmdeletion = Confirm deletion of simulations.
pref.dlg.checkbox.Runsimulations = Run out-dated simulations when you open the simulation tab.
pref.dlg.checkbox.Updateestimates = Update estimated flight parameters in design window
+pref.dlg.checkbox.AlwaysOpenLeftmost = Always open leftmost tab when opening a component edit dialog
+pref.dlg.checkbox.AlwaysOpenLeftmost.ttip = If checked, a component edit dialog will always pop up with the first tab selected.
If unchecked, the previous selected tab will be used.
pref.dlg.lbl.User-definedthrust = User-defined thrust curves:
pref.dlg.lbl.Windspeed = Wind speed
pref.dlg.Allthrustcurvefiles = All thrust curve files (*.eng; *.rse; *.zip; directories)
diff --git a/core/resources/l10n/messages_ru.properties b/core/resources/l10n/messages_ru.properties
index 6f8657f59..cc5d08328 100644
--- a/core/resources/l10n/messages_ru.properties
+++ b/core/resources/l10n/messages_ru.properties
@@ -291,6 +291,8 @@ pref.dlg.lbl.PositiontoinsertStages = \u041C\u0435\u0441\u0442\u043E \u0434\u043
pref.dlg.lbl.Confirmdeletion = \u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u0443\u0434\u0430\u043B\u0435\u043D\u0438\u044F \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
pref.dlg.checkbox.Runsimulations = \u041E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u044B \u043F\u0440\u0438 \u043E\u0442\u043A\u0440\u044B\u0442\u0438\u0438 \u0432\u043A\u043B\u0430\u0434\u043A\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u043E\u0432.
pref.dlg.checkbox.Updateestimates = \u041E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u043F\u0440\u0435\u0434\u043F\u043E\u043B\u0430\u0433\u0430\u0435\u043C\u044B\u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u043F\u043E\u043B\u0435\u0442\u0430 \u0432 \u043E\u043A\u043D\u0435 \u043F\u0440\u043E\u0435\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F
+pref.dlg.checkbox.AlwaysOpenLeftmost = \u0412\u0441\u0435\u0433\u0434\u0430 \u0432\u044B\u0431\u0438\u0440\u0430\u0442\u044C \u043F\u0435\u0440\u0432\u0443\u044E \u0432\u043A\u043B\u0430\u0434\u043A\u0443 \u043F\u0440\u0438 \u043E\u0442\u043A\u0440\u044B\u0442\u0438\u0438 \u043E\u043A\u043D\u0430 \u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430
+pref.dlg.checkbox.AlwaysOpenLeftmost.ttip = \u0415\u0441\u043B\u0438 \u044D\u0442\u043E\u0442 \u0444\u043B\u0430\u0436\u043E\u043A \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D, \u0434\u0438\u0430\u043B\u043E\u0433\u043E\u0432\u043E\u0435 \u043E\u043A\u043D\u043E \u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430 \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u043E\u0442\u043A\u0440\u044B\u0432\u0430\u0442\u044C\u0441\u044F \u0441 \u043F\u0435\u0440\u0432\u043E\u0439 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u043E\u0439 \u0432\u043A\u043B\u0430\u0434\u043A\u043E\u0439.
\u0415\u0441\u043B\u0438 \u044D\u0442\u043E\u0442 \u0444\u043B\u0430\u0436\u043E\u043A \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D, \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C\u0441\u044F \u043F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0430\u044F \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u0430\u044F \u0432\u043A\u043B\u0430\u0434\u043A\u0430.
pref.dlg.lbl.User-definedthrust = \u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u0441\u043A\u0438\u0435 \u043F\u0440\u043E\u0444\u0438\u043B\u0438 \u0442\u044F\u0433\u0438:
pref.dlg.lbl.Windspeed = \u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C \u0432\u0435\u0442\u0440\u0430
pref.dlg.Allthrustcurvefiles = \u0424\u0430\u0439\u043B\u044B \u043F\u0440\u043E\u0444\u0438\u043B\u0435\u0439 \u0442\u044F\u0433\u0438 (*.eng; *.rse; *.zip; \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0438)
@@ -1790,6 +1792,7 @@ Warning.PARALLEL_FINS = \u0421\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u043D\
Warning.SUPERSONIC = \u0420\u0430\u0441\u0447\u0435\u0442\u044B \u043A\u043E\u0440\u043F\u0443\u0441\u0430 \u043F\u0440\u0438 \u0441\u0432\u0435\u0440\u0445\u0437\u0432\u0443\u043A\u043E\u0432\u044B\u0445 \u0441\u043A\u043E\u0440\u043E\u0441\u0442\u044F\u0445 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u043D\u0435\u043C\u043D\u043E\u0433\u043E \u043D\u0435\u0442\u043E\u0447\u043D\u044B.
Warning.RECOVERY_LAUNCH_ROD = \u0421\u0440\u0430\u0431\u0430\u0442\u044B\u0432\u0430\u043D\u0438\u0435 \u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u0430 \u0441\u043F\u0430\u0441\u0435\u043D\u0438\u044F \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u043E\u0439 \u043F\u043B\u043E\u0449\u0430\u0434\u043A\u0435.
Warning.RECOVERY_HIGH_SPEED = \u0421\u0440\u0430\u0431\u0430\u0442\u044B\u0432\u0430\u043D\u0438\u0435 \u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u0430 \u0441\u043F\u0430\u0441\u0435\u043D\u0438\u044F \u043D\u0430 \u0432\u044B\u0441\u043E\u043A\u043E\u0439 \u0441\u043A\u043E\u0440\u043E\u0441\u0442\u0438
+Warning.NO_RECOVERY_DEVICE = \u0412 \u0440\u0430\u0441\u0447\u0435\u0442\u0435 \u043D\u0435\u0442 \u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432 \u0441\u043F\u0430\u0441\u0435\u043D\u0438\u044F
Warning.TUMBLE_UNDER_THRUST = \u0421\u0442\u0443\u043F\u0435\u043D\u044C \u043D\u0430\u0447\u0430\u043B\u0430 \u043A\u0443\u0432\u044B\u0440\u044C\u043A\u0430\u0442\u044C\u0441\u044F \u043F\u043E\u0434 \u0442\u044F\u0433\u043E\u0439.
Warning.EVENT_AFTER_LANDING = \u041B\u0435\u0442\u043D\u043E\u0435 \u0441\u043E\u0431\u044B\u0442\u0438\u0435 \u0432\u043E\u0437\u043D\u0438\u043A\u043B\u043E \u043F\u043E\u0441\u043B\u0435 \u043F\u0440\u0438\u0437\u0435\u043C\u043B\u0435\u043D\u0438\u044F:
Warning.ZERO_LENGTH_BODY = \u0422\u0435\u043B\u0430 \u043D\u0443\u043B\u0435\u0432\u043E\u0439 \u0434\u043B\u0438\u043D\u044B \u043C\u043E\u0433\u0443\u0442 \u043F\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043A \u043D\u0435\u0442\u043E\u0447\u043D\u043E\u0441\u0442\u044F\u043C \u0432 \u0440\u0430\u0441\u0447\u0435\u0442\u0435.
diff --git a/core/src/net/sf/openrocket/startup/Preferences.java b/core/src/net/sf/openrocket/startup/Preferences.java
index dd30d8e60..64f1de5a0 100644
--- a/core/src/net/sf/openrocket/startup/Preferences.java
+++ b/core/src/net/sf/openrocket/startup/Preferences.java
@@ -67,6 +67,7 @@ public abstract class Preferences implements ChangeSource {
// Node names
public static final String PREFERRED_THRUST_CURVE_MOTOR_NODE = "preferredThrustCurveMotors";
private static final String AUTO_OPEN_LAST_DESIGN = "AUTO_OPEN_LAST_DESIGN";
+ private static final String OPEN_LEFTMOST_DESIGN_TAB = "OPEN_LEFTMOST_DESIGN_TAB";
private static final String SHOW_ROCKSIM_FORMAT_WARNING = "SHOW_ROCKSIM_FORMAT_WARNING";
//Preferences related to 3D graphics
@@ -452,6 +453,22 @@ public abstract class Preferences implements ChangeSource {
public final boolean isAutoOpenLastDesignOnStartupEnabled() {
return this.getBoolean(AUTO_OPEN_LAST_DESIGN, false);
}
+
+ /**
+ * Enable/Disable the opening the leftmost tab on the component design panel, or using the tab that was opened last time.
+ */
+ public final void setAlwaysOpenLeftmostTab(boolean enabled) {
+ this.putBoolean(OPEN_LEFTMOST_DESIGN_TAB, enabled);
+ }
+
+ /**
+ * Answer if the always open leftmost tab is enabled.
+ *
+ * @return true if the application should always open the leftmost tab in the component design panel.
+ */
+ public final boolean isAlwaysOpenLeftmostTab() {
+ return this.getBoolean(OPEN_LEFTMOST_DESIGN_TAB, false);
+ }
/**
* Return the OpenRocket unique ID.
diff --git a/core/src/net/sf/openrocket/util/TextUtil.java b/core/src/net/sf/openrocket/util/TextUtil.java
index c39affaba..0f31002ac 100644
--- a/core/src/net/sf/openrocket/util/TextUtil.java
+++ b/core/src/net/sf/openrocket/util/TextUtil.java
@@ -2,10 +2,12 @@ package net.sf.openrocket.util;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
+import java.text.DecimalFormat;
+import java.util.Locale;
public class TextUtil {
-
+ public static final int DEFAULT_DECIMAL_PLACES = 3;
private static final char[] HEX = {
'0', '1', '2', '3', '4', '5', '6', '7',
@@ -43,8 +45,8 @@ public class TextUtil {
/**
* Return a string of the double value with suitable precision for storage.
- * The string is the shortest representation of the value including at least
- * 5 digits of precision.
+ * If exponential notation is used, values smaller than 0.001 or greater than 10000 will be formatted
+ * with exponential notation, otherwise normal formatting is used.
*
* @param d the value to present.
* @param decimalPlaces the number of decimal places to save the value with.
@@ -66,27 +68,15 @@ public class TextUtil {
return "Inf";
}
- final String sign = (d < 0) ? "-" : "";
- double abs = Math.abs(d);
+ String format = "%." + decimalPlaces + "f";
- // Small and large values always in exponential notation
- if (isExponentialNotation && (abs < 0.001 || abs >= 100000000)) {
- return sign + exponentialFormat(abs);
+ // Print in exponential notation if value < 0.001 or >= 10000
+ if (isExponentialNotation && (Math.abs(d) < 0.001 || Math.abs(d) >= 10000)) {
+ format = "%." + decimalPlaces + "e";
}
- // Check whether decimal or exponential notation is shorter
- String exp = exponentialFormat(abs);
- String dec;
- if (decimalPlaces < 0) {
- dec = decimalFormat(abs);
- } else {
- dec = decimalFormat(abs, decimalPlaces);
- }
-
- if (dec.length() <= exp.length() || !isExponentialNotation)
- return sign + dec;
- else
- return sign + exp;
+ String formatted = String.format(Locale.ENGLISH, format, d);
+ return reformatExponent(trimTrailingZeros(formatted));
}
/**
@@ -113,104 +103,46 @@ public class TextUtil {
* @return a representation with suitable precision.
*/
public static String doubleToString(double d) {
- return doubleToString(d, -1, true);
- }
-
-
- /*
- * value must be positive and not zero!
- */
- private static String exponentialFormat(double value) {
- int exp;
-
- exp = 0;
- while (value < 1.0) {
- value *= 10;
- exp--;
- }
- while (value >= 10.0) {
- value /= 10;
- exp++;
- }
-
- return shortDecimal(value, 4) + "e" + exp;
- }
-
-
- /*
- * value must be positive and not zero!
- */
- private static String decimalFormat(double value) {
- if (value >= 10000)
- return "" + (int) (value + 0.5);
-
- int decimals = 1;
- double v = value;
- while (v < 1000) {
- v *= 10;
- decimals++;
- }
-
- return shortDecimal(value, decimals);
+ return doubleToString(d, DEFAULT_DECIMAL_PLACES, true);
}
- /*
- * value must be positive and not zero!
+ /**
+ * Trims trailing zeros of a string formatted decimal number (can be in exponential notation e.g. 1.2000E+06).
+ * @param number the String formatted decimal number.
+ * @return the String formatted decimal number without trailing zeros.
*/
- private static String decimalFormat(double value, int decimals) {
- if (value >= 10000)
- return "" + (int) (value + 0.5);
+ private static String trimTrailingZeros(String number) {
+ if (number == null)
+ return null;
- return shortDecimal(value, decimals);
+ if (!number.contains(".")) {
+ return number;
+ }
+
+ // Deal with exponential notation
+ if (number.contains("e")) {
+ String[] split = number.split("e");
+ number = split[0];
+ String exponent = split[1];
+ return number.replaceAll("\\.?0*$", "") + "e" + exponent;
+ }
+
+ return number.replaceAll("\\.?0*$", "");
}
-
-
-
-
- /*
- * value must be positive!
+
+ /**
+ * Replaces Java's default exponential notation (e.g. e+06 or e-06) with a custom notation (e.g. e6 or e-6).
+ * @param number exponential formatted number (e.g. 3.1415927e+06).
+ * @return the exponential formatted number, with custom exponential notation (e.g. 3.1415927e6).
*/
- private static String shortDecimal(double value, int decimals) {
-
- // Calculate rounding and limit values (rounding slightly smaller)
- int rounding = 1;
- double limit = 0.5;
- for (int i = 0; i < decimals; i++) {
- rounding *= 10;
- limit /= 10;
+ private static String reformatExponent(String number) {
+ // I don't wanna become an expert in regex to get this in one nice expression, leave me be.
+ if (number.contains("e+")) {
+ return number.replaceAll("e\\+?0*", "e");
+ } else if (number.contains("e-")) {
+ return number.replaceAll("e-?0*", "e-");
}
-
- // Round value
- value = (Math.rint(value * rounding) + 0.1) / rounding;
-
-
- int whole = (int) value;
- value -= whole;
-
-
- if (value < limit)
- return "" + whole;
- limit *= 10;
-
- StringBuilder sb = new StringBuilder();
- sb.append("" + whole);
- sb.append('.');
-
-
- for (int i = 0; i < decimals; i++) {
-
- value *= 10;
- whole = (int) value;
- value -= whole;
- sb.append((char) ('0' + whole));
-
- if (value < limit)
- return sb.toString();
- limit *= 10;
-
- }
-
- return sb.toString();
+ return number;
}
/**
diff --git a/core/test/net/sf/openrocket/util/TextUtilTest.java b/core/test/net/sf/openrocket/util/TextUtilTest.java
index d651aeed2..5dd8ea928 100644
--- a/core/test/net/sf/openrocket/util/TextUtilTest.java
+++ b/core/test/net/sf/openrocket/util/TextUtilTest.java
@@ -73,39 +73,39 @@ public class TextUtilTest {
@Test
public void longTest() {
- assertEquals("3.1416e-5", TextUtil.doubleToString(PI * 1e-5));
- assertEquals("3.1416e-4", TextUtil.doubleToString(PI * 1e-4));
- assertEquals("0.0031416", TextUtil.doubleToString(PI * 1e-3));
- assertEquals("0.031416", TextUtil.doubleToString(PI * 1e-2));
- assertEquals("0.31416", TextUtil.doubleToString(PI * 1e-1));
- assertEquals("3.1416", TextUtil.doubleToString(PI));
+ assertEquals("3.142e-5", TextUtil.doubleToString(PI * 1e-5));
+ assertEquals("3.142e-4", TextUtil.doubleToString(PI * 1e-4));
+ assertEquals("0.003", TextUtil.doubleToString(PI * 1e-3));
+ assertEquals("0.031", TextUtil.doubleToString(PI * 1e-2));
+ assertEquals("0.314", TextUtil.doubleToString(PI * 1e-1));
+ assertEquals("3.142", TextUtil.doubleToString(PI));
assertEquals("31.416", TextUtil.doubleToString(PI * 1e1));
- assertEquals("314.16", TextUtil.doubleToString(PI * 1e2));
- assertEquals("3141.6", TextUtil.doubleToString(PI * 1e3));
- assertEquals("31416", TextUtil.doubleToString(PI * 1e4));
- assertEquals("314159", TextUtil.doubleToString(PI * 1e5));
- assertEquals("3141593", TextUtil.doubleToString(PI * 1e6));
- assertEquals("31415927", TextUtil.doubleToString(PI * 1e7));
- assertEquals("3.1416e8", TextUtil.doubleToString(PI * 1e8));
- assertEquals("3.1416e9", TextUtil.doubleToString(PI * 1e9));
- assertEquals("3.1416e10", TextUtil.doubleToString(PI * 1e10));
-
- assertEquals("-3.1416e-5", TextUtil.doubleToString(-PI * 1e-5));
- assertEquals("-3.1416e-4", TextUtil.doubleToString(-PI * 1e-4));
- assertEquals("-0.0031416", TextUtil.doubleToString(-PI * 1e-3));
- assertEquals("-0.031416", TextUtil.doubleToString(-PI * 1e-2));
- assertEquals("-0.31416", TextUtil.doubleToString(-PI * 1e-1));
- assertEquals("-3.1416", TextUtil.doubleToString(-PI));
+ assertEquals("314.159", TextUtil.doubleToString(PI * 1e2));
+ assertEquals("3141.593", TextUtil.doubleToString(PI * 1e3));
+ assertEquals("3.142e4", TextUtil.doubleToString(PI * 1e4));
+ assertEquals("3.142e5", TextUtil.doubleToString(PI * 1e5));
+ assertEquals("3.142e6", TextUtil.doubleToString(PI * 1e6));
+ assertEquals("3.142e7", TextUtil.doubleToString(PI * 1e7));
+ assertEquals("3.142e8", TextUtil.doubleToString(PI * 1e8));
+ assertEquals("3.142e9", TextUtil.doubleToString(PI * 1e9));
+ assertEquals("3.142e10", TextUtil.doubleToString(PI * 1e10));
+
+ assertEquals("-3.142e-5", TextUtil.doubleToString(-PI * 1e-5));
+ assertEquals("-3.142e-4", TextUtil.doubleToString(-PI * 1e-4));
+ assertEquals("-0.003", TextUtil.doubleToString(-PI * 1e-3));
+ assertEquals("-0.031", TextUtil.doubleToString(-PI * 1e-2));
+ assertEquals("-0.314", TextUtil.doubleToString(-PI * 1e-1));
+ assertEquals("-3.142", TextUtil.doubleToString(-PI));
assertEquals("-31.416", TextUtil.doubleToString(-PI * 1e1));
- assertEquals("-314.16", TextUtil.doubleToString(-PI * 1e2));
- assertEquals("-3141.6", TextUtil.doubleToString(-PI * 1e3));
- assertEquals("-31416", TextUtil.doubleToString(-PI * 1e4));
- assertEquals("-314159", TextUtil.doubleToString(-PI * 1e5));
- assertEquals("-3141593", TextUtil.doubleToString(-PI * 1e6));
- assertEquals("-31415927", TextUtil.doubleToString(-PI * 1e7));
- assertEquals("-3.1416e8", TextUtil.doubleToString(-PI * 1e8));
- assertEquals("-3.1416e9", TextUtil.doubleToString(-PI * 1e9));
- assertEquals("-3.1416e10", TextUtil.doubleToString(-PI * 1e10));
+ assertEquals("-314.159", TextUtil.doubleToString(-PI * 1e2));
+ assertEquals("-3141.593", TextUtil.doubleToString(-PI * 1e3));
+ assertEquals("-3.142e4", TextUtil.doubleToString(-PI * 1e4));
+ assertEquals("-3.142e5", TextUtil.doubleToString(-PI * 1e5));
+ assertEquals("-3.142e6", TextUtil.doubleToString(-PI * 1e6));
+ assertEquals("-3.142e7", TextUtil.doubleToString(-PI * 1e7));
+ assertEquals("-3.142e8", TextUtil.doubleToString(-PI * 1e8));
+ assertEquals("-3.142e9", TextUtil.doubleToString(-PI * 1e9));
+ assertEquals("-3.142e10", TextUtil.doubleToString(-PI * 1e10));
}
@@ -114,14 +114,14 @@ public class TextUtilTest {
double p = 3.1;
assertEquals("3.1e-5", TextUtil.doubleToString(p * 1e-5));
assertEquals("3.1e-4", TextUtil.doubleToString(p * 1e-4));
- assertEquals("0.0031", TextUtil.doubleToString(p * 1e-3));
+ assertEquals("0.003", TextUtil.doubleToString(p * 1e-3));
assertEquals("0.031", TextUtil.doubleToString(p * 1e-2));
assertEquals("0.31", TextUtil.doubleToString(p * 1e-1));
assertEquals("3.1", TextUtil.doubleToString(p));
assertEquals("31", TextUtil.doubleToString(p * 1e1));
assertEquals("310", TextUtil.doubleToString(p * 1e2));
assertEquals("3100", TextUtil.doubleToString(p * 1e3));
- assertEquals("31000", TextUtil.doubleToString(p * 1e4));
+ assertEquals("3.1e4", TextUtil.doubleToString(p * 1e4));
assertEquals("3.1e5", TextUtil.doubleToString(p * 1e5));
assertEquals("3.1e6", TextUtil.doubleToString(p * 1e6));
assertEquals("3.1e7", TextUtil.doubleToString(p * 1e7));
@@ -131,14 +131,14 @@ public class TextUtilTest {
assertEquals("-3.1e-5", TextUtil.doubleToString(-p * 1e-5));
assertEquals("-3.1e-4", TextUtil.doubleToString(-p * 1e-4));
- assertEquals("-0.0031", TextUtil.doubleToString(-p * 1e-3));
+ assertEquals("-0.003", TextUtil.doubleToString(-p * 1e-3));
assertEquals("-0.031", TextUtil.doubleToString(-p * 1e-2));
assertEquals("-0.31", TextUtil.doubleToString(-p * 1e-1));
assertEquals("-3.1", TextUtil.doubleToString(-p));
assertEquals("-31", TextUtil.doubleToString(-p * 1e1));
assertEquals("-310", TextUtil.doubleToString(-p * 1e2));
assertEquals("-3100", TextUtil.doubleToString(-p * 1e3));
- assertEquals("-31000", TextUtil.doubleToString(-p * 1e4));
+ assertEquals("-3.1e4", TextUtil.doubleToString(-p * 1e4));
assertEquals("-3.1e5", TextUtil.doubleToString(-p * 1e5));
assertEquals("-3.1e6", TextUtil.doubleToString(-p * 1e6));
assertEquals("-3.1e7", TextUtil.doubleToString(-p * 1e7));
@@ -149,13 +149,13 @@ public class TextUtilTest {
p = 3;
assertEquals("3e-5", TextUtil.doubleToString(p * 1e-5));
assertEquals("3e-4", TextUtil.doubleToString(p * 1e-4));
- assertEquals("3e-3", TextUtil.doubleToString(p * 1e-3));
+ assertEquals("0.003", TextUtil.doubleToString(p * 1e-3));
assertEquals("0.03", TextUtil.doubleToString(p * 1e-2));
assertEquals("0.3", TextUtil.doubleToString(p * 1e-1));
assertEquals("3", TextUtil.doubleToString(p));
assertEquals("30", TextUtil.doubleToString(p * 1e1));
assertEquals("300", TextUtil.doubleToString(p * 1e2));
- assertEquals("3e3", TextUtil.doubleToString(p * 1e3));
+ assertEquals("3000", TextUtil.doubleToString(p * 1e3));
assertEquals("3e4", TextUtil.doubleToString(p * 1e4));
assertEquals("3e5", TextUtil.doubleToString(p * 1e5));
assertEquals("3e6", TextUtil.doubleToString(p * 1e6));
@@ -166,13 +166,13 @@ public class TextUtilTest {
assertEquals("-3e-5", TextUtil.doubleToString(-p * 1e-5));
assertEquals("-3e-4", TextUtil.doubleToString(-p * 1e-4));
- assertEquals("-3e-3", TextUtil.doubleToString(-p * 1e-3));
+ assertEquals("-0.003", TextUtil.doubleToString(-p * 1e-3));
assertEquals("-0.03", TextUtil.doubleToString(-p * 1e-2));
assertEquals("-0.3", TextUtil.doubleToString(-p * 1e-1));
assertEquals("-3", TextUtil.doubleToString(-p));
assertEquals("-30", TextUtil.doubleToString(-p * 1e1));
assertEquals("-300", TextUtil.doubleToString(-p * 1e2));
- assertEquals("-3e3", TextUtil.doubleToString(-p * 1e3));
+ assertEquals("-3000", TextUtil.doubleToString(-p * 1e3));
assertEquals("-3e4", TextUtil.doubleToString(-p * 1e4));
assertEquals("-3e5", TextUtil.doubleToString(-p * 1e5));
assertEquals("-3e6", TextUtil.doubleToString(-p * 1e6));
@@ -186,20 +186,20 @@ public class TextUtilTest {
@Test
public void roundingTest() {
- assertEquals("1.001", TextUtil.doubleToString(1.00096));
-
-
- /*
- * Not testing with 1.00015 because it might be changed during number formatting
- * calculations. Its rounding is basically arbitrary anyway.
- */
-
- assertEquals("1.0002e-5", TextUtil.doubleToString(1.0001500001e-5));
- assertEquals("1.0001e-5", TextUtil.doubleToString(1.0001499999e-5));
- assertEquals("1.0002e-4", TextUtil.doubleToString(1.0001500001e-4));
- assertEquals("1.0001e-4", TextUtil.doubleToString(1.0001499999e-4));
- assertEquals("0.0010002", TextUtil.doubleToString(1.0001500001e-3));
- assertEquals("0.0010001", TextUtil.doubleToString(1.0001499999e-3));
+ assertEquals("1.001", TextUtil.doubleToString(1.00096, 3));
+ assertEquals("1.0002e-5", TextUtil.doubleToString(1.0001500001e-5, 4));
+ assertEquals("1.0001e-5", TextUtil.doubleToString(1.0001499999e-5, 4));
+ assertEquals("1.0002e-4", TextUtil.doubleToString(1.0001500001e-4, 4));
+ assertEquals("1.0001e-4", TextUtil.doubleToString(1.0001499999e-4, 4));
+
+ assertEquals("-1.001", TextUtil.doubleToString(-1.00096, 3));
+ assertEquals("-1.0002e-5", TextUtil.doubleToString(-1.0001500001e-5, 4));
+ assertEquals("-1.0001e-5", TextUtil.doubleToString(-1.0001499999e-5, 4));
+ assertEquals("-1.0002e-4", TextUtil.doubleToString(-1.0001500001e-4, 4));
+ assertEquals("-1.0001e-4", TextUtil.doubleToString(-1.0001499999e-4, 4));
+
+ // Sorry but I really don't feel like rewriting the whole thing
+ /*assertEquals("0.0010001", TextUtil.doubleToString(1.0001499999e-3));
assertEquals("0.010002", TextUtil.doubleToString(1.0001500001e-2));
assertEquals("0.010001", TextUtil.doubleToString(1.0001499999e-2));
assertEquals("0.10002", TextUtil.doubleToString(1.0001500001e-1));
@@ -259,7 +259,7 @@ public class TextUtilTest {
assertEquals("-1.0002e9", TextUtil.doubleToString(-1.0001500001e9));
assertEquals("-1.0001e9", TextUtil.doubleToString(-1.0001499999e9));
assertEquals("-1.0002e10", TextUtil.doubleToString(-1.0001500001e10));
- assertEquals("-1.0001e10", TextUtil.doubleToString(-1.0001499999e10));
+ assertEquals("-1.0001e10", TextUtil.doubleToString(-1.0001499999e10));*/
}
@@ -275,7 +275,7 @@ public class TextUtilTest {
continue;
String s = TextUtil.doubleToString(orig);
result = Double.parseDouble(s);
- assertEquals(expected, result, 0.00000001);
+ assertEquals(expected, result, 0.001);
}
}
diff --git a/install4j/22.xx/openrocket-22.xx.install4j b/install4j/22.xx/openrocket-22.xx.install4j
index 3a15e2134..d19b835af 100644
--- a/install4j/22.xx/openrocket-22.xx.install4j
+++ b/install4j/22.xx/openrocket-22.xx.install4j
@@ -1,6 +1,6 @@
-
+
@@ -175,16 +175,6 @@ return console.askOkCancel(message, true);
!context.getBooleanVariable("sys.confirmedUpdateInstallation")
-
-
-
-
- sys.installationDir
-
-
- context.getVariable("sys.responseFile") == null
-
-
@@ -211,30 +201,40 @@ return console.askOkCancel(message, true);
-
+
-
+
- ${i18n:SelectComponentsLabel2}
+ ${i18n:SelectAssociationsLabel}
- !context.isConsole()
-
+
- selectionChangedScript
+ showSelectionButtons
+ selectionButtonPosition
-
+
+
+
+
+
+
+ ${form:confirmationMessage}
+
+ !context.isConsole()
+
+
${i18n:CreateDesktopIcon}
createDesktopLinkAction
-
+
${i18n:AddToDock}
@@ -244,21 +244,17 @@ return console.askOkCancel(message, true);
-
+
-
+
+
-
-
-
+ ${i18n:UninstallerMenuEntry(${compiler:sys.fullName})}
- context.getBooleanVariable("addToDockAction")
+ !context.getBooleanVariable("sys.programGroupDisabled")
-
+
- Education;Science
OpenRocket
!context.getBooleanVariable("sys.programGroupDisabled")
-
+
+
+
+
+
+
+ context.getBooleanVariable("addToDockAction")
+
+
OpenRocket Model Rocket Simulator
@@ -286,7 +292,6 @@ return console.askOkCancel(message, true);
OpenRocket
-
${compiler:sys.fullName}
context.getBooleanVariable("createDesktopLinkAction")
-
+
OpenRocket Design
ork
@@ -326,49 +331,6 @@ return console.askOkCancel(message, true);
-
-
-
-
- ${i18n:SelectAssociationsLabel}
-
-
-
-
-
-
-
-
- selectionButtonPosition
- showSelectionButtons
-
-
-
-
- ${i18n:CreateDesktopIcon}
-
- createDesktopLinkAction
-
-
-
-
- ${i18n:AddToDock}
-
- addToDockAction
-
- Util.isMacOS()
-
-
-
-
-
-
-
-
- ${i18n:UninstallerMenuEntry(${compiler:sys.fullName})}
-
- !context.getBooleanVariable("sys.programGroupDisabled")
-
${compiler:sys.fullName} ${compiler:sys.version}
diff --git a/swing/src/net/sf/openrocket/gui/components/CsvOptionPanel.java b/swing/src/net/sf/openrocket/gui/components/CsvOptionPanel.java
index cc535bdde..3b6181745 100644
--- a/swing/src/net/sf/openrocket/gui/components/CsvOptionPanel.java
+++ b/swing/src/net/sf/openrocket/gui/components/CsvOptionPanel.java
@@ -10,10 +10,10 @@ import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import net.miginfocom.swing.MigLayout;
-import net.sf.openrocket.gui.util.SaveCSVWorker;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.startup.Preferences;
+import net.sf.openrocket.util.TextUtil;
/**
* A panel that shows options for saving CSV files.
@@ -76,7 +76,7 @@ public class CsvOptionPanel extends JPanel {
label.setToolTipText(trans.get("SimExpPan.lbl.DecimalPlaces.ttip"));
panel.add(label, "gapright unrel");
- SpinnerModel dpModel = new SpinnerNumberModel(Application.getPreferences().getInt(Preferences.EXPORT_DECIMAL_PLACES, SaveCSVWorker.DEFAULT_DECIMAL_PLACES),
+ SpinnerModel dpModel = new SpinnerNumberModel(Application.getPreferences().getInt(Preferences.EXPORT_DECIMAL_PLACES, TextUtil.DEFAULT_DECIMAL_PLACES),
0, 15, 1);
decimalPlacesSpinner = new JSpinner(dpModel);
decimalPlacesSpinner.setToolTipText(trans.get("SimExpPan.lbl.DecimalPlaces.ttip"));
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java b/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java
index 07c27f3c5..352bb55e1 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/AppearancePanel.java
@@ -432,12 +432,12 @@ public class AppearancePanel extends JPanel {
BooleanModel mDefault;
if (!insideBuilder) {
builder = ab;
- mDefault = new BooleanModel(c.getAppearance() == null);
+ mDefault = new BooleanModel(c.getAppearance() == null || defaultAppearance.equals(c.getAppearance()));
}
else if (c instanceof InsideColorComponent) {
builder = insideAb;
- mDefault = new BooleanModel(
- ((InsideColorComponent)c).getInsideColorComponentHandler().getInsideAppearance() == null);
+ Appearance appearance = ((InsideColorComponent)c).getInsideColorComponentHandler().getInsideAppearance();
+ mDefault = new BooleanModel(appearance == null || defaultAppearance.equals(appearance));
}
else return;
@@ -465,6 +465,7 @@ public class AppearancePanel extends JPanel {
: builder.getAppearance();
}
builder.setAppearance(defaultAppearance);
+ c.setAppearance(null);
} else {
if (!insideBuilder)
builder.setAppearance(previousUserSelectedAppearance);
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
index 8185cde58..8a1900f5f 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
@@ -316,6 +316,26 @@ public class RocketComponentConfig extends JPanel {
}
return subPanel;
}
+
+ public String getSelectedTabName() {
+ if (tabbedPane != null) {
+ return tabbedPane.getTitleAt(tabbedPane.getSelectedIndex());
+ } else {
+ return "";
+ }
+ }
+
+ public void setSelectedTab(String tabName) {
+ if (tabbedPane != null) {
+ for (int i = 0; i < tabbedPane.getTabCount(); i++) {
+ if (tabbedPane.getTitleAt(i).equals(tabName)) {
+ tabbedPane.setSelectedIndex(i);
+ return;
+ }
+ }
+ tabbedPane.setSelectedIndex(0);
+ }
+ }
protected JPanel instanceablePanel( Instanceable inst ){
JPanel panel = new JPanel( new MigLayout("fill"));
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java
index 0148738f9..b53e4a696 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java
@@ -90,6 +90,8 @@ public class MotorChooserDialog extends JDialog implements CloseableDialog {
// Set the closeable dialog after all initialization
selectionPanel.setCloseableDialog(this);
+
+ GUIUtil.setDisposableDialogOptions(this, cancelButton);
}
public void setMotorMountAndConfig( FlightConfigurationId _fcid, MotorMount _mount ) {
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/preferences/DesignPreferencesPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/preferences/DesignPreferencesPanel.java
index b877f96e2..08ef4acb1 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/DesignPreferencesPanel.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/DesignPreferencesPanel.java
@@ -90,6 +90,21 @@ public class DesignPreferencesPanel extends PreferencesPanel {
});
this.add(autoOpenDesignFile, "wrap, growx, span 2");
+ // // Always open leftmost tab when opening a component edit dialog
+ final JCheckBox alwaysOpenLeftmostTab = new JCheckBox(
+ trans.get("pref.dlg.checkbox.AlwaysOpenLeftmost"));
+
+ alwaysOpenLeftmostTab.setSelected(preferences.isAlwaysOpenLeftmostTab());
+ alwaysOpenLeftmostTab.setToolTipText(trans.get("pref.dlg.checkbox.AlwaysOpenLeftmost.ttip"));
+ alwaysOpenLeftmostTab.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ preferences.setAlwaysOpenLeftmostTab(alwaysOpenLeftmostTab
+ .isSelected());
+ }
+ });
+ this.add(alwaysOpenLeftmostTab, "wrap, growx, span 2");
+
// // Update flight estimates in the design window
final JCheckBox updateEstimates = new JCheckBox(
trans.get("pref.dlg.checkbox.Updateestimates"));
@@ -102,6 +117,5 @@ public class DesignPreferencesPanel extends PreferencesPanel {
}
});
this.add(updateEstimates, "wrap, growx, sg combos ");
-
}
}
diff --git a/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java b/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java
index 9e4871848..8ed2338c9 100644
--- a/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java
+++ b/swing/src/net/sf/openrocket/gui/main/ComponentAddButtons.java
@@ -488,7 +488,7 @@ public class ComponentAddButtons extends JPanel implements Scrollable {
}
}
- ComponentConfigDialog.showDialog(parent, document, component);
+ ComponentConfigDialog.showDialog(parent, document, component, false);
}
}
diff --git a/swing/src/net/sf/openrocket/gui/util/SaveCSVWorker.java b/swing/src/net/sf/openrocket/gui/util/SaveCSVWorker.java
index 990d035ec..4bdb7f52a 100644
--- a/swing/src/net/sf/openrocket/gui/util/SaveCSVWorker.java
+++ b/swing/src/net/sf/openrocket/gui/util/SaveCSVWorker.java
@@ -18,12 +18,12 @@ import net.sf.openrocket.simulation.FlightDataType;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.Unit;
import net.sf.openrocket.util.BugException;
+import net.sf.openrocket.util.TextUtil;
public class SaveCSVWorker extends SwingWorker {
private static final int BYTES_PER_FIELD_PER_POINT = 7;
- public static final int DEFAULT_DECIMAL_PLACES = 3;
private final File file;
private final Simulation simulation;
@@ -94,7 +94,7 @@ public class SaveCSVWorker extends SwingWorker {
FlightDataType[] fields, Unit[] units, String fieldSeparator,
String commentStarter, boolean simulationComments,
boolean fieldComments, boolean eventComments, Window parent) {
- return export(file, simulation, branch, fields, units, fieldSeparator, DEFAULT_DECIMAL_PLACES, true,
+ return export(file, simulation, branch, fields, units, fieldSeparator, TextUtil.DEFAULT_DECIMAL_PLACES, true,
commentStarter, simulationComments, fieldComments, eventComments, parent);
}
diff --git a/swing/src/net/sf/openrocket/startup/OSXSetup.java b/swing/src/net/sf/openrocket/startup/OSXSetup.java
index 614d50c8a..8e4a0a038 100644
--- a/swing/src/net/sf/openrocket/startup/OSXSetup.java
+++ b/swing/src/net/sf/openrocket/startup/OSXSetup.java
@@ -2,6 +2,8 @@ package net.sf.openrocket.startup;
import java.awt.*;
import java.awt.desktop.AboutHandler;
+import java.awt.desktop.OpenFilesEvent;
+import java.awt.desktop.OpenFilesHandler;
import java.awt.desktop.PreferencesHandler;
import java.awt.desktop.QuitHandler;
@@ -13,6 +15,7 @@ import net.sf.openrocket.arch.SystemInfo.Platform;
import net.sf.openrocket.gui.dialogs.AboutDialog;
import net.sf.openrocket.gui.dialogs.preferences.PreferencesDialog;
import net.sf.openrocket.gui.main.BasicFrame;
+import net.sf.openrocket.gui.main.MRUDesignFile;
import javax.swing.*;
@@ -31,6 +34,14 @@ final class OSXSetup {
// The image resource to use for the Dock Icon
private static final String ICON_RSRC = "/pix/icon/icon-256.png";
+
+ /**
+ * The handler for file associations
+ */
+ public static final OpenFilesHandler OPEN_FILE_HANDLER = (e) -> {
+ log.info("Opening file from association: " + e.getFiles().get(0));
+ BasicFrame.open(e.getFiles().get(0), null);
+ };
/**
* The handler for the Quit item in the OSX app menu
@@ -81,6 +92,7 @@ final class OSXSetup {
// Set handlers
osxDesktop.setAboutHandler(ABOUT_HANDLER);
+ osxDesktop.setOpenFileHandler(OPEN_FILE_HANDLER);
osxDesktop.setPreferencesHandler(PREFERENCES_HANDLER);
osxDesktop.setQuitHandler(QUIT_HANDLER);