diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 46a969ff4..f836bf176 100644 --- a/core/resources/l10n/messages.properties +++ b/core/resources/l10n/messages.properties @@ -306,7 +306,7 @@ pref.dlg.Allthrustcurvefiles = All thrust curve files (*.eng; *.rse; *.zip; dire pref.dlg.RASPfiles = RASP motor files (*.eng) pref.dlg.RockSimfiles = RockSim engine files (*.rse) pref.dlg.ZIParchives = ZIP archives (*.zip) -pref.dlg.checkbox.Checkupdates = Check for software updates at startup +pref.dlg.checkbox.Checkupdates = Always check for software updates at startup pref.dlg.checkbox.Checkupdates.ttip = Check for software updates every time you start up OpenRocket pref.dlg.checkbox.CheckBetaupdates = Also check for beta releases pref.dlg.checkbox.CheckBetaupdates.ttip = If checked, beta release updates are also notified. If unchecked, only official releases are considered. @@ -363,11 +363,11 @@ update.dlg.latestVersion = You are running the latest version of OpenRocket, ver update.dlg.newerVersion.title = Newer version detected update.dlg.newerVersion = You are either running a test/unofficial release of OpenRocket, or you have a time machine and are running an official release from the future.\n\nYour version: %s\nLatest official release: %s update.dlg.updateAvailable.title = Update available -update.dlg.updateAvailable.txtPane.title = OpenRocket version %s available! -update.dlg.updateAvailable.txtPane.yourVersion = Your current version: %s -update.dlg.updateAvailable.txtPane.changelog = Changelog +update.dlg.updateAvailable.lbl.title = A new version of OpenRocket is available! +update.dlg.updateAvailable.lbl.yourVersion = OpenRocket %s is available! \u2015 you have %s. Would you like to download it now? +update.dlg.updateAvailable.lbl.releaseNotes = Release notes: update.dlg.updateAvailable.txtPane.readMore = Read more on GitHub -update.dlg.updateAvailable.but.install = Install update +update.dlg.updateAvailable.but.install = Install Update update.dlg.updateAvailable.combo.noDownloads = No downloads available update.fetcher.badResponse = Bad response code from server: %d update.fetcher.badConnection = Could not connect to the GitHub server. Please check your internet connection. diff --git a/core/resources/l10n/messages_ru.properties b/core/resources/l10n/messages_ru.properties index 2903f7242..622206d70 100644 --- a/core/resources/l10n/messages_ru.properties +++ b/core/resources/l10n/messages_ru.properties @@ -64,6 +64,8 @@ RocketPanel.lbl.Stability = \u0421\u0442\u0430\u0431\u0438\u043B\u044C\u043D\u04 RocketPanel.checkbox.ShowCGCP = \u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0426\u0422/\u0426\u0414 RocketPanel.checkbox.ShowCGCP.ttip = \u041E\u0442\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435 \u044D\u0442\u043E\u0433\u043E \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430 \u0441\u043A\u0440\u043E\u0435\u0442 \u043E\u0442\u043C\u0435\u0442\u043A\u0438 \u0426\u0422/\u0426\u0414. RocketPanel.lbl.Stages = \u0421\u0442\u0443\u043F\u0435\u043D\u0438: +RocketPanel.btn.Stages.Toggle.ttip = \u041D\u0430\u0436\u0430\u0442\u0438\u0435 \u044D\u0442\u043E\u0439 \u043A\u043D\u043E\u043F\u043A\u0438 \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u0442/\u0434\u0435\u0430\u043A\u0442\u0438\u0432\u0438\u0440\u0443\u0435\u0442 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044E\u0449\u0443\u044E \u0441\u0442\u0443\u043F\u0435\u043D\u044C \u0440\u0430\u043A\u0435\u0442\u044B. +RocketPanel.btn.Stages.NoChildren.ttip = \u0412 \u044D\u0442\u043E\u0439 \u0441\u0442\u0443\u043F\u0435\u043D\u0438 \u043D\u0435\u0442 \u0434\u043E\u0447\u0435\u0440\u043D\u0438\u0445 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u043E\u0432, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u043E\u043D\u0430 \u043F\u043E\u043C\u0435\u0447\u0435\u043D\u0430 \u043A\u0430\u043A \u043D\u0435\u0430\u043A\u0442\u0438\u0432\u043D\u0430\u044F.
\u0414\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u044B \u0432 \u0441\u0442\u0443\u043F\u0435\u043D\u044C, \u0447\u0442\u043E\u0431\u044B \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0435\u0451. RocketPanel.ttip.Rotation = \u0421\u043C\u0435\u043D\u0430 \u0432\u0440\u0430\u0449\u0435\u043D\u0438\u044F \u043A\u0440\u0435\u043D\u0430 \u0440\u0430\u043A\u0435\u0442\u044B (\u0442\u043E\u043B\u044C\u043A\u043E \u0432 \u043E\u043A\u043D\u0435 \u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440\u0430) ! BasicFrame @@ -305,7 +307,7 @@ pref.dlg.Allthrustcurvefiles = \u0424\u0430\u0439\u043B\u044B \u043F\u0440\u043E pref.dlg.RASPfiles = \u0424\u0430\u0439\u043B\u044B \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u0435\u0439 RASP (*.eng) pref.dlg.RockSimfiles = \u0424\u0430\u0439\u043B\u044B \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u0435\u0439 RockSim (*.rse) pref.dlg.ZIParchives = ZIP-\u0430\u0440\u0445\u0438\u0432\u044B (*.zip) -pref.dlg.checkbox.Checkupdates = \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u043D\u0430\u043B\u0438\u0447\u0438\u0435 \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043F\u0440\u0438 \u0437\u0430\u043F\u0443\u0441\u043A\u0435 +pref.dlg.checkbox.Checkupdates = \u0412\u0441\u0435\u0433\u0434\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u043D\u0430\u043B\u0438\u0447\u0438\u0435 \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043F\u0440\u0438 \u0437\u0430\u043F\u0443\u0441\u043A\u0435 pref.dlg.checkbox.Checkupdates.ttip = \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u043D\u0430\u043B\u0438\u0447\u0438\u0435 \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043F\u0440\u0438 \u043A\u0430\u0436\u0434\u043E\u043C \u0437\u0430\u043F\u0443\u0441\u043A\u0435 OpenRocket pref.dlg.checkbox.CheckBetaupdates = \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u0431\u0435\u0442\u0430-\u0432\u0435\u0440\u0441\u0438\u0438 pref.dlg.checkbox.CheckBetaupdates.ttip = \u0415\u0441\u043B\u0438 \u0444\u043B\u0430\u0436\u043E\u043A \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D, \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u0431\u0435\u0442\u0430-\u0432\u0435\u0440\u0441\u0438\u0438 \u0442\u0430\u043A\u0436\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u044E\u0442\u0441\u044F. \u0415\u0441\u043B\u0438 \u0444\u043B\u0430\u0436\u043E\u043A \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D, \u0443\u0447\u0438\u0442\u044B\u0432\u0430\u044E\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u043E\u0444\u0438\u0446\u0438\u0430\u043B\u044C\u043D\u044B\u0435 \u0432\u044B\u043F\u0443\u0441\u043A\u0438. @@ -362,9 +364,9 @@ update.dlg.latestVersion = \u0412\u044B \u0440\u0430\u0431\u043E\u0442\u0430\u04 update.dlg.newerVersion.title = \u041E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D\u0430 \u0431\u043E\u043B\u0435\u0435 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F update.dlg.newerVersion = \u0412\u044B \u043B\u0438\u0431\u043E \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0435 \u0442\u0435\u0441\u0442\u043E\u0432\u0443\u044E/\u043D\u0435\u043E\u0444\u0438\u0446\u0438\u0430\u043B\u044C\u043D\u0443\u044E \u0432\u0435\u0440\u0441\u0438\u044E OpenRocket, \u043B\u0438\u0431\u043E \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044C \u043C\u0430\u0448\u0438\u043D\u0430 \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u0438 \u0432\u044B \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0435 \u043E\u0444\u0438\u0446\u0438\u0430\u043B\u044C\u043D\u0443\u044E \u0432\u0435\u0440\u0441\u0438\u044E \u0438\u0437 \u0431\u0443\u0434\u0443\u0449\u0435\u0433\u043E.\n\n\u0412\u0430\u0448\u0430 \u0432\u0435\u0440\u0441\u0438\u044F: %s\n\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0439 \u043E\u0444\u0438\u0446\u0438\u0430\u043B\u044C\u043D\u044B\u0439 \u0432\u044B\u043F\u0443\u0441\u043A: %s update.dlg.updateAvailable.title = \u0414\u043E\u0441\u0442\u0443\u043F\u043D\u044B \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F -update.dlg.updateAvailable.txtPane.title = \u0414\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u0432\u0435\u0440\u044F\u0438 OpenRocket %s! -update.dlg.updateAvailable.txtPane.yourVersion = \u0412\u0430\u0448\u0430 \u0442\u0435\u043A\u0443\u0449\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F: %s -update.dlg.updateAvailable.txtPane.changelog = \u0421\u043F\u0438\u0441\u043E\u043A \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439 +update.dlg.updateAvailable.lbl.title = \u0414\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F OpenRocket! +update.dlg.updateAvailable.lbl.yourVersion = \u0414\u043E\u0441\u0442\u0443\u043F\u043D\u0430 OpenRocket %s! \u0423 \u0432\u0430\u0441 %s. \u0425\u043E\u0442\u0438\u0442\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0435\u0451 \u0441\u0435\u0439\u0447\u0430\u0441? +update.dlg.updateAvailable.lbl.releaseNotes = \u041F\u0440\u0438\u043C\u0435\u0447\u0430\u043D\u0438\u044F \u043A \u0432\u044B\u043F\u0443\u0441\u043A\u0443: update.dlg.updateAvailable.txtPane.readMore = \u0423\u0437\u043D\u0430\u0439\u0442\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0430 GitHub update.dlg.updateAvailable.but.install = \u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 update.dlg.updateAvailable.combo.noDownloads = \u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u0437\u0430\u0433\u0440\u0443\u0437\u043E\u043A diff --git a/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java b/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java index 6e32873e4..3cc791d79 100644 --- a/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java @@ -428,8 +428,15 @@ public class OpenRocketSaver extends RocketSaver { private void savePhotoSettings(Map p) throws IOException { log.debug("Saving Photo Settings"); + + writeln(""); + indent++; + for (String s : PhotoStudioSaver.getElements(p)) writeln(s); + + indent--; + writeln(""); } diff --git a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java index e9bd33b29..60a20db09 100644 --- a/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java +++ b/core/src/net/sf/openrocket/file/openrocket/importt/DocumentConfig.java @@ -374,7 +374,7 @@ class DocumentConfig { // MassObject setters.put("MassObject:packedlength", new DoubleSetter( - Reflection.findMethod(MassObject.class, "setLength", double.class))); + Reflection.findMethod(MassObject.class, "setLengthNoAuto", double.class))); setters.put("MassObject:packedradius", new DoubleSetter( Reflection.findMethod(MassObject.class, "setRadius", double.class), "auto", " ", diff --git a/core/src/net/sf/openrocket/file/openrocket/savers/PhotoStudioSaver.java b/core/src/net/sf/openrocket/file/openrocket/savers/PhotoStudioSaver.java index 2d91e5f40..16a79c459 100644 --- a/core/src/net/sf/openrocket/file/openrocket/savers/PhotoStudioSaver.java +++ b/core/src/net/sf/openrocket/file/openrocket/savers/PhotoStudioSaver.java @@ -21,8 +21,6 @@ public class PhotoStudioSaver { if (photoSettings == null || photoSettings.size() == 0) return elements; - elements.add(""); - elements.add("" + photoSettings.get("roll") + ""); elements.add("" + photoSettings.get("yaw") + ""); elements.add("" + photoSettings.get("pitch") + ""); @@ -45,7 +43,6 @@ public class PhotoStudioSaver { emitColor("flameColor", elements, photoSettings.get("flameColor")); elements.add("" + photoSettings.get("smoke") + ""); emitColor("smokeColor", elements, photoSettings.get("smokeColor")); - elements.add("" + photoSettings.get("smokeOpacity") + ""); elements.add("" + photoSettings.get("sparks") + ""); elements.add("" + photoSettings.get("exhaustScale") + ""); elements.add("" + photoSettings.get("flameAspectRatio") + ""); @@ -55,8 +52,6 @@ public class PhotoStudioSaver { elements.add("" + photoSettings.get("sky") + ""); - elements.add(""); - return elements; } diff --git a/core/src/net/sf/openrocket/rocketcomponent/MassObject.java b/core/src/net/sf/openrocket/rocketcomponent/MassObject.java index 1522fde04..cfd69691f 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/MassObject.java +++ b/core/src/net/sf/openrocket/rocketcomponent/MassObject.java @@ -53,10 +53,10 @@ public abstract class MassObject extends InternalComponent { @Override public double getLength() { if (this.autoRadius) { - // Calculate the parachute volume using the non auto radius and the non auto length, and transform that back + // Calculate the volume using the non auto radius and the non auto length, and transform that back // to the auto radius situation to get the auto radius length (the volume in both situations is the same). - double parachuteVolume = Math.pow(this.radius, 2) * this.length; // Math.PI left out, not needed - return parachuteVolume / Math.pow(getRadius(), 2); + double volume = Math.pow(this.radius, 2) * this.length; // Math.PI left out, not needed + return volume / Math.pow(getRadius(), 2); } return length; } @@ -93,10 +93,10 @@ public abstract class MassObject extends InternalComponent { length = Math.max(length, 0); if (this.autoRadius) { - // Calculate the parachute volume using the auto radius and the new "auto" length, and transform that back + // Calculate the volume using the auto radius and the new "auto" length, and transform that back // to the non auto radius situation to set this.length (the volume in both situations is the same). - double parachuteVolume = Math.pow(getRadius(), 2) * length; // Math.PI left out, not needed - double newLength = parachuteVolume / Math.pow(this.radius, 2); + double volume = Math.pow(getRadius(), 2) * length; // Math.PI left out, not needed + double newLength = volume / Math.pow(this.radius, 2); if (MathUtil.equals(this.length, newLength)) return; this.length = newLength; @@ -168,8 +168,8 @@ public abstract class MassObject extends InternalComponent { autoRadius = auto; // Set the length - double parachuteVolume = (Math.PI * Math.pow(getRadius(), 2) * length); - length = parachuteVolume / (Math.PI * Math.pow(getRadius(), 2)); + double volume = (Math.PI * Math.pow(getRadius(), 2) * length); + length = volume / (Math.PI * Math.pow(getRadius(), 2)); fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE); } @@ -248,8 +248,8 @@ public abstract class MassObject extends InternalComponent { @Override public final Collection getComponentBounds() { Collection c = new ArrayList(); - addBound(c, 0, radius); - addBound(c, length, radius); + addBound(c, 0, getRadius()); + addBound(c, getLength(), getRadius()); return c; } diff --git a/core/src/net/sf/openrocket/startup/Preferences.java b/core/src/net/sf/openrocket/startup/Preferences.java index 90da3c320..0b27c19f1 100644 --- a/core/src/net/sf/openrocket/startup/Preferences.java +++ b/core/src/net/sf/openrocket/startup/Preferences.java @@ -58,6 +58,7 @@ public abstract class Preferences implements ChangeSource { private static final String CHECK_UPDATES = "CheckUpdates"; + private static final String IGNORE_VERSIONS = "IgnoreVersions"; private static final String CHECK_BETA_UPDATES = "CheckBetaUpdates"; public static final String MOTOR_DIAMETER_FILTER = "MotorDiameterMatch"; @@ -150,6 +151,14 @@ public abstract class Preferences implements ChangeSource { this.putBoolean(CHECK_UPDATES, check); } + public final List getIgnoreVersions() { + return List.of(this.getString(IGNORE_VERSIONS, "").split("\n")); + } + + public final void setIgnoreVersions(List versions) { + this.putString(IGNORE_VERSIONS, String.join("\n", versions)); + } + public final boolean getCheckBetaUpdates() { return this.getBoolean(CHECK_BETA_UPDATES, BuildProperties.getDefaultCheckBetaUpdates()); } diff --git a/core/test/net/sf/openrocket/rocketcomponent/MassObjectTest.java b/core/test/net/sf/openrocket/rocketcomponent/MassObjectTest.java new file mode 100644 index 000000000..a7e18ea75 --- /dev/null +++ b/core/test/net/sf/openrocket/rocketcomponent/MassObjectTest.java @@ -0,0 +1,86 @@ +package net.sf.openrocket.rocketcomponent; + +import net.sf.openrocket.util.BaseTestCase.BaseTestCase; +import net.sf.openrocket.util.MathUtil; +import org.junit.Test; +import org.junit.Assert; + +public class MassObjectTest extends BaseTestCase { + @Test + public void testAutoRadius() { + MassObject sc = new ShockCord(); + MassObject mc = new MassComponent(); + MassObject pc = new Parachute(); + MassObject st = new Streamer(); + MassObject[] massObjects = {sc, mc, pc, st}; + + for (MassObject mo : massObjects) { + // Test no auto + mo.setRadiusAutomatic(false); + mo.setRadius(0.1); + mo.setLength(0.1); + Assert.assertEquals(String.format(" No auto %s incorrect radius", mo.getClass().getName()), + 0.1, mo.getRadius(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" No auto %s incorrect no auto radius", mo.getClass().getName()), + 0.1, mo.getRadiusNoAuto(),MathUtil.EPSILON); + Assert.assertEquals(String.format(" No auto %s incorrect length", mo.getClass().getName()), + 0.1, mo.getLength(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" No auto %s incorrect no auto length", mo.getClass().getName()), + 0.1, mo.getLengthNoAuto(), MathUtil.EPSILON); + + mo.setLengthNoAuto(0.1); + Assert.assertEquals(String.format(" No auto 2 %s incorrect length", mo.getClass().getName()), + 0.1, mo.getLength(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" No auto 2 %s incorrect no auto length", mo.getClass().getName()), + 0.1, mo.getLengthNoAuto(), MathUtil.EPSILON); + + // Test auto + BodyTube parent = new BodyTube(); + parent.setOuterRadius(0.05); + parent.setInnerRadius(0.05); + parent.addChild(mo); + mo.setRadiusAutomatic(true); + Assert.assertEquals(String.format(" Auto 1 %s incorrect radius", mo.getClass().getName()), + 0.05, mo.getRadius(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" Auto 1 %s incorrect no auto radius", mo.getClass().getName()), + 0.1, mo.getRadiusNoAuto(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" Auto 1 %s incorrect length", mo.getClass().getName()), + 0.4, mo.getLength(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" Auto 1 %s incorrect no auto length", mo.getClass().getName()), + 0.1, mo.getLengthNoAuto(), MathUtil.EPSILON); + + parent.setOuterRadius(0.1); + parent.setInnerRadius(0.1); + Assert.assertEquals(String.format(" Auto 2 %s incorrect radius", mo.getClass().getName()), + 0.1, mo.getRadius(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" Auto 2 %s incorrect no auto radius", mo.getClass().getName()), + 0.1, mo.getRadiusNoAuto(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" Auto 2 %s incorrect length", mo.getClass().getName()), + 0.1, mo.getLength(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" Auto 2 %s incorrect no auto length", mo.getClass().getName()), + 0.1, mo.getLengthNoAuto(), MathUtil.EPSILON); + + parent.setOuterRadius(0.075); + parent.setInnerRadius(0.075); + mo.setLength(0.075); + Assert.assertEquals(String.format(" Auto 3 %s incorrect radius", mo.getClass().getName()), + 0.075, mo.getRadius(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" Auto 3 %s incorrect no auto radius", mo.getClass().getName()), + 0.1, mo.getRadiusNoAuto(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" Auto 3 %s incorrect length", mo.getClass().getName()), + 0.075, mo.getLength(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" Auto 3 %s incorrect no auto length", mo.getClass().getName()), + 0.0422, mo.getLengthNoAuto(), 0.001); + + mo.setLengthNoAuto(0.05); + Assert.assertEquals(String.format(" Auto 4 %s incorrect radius", mo.getClass().getName()), + 0.075, mo.getRadius(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" Auto 4 %s incorrect no auto radius", mo.getClass().getName()), + 0.1, mo.getRadiusNoAuto(), MathUtil.EPSILON); + Assert.assertEquals(String.format(" Auto 4 %s incorrect length", mo.getClass().getName()), + 0.0889, mo.getLength(), 0.001); + Assert.assertEquals(String.format(" Auto 4 %s incorrect no auto length", mo.getClass().getName()), + 0.05, mo.getLengthNoAuto(), MathUtil.EPSILON); + } + } +} diff --git a/swing/src/net/sf/openrocket/communication/AssetHandler.java b/swing/src/net/sf/openrocket/communication/AssetHandler.java index e21b5e997..942dec758 100644 --- a/swing/src/net/sf/openrocket/communication/AssetHandler.java +++ b/swing/src/net/sf/openrocket/communication/AssetHandler.java @@ -32,7 +32,7 @@ public class AssetHandler { mapExtensionToPlatform.put(".sh", new UpdatePlatform[] {UpdatePlatform.LINUX, UpdatePlatform.UNIX}); mapExtensionToPlatform.put(".jar", new UpdatePlatform[] {UpdatePlatform.JAR}); - mapPlatformToName.put(UpdatePlatform.MAC_OS, "Mac OS"); + mapPlatformToName.put(UpdatePlatform.MAC_OS, "macOS"); mapPlatformToName.put(UpdatePlatform.WINDOWS, "Windows"); mapPlatformToName.put(UpdatePlatform.LINUX, "Linux"); mapPlatformToName.put(UpdatePlatform.UNIX, "Linux"); @@ -42,7 +42,7 @@ public class AssetHandler { /** * Maps a list of asset URLs to their respective operating platform name. * E.g. "https://github.com/openrocket/openrocket/releases/download/release-15.03/OpenRocket-15.03.dmg" is mapped a - * map element with "Mac OS" as key and the url as value. + * map element with "macOS" as key and the url as value. * @param urls list of asset URLs * @return map with as key the operating platform name and as value the corresponding asset URL */ @@ -70,7 +70,7 @@ public class AssetHandler { } /** - * Get the name of a platform (e.g. for Platform.MAC_OS, return "Mac OS") + * Get the name of a platform (e.g. for Platform.MAC_OS, return "macOS") * @param platform platform to get the name from * @return name of the platform */ diff --git a/swing/src/net/sf/openrocket/file/photo/PhotoStudioGetter.java b/swing/src/net/sf/openrocket/file/photo/PhotoStudioGetter.java index 31bea899d..41f37e796 100644 --- a/swing/src/net/sf/openrocket/file/photo/PhotoStudioGetter.java +++ b/swing/src/net/sf/openrocket/file/photo/PhotoStudioGetter.java @@ -135,11 +135,6 @@ public class PhotoStudioGetter { p.setSmokeColor(smokeColor); return; } - if ("smokeOpacity".equals(element)) { - double smokeOpacity = Double.parseDouble(content); - p.setSmokeOpacity(smokeOpacity); - return; - } if ("sparks".equals(element)) { boolean sparks = Boolean.parseBoolean(content); p.setSparks(sparks); diff --git a/swing/src/net/sf/openrocket/file/photo/PhotoStudioSetter.java b/swing/src/net/sf/openrocket/file/photo/PhotoStudioSetter.java index 3fd4bd48f..b5dfec0ca 100644 --- a/swing/src/net/sf/openrocket/file/photo/PhotoStudioSetter.java +++ b/swing/src/net/sf/openrocket/file/photo/PhotoStudioSetter.java @@ -41,7 +41,6 @@ public class PhotoStudioSetter { photoSettings.put("flameColor", getColor(p.getFlameColor())); photoSettings.put("smoke", String.valueOf(p.isSmoke())); photoSettings.put("smokeColor", getColor(p.getSmokeColor())); - photoSettings.put("smokeOpacity", String.valueOf(p.getSmokeOpacity())); photoSettings.put("sparks", String.valueOf(p.isSparks())); photoSettings.put("exhaustScale", String.valueOf(p.getExhaustScale())); photoSettings.put("flameAspectRatio", String.valueOf(p.getFlameAspectRatio())); diff --git a/swing/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java index e5587a812..3a8cc9bcf 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java @@ -7,6 +7,7 @@ import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.URI; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -28,6 +29,8 @@ import net.sf.openrocket.communication.AssetHandler; import net.sf.openrocket.communication.AssetHandler.UpdatePlatform; import net.sf.openrocket.communication.ReleaseInfo; import net.sf.openrocket.communication.UpdateInfo; +import net.sf.openrocket.gui.components.StyledLabel; +import net.sf.openrocket.gui.configdialog.CommonStrings; import net.sf.openrocket.gui.util.GUIUtil; import net.sf.openrocket.gui.util.Icons; import net.sf.openrocket.gui.util.SwingPreferences; @@ -55,8 +58,19 @@ public class UpdateInfoDialog extends JDialog { JPanel panel = new JPanel(new MigLayout("insets n n 8px n, fill")); - panel.add(new JLabel(Icons.loadImageIcon("pix/icon/icon-about.png", "OpenRocket")), - "split, span, top"); + panel.add(new JLabel(Icons.getScaledIcon(Icons.loadImageIcon("pix/icon/icon-about.png", "OpenRocket"), 0.6)), + "spany, top, gapright 20px, cell 0 0"); + + // OpenRocket version available! + panel.add(new StyledLabel(trans.get("update.dlg.updateAvailable.lbl.title"), 8, StyledLabel.Style.BOLD), "spanx, wrap"); + + // Your version + ReleaseInfo release = info.getLatestRelease(); + panel.add(new StyledLabel(String.format(trans.get("update.dlg.updateAvailable.lbl.yourVersion"), + release.getReleaseName(), BuildProperties.getVersion()), -1, StyledLabel.Style.PLAIN), "skip 1, spanx, wrap para"); + + // Release notes + panel.add(new StyledLabel(trans.get("update.dlg.updateAvailable.lbl.releaseNotes"), 1, StyledLabel.Style.BOLD), "spanx, wrap"); // Release information box final JTextPane textPane = new JTextPane(); @@ -65,18 +79,10 @@ public class UpdateInfoDialog extends JDialog { textPane.setMargin(new Insets(10, 10, 40, 10)); textPane.putClientProperty(JTextPane.HONOR_DISPLAY_PROPERTIES, true); - ReleaseInfo release = info.getLatestRelease(); StringBuilder sb = new StringBuilder(); - - // OpenRocket version available! sb.append(""); - sb.append(String.format("

%s

", String.format(trans.get("update.dlg.updateAvailable.txtPane.title"), release.getReleaseName()))); - // Your version - sb.append(String.format("%s

", String.format(trans.get("update.dlg.updateAvailable.txtPane.yourVersion"), BuildProperties.getVersion()))); - - // Changelog - sb.append(String.format("

%s

", trans.get("update.dlg.updateAvailable.txtPane.changelog"))); + // Release notes String releaseNotes = release.getReleaseNotes(); releaseNotes = releaseNotes.replaceAll("^\"|\"$", ""); // Remove leading and trailing quotations sb.append(MarkdownUtil.toHtml(releaseNotes)).append("

"); @@ -103,7 +109,7 @@ public class UpdateInfoDialog extends JDialog { textPane.setText(sb.toString()); textPane.setCaretPosition(0); // Scroll to the top - panel.add(new JScrollPane(textPane), "left, grow, span, push, gapleft 40px, gapbottom 6px, wrap"); + panel.add(new JScrollPane(textPane), "skip 1, left, spanx, grow, push, gapbottom 6px, wrap"); //// Check for software updates at startup JCheckBox checkAtStartup = new JCheckBox(trans.get("pref.dlg.checkbox.Checkupdates")); @@ -116,9 +122,36 @@ public class UpdateInfoDialog extends JDialog { preferences.setCheckUpdates(checkAtStartup.isSelected()); } }); - panel.add(checkAtStartup); + panel.add(checkAtStartup, "skip 1, spanx, wrap"); - // Install operating system combo box + // Lower row buttons + //// Remind me later button + JButton btnLater = new SelectColorButton("Remind Me Later"); + btnLater.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + UpdateInfoDialog.this.dispose(); + } + }); + panel.add(btnLater, "skip 1, split 2"); + + //// Skip this version button + JButton btnSkip = new SelectColorButton("Skip This Version"); + btnSkip.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + List ignoreVersions = new ArrayList<>(preferences.getIgnoreVersions()); + String ignore = release.getReleaseName(); + if (!ignoreVersions.contains(ignore)) { + ignoreVersions.add(ignore); + preferences.setIgnoreVersions(ignoreVersions); + } + UpdateInfoDialog.this.dispose(); + } + }); + panel.add(btnSkip); + + //// Install operating system combo box List assetURLs = release.getAssetURLs(); Map mappedAssets = AssetHandler.mapURLToPlatform(assetURLs); JComboBox comboBox; @@ -141,7 +174,7 @@ public class UpdateInfoDialog extends JDialog { } panel.add(comboBox, "pushx, right"); - // Install update button + //// Install update button JButton btnInstall = new SelectColorButton(trans.get("update.dlg.updateAvailable.but.install")); btnInstall.addActionListener(new ActionListener() { @Override @@ -159,25 +192,15 @@ public class UpdateInfoDialog extends JDialog { if (mappedAssets == null || mappedAssets.size() == 0) { btnInstall.setEnabled(false); } - panel.add(btnInstall, "gapright 20"); - - // Cancel button - JButton btnCancel = new SelectColorButton(trans.get("button.cancel")); - btnCancel.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - UpdateInfoDialog.this.dispose(); - } - }); - panel.add(btnCancel); + panel.add(btnInstall, "wrap"); - panel.setPreferredSize(new Dimension(900, 600)); + panel.setPreferredSize(new Dimension(850, 700)); this.add(panel); this.pack(); this.setLocationRelativeTo(null); - GUIUtil.setDisposableDialogOptions(this, btnCancel); + GUIUtil.setDisposableDialogOptions(this, btnLater); } /** diff --git a/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java index e2efb2251..d4613d0e0 100644 --- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java +++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java @@ -326,6 +326,13 @@ public class GeneralPreferencesPanel extends PreferencesPanel { // Nothing went wrong (yay!) ReleaseStatus status = info.getReleaseStatus(); ReleaseInfo release = info.getLatestRelease(); + + // Do nothing if the release is part of the ignore versions + if (preferences.getIgnoreVersions().contains(release.getReleaseName())) { + return; + } + + // Display software updater dialog, based on the current build version status switch (status) { case LATEST: JOptionPane.showMessageDialog(this, diff --git a/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoSettings.java b/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoSettings.java index 23599f7f3..ab2ab795b 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoSettings.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/photo/PhotoSettings.java @@ -31,7 +31,6 @@ public class PhotoSettings extends AbstractChangeSource implements FlameSettings private Color flameColor = new Color(255, 100, 50); private boolean smoke = false; private Color smokeColor = new Color(230, 230, 230, 102); - private double smokeOpacity = 0.4; private boolean sparks = false; private double exhaustScale = 1.0; private double flameAspectRatio = 1.0; @@ -204,19 +203,23 @@ public class PhotoSettings extends AbstractChangeSource implements FlameSettings } public void setSmokeColor(Color smokeColor) { - smokeColor.setAlpha(this.smokeColor.getAlpha()); this.smokeColor = smokeColor; fireChangeEvent(); } - - public double getSmokeAlpha() { - return smokeColor.getAlpha() / 255f; - } + public void setSmokeAlpha(double alpha) { smokeColor.setAlpha((int) (alpha * 255)); fireChangeEvent(); } + + public double getSmokeOpacity() { + return smokeColor.getAlpha() / 255f; + } + + public void setSmokeOpacity(double smokeOpacity) { + setSmokeAlpha(smokeOpacity); + } public boolean isSparks() { return sparks; @@ -271,13 +274,4 @@ public class PhotoSettings extends AbstractChangeSource implements FlameSettings this.sparkWeight = sparkWeight; fireChangeEvent(); } - - public double getSmokeOpacity() { - return smokeOpacity; - } - - public void setSmokeOpacity(double smokeOpacity) { - this.smokeOpacity = smokeOpacity; - setSmokeAlpha(smokeOpacity); - } } \ No newline at end of file diff --git a/swing/src/net/sf/openrocket/gui/figure3d/photo/exhaust/FlameRenderer.java b/swing/src/net/sf/openrocket/gui/figure3d/photo/exhaust/FlameRenderer.java index 8980ea0e6..524324ff2 100644 --- a/swing/src/net/sf/openrocket/gui/figure3d/photo/exhaust/FlameRenderer.java +++ b/swing/src/net/sf/openrocket/gui/figure3d/photo/exhaust/FlameRenderer.java @@ -152,8 +152,6 @@ public final class FlameRenderer { public Color getSmokeColor(); - public double getSmokeAlpha(); - public double getFlameAspectRatio(); public boolean isSparks(); diff --git a/swing/src/net/sf/openrocket/gui/main/DocumentSelectionModel.java b/swing/src/net/sf/openrocket/gui/main/DocumentSelectionModel.java index 5d9277df7..54848a521 100644 --- a/swing/src/net/sf/openrocket/gui/main/DocumentSelectionModel.java +++ b/swing/src/net/sf/openrocket/gui/main/DocumentSelectionModel.java @@ -2,6 +2,7 @@ package net.sf.openrocket.gui.main; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -90,7 +91,7 @@ public class DocumentSelectionModel { * @return the currently selected rocket components, or null. */ public List getSelectedComponents() { - if (componentSelection.size() == 0) return null; + if (componentSelection.size() == 0) return Collections.emptyList(); return componentSelection; } diff --git a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java index 423f23d25..9f702dd22 100644 --- a/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/SimulationPanel.java @@ -183,22 +183,19 @@ public class SimulationPanel extends JPanel { @Override public void mouseClicked(MouseEvent e) { int selectedRow = simulationTable.getSelectedRow(); + int row = simulationTable.rowAtPoint(e.getPoint()); + int column = simulationTable.columnAtPoint(e.getPoint()); + + // Clear the table selection when clicked outside the table rows. + if (row == -1 || column == -1 || selectedRow == -1) { + simulationTable.clearSelection(); + return; + } if (e.getButton() == MouseEvent.BUTTON1) { - // Clear the table selection when clicked outside the table rows. - if (e.getClickCount() == 1) { - int row = simulationTable.rowAtPoint(e.getPoint()); - int column = simulationTable.columnAtPoint(e.getPoint()); - - if (row == -1 || column == -1) { - simulationTable.clearSelection(); - } - } // Edit the simulation or plot/export - else if (e.getClickCount() == 2) { + if (e.getClickCount() == 2) { int selected = simulationTable.convertRowIndexToModel(selectedRow); - - int column = simulationTable.columnAtPoint(e.getPoint()); if (column == 0) { SimulationWarningDialog.showWarningDialog(SimulationPanel.this, document.getSimulations().get(selected)); } else { diff --git a/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java b/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java index 9bcb0253f..9900305b4 100644 --- a/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java +++ b/swing/src/net/sf/openrocket/gui/plot/SimulationPlot.java @@ -427,6 +427,7 @@ public class SimulationPlot { // Plot the markers if (config.getDomainAxisType() == FlightDataType.TYPE_TIME) { + double markerWidth = 0.01 * plot.getDomainAxis().getUpperBound(); // Domain time is plotted as vertical markers for (int i = 0; i < eventTimes.size(); i++) { @@ -441,6 +442,10 @@ public class SimulationPlot { m.setAlpha(0.7f); m.setLabelFont(new Font("Dialog", Font.PLAIN, 13)); plot.addDomainMarker(m); + + if (t > plot.getDomainAxis().getUpperBound() - markerWidth) { + plot.setDomainAxis(new PresetNumberAxis(plot.getDomainAxis().getLowerBound(), t + markerWidth)); + } } } else { diff --git a/swing/src/net/sf/openrocket/startup/OSXSetup.java b/swing/src/net/sf/openrocket/startup/OSXSetup.java index e16ac9716..4023875d2 100644 --- a/swing/src/net/sf/openrocket/startup/OSXSetup.java +++ b/swing/src/net/sf/openrocket/startup/OSXSetup.java @@ -7,6 +7,7 @@ import java.awt.desktop.PreferencesHandler; import java.awt.desktop.QuitHandler; import java.awt.desktop.AppReopenedListener; +import net.sf.openrocket.communication.UpdateInfoRetriever; import net.sf.openrocket.gui.util.DummyFrameMenuOSX; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,6 +57,10 @@ final class OSXSetup { if (BasicFrame.isFramesEmpty()) { log.info("App re-opened"); BasicFrame.reopen(); + + // Also check for software updates + final UpdateInfoRetriever updateRetriever = SwingStartup.startUpdateChecker(); + SwingStartup.checkUpdateStatus(updateRetriever); } }; diff --git a/swing/src/net/sf/openrocket/startup/SwingStartup.java b/swing/src/net/sf/openrocket/startup/SwingStartup.java index 462549e11..954abcc44 100644 --- a/swing/src/net/sf/openrocket/startup/SwingStartup.java +++ b/swing/src/net/sf/openrocket/startup/SwingStartup.java @@ -193,15 +193,7 @@ public class SwingStartup { guiModule.startLoader(); // Start update info fetching - final UpdateInfoRetriever updateRetriever; - if (Application.getPreferences().getCheckUpdates()) { - log.info("Starting update check"); - updateRetriever = new UpdateInfoRetriever(); - updateRetriever.startFetchUpdateInfo(); - } else { - log.info("Update check disabled"); - updateRetriever = null; - } + final UpdateInfoRetriever updateRetriever = startUpdateChecker(); // Set the best available look-and-feel log.info("Setting best LAF"); @@ -248,9 +240,21 @@ public class SwingStartup { } } + + public static UpdateInfoRetriever startUpdateChecker() { + final UpdateInfoRetriever updateRetriever; + if (Application.getPreferences().getCheckUpdates()) { + log.info("Starting update check"); + updateRetriever = new UpdateInfoRetriever(); + updateRetriever.startFetchUpdateInfo(); + } else { + log.info("Update check disabled"); + updateRetriever = null; + } + return updateRetriever; + } - - private void checkUpdateStatus(final UpdateInfoRetriever updateRetriever) { + public static void checkUpdateStatus(final UpdateInfoRetriever updateRetriever) { if (updateRetriever == null) return; @@ -268,10 +272,12 @@ public class SwingStartup { if (!updateRetriever.isRunning()) { timer.stop(); + final SwingPreferences preferences = (SwingPreferences) Application.getPreferences(); UpdateInfo info = updateRetriever.getUpdateInfo(); // Only display something when an update is found - if (info != null && info.getException() == null && info.getReleaseStatus() == ReleaseStatus.OLDER) { + if (info != null && info.getException() == null && info.getReleaseStatus() == ReleaseStatus.OLDER && + !preferences.getIgnoreVersions().contains(info.getLatestRelease().getReleaseName())) { UpdateInfoDialog infoDialog = new UpdateInfoDialog(info); infoDialog.setVisible(true); }