diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index f3a06a816..823d24092 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -1,6 +1,20 @@
+
+
+
+
+
Release Notes
=============
+
+
+
+
OpenRocket 22.02.beta.05 (2022-09-28)
------------------------
(through PR1688)
@@ -66,6 +80,10 @@ OpenRocket 22.02.beta.05 (2022-09-28)
* Fixed overlapping labels in motor selection diameter filter slider (fixes #1643)
* More Russian translation updates
+
+
+
+
OpenRocket 22.02.beta.04 (2022-06-17)
------------------------
(through PR1456)
@@ -102,6 +120,9 @@ However, the JAR file will still allow Java 11 *or* 17, so if you want to keep e
* Updated guided tours
* Improved Russian translation
+
+
+
OpenRocket 22.02.beta.03 (2022-05-18)
------------------------
@@ -131,6 +152,10 @@ OpenRocket 22.02.beta.03 (2022-05-18)
* Improved time step selection for descent
* Java 17 is now included in the packaged installers and supported by the JAR file.
+
+
+
+
OpenRocket 22.02.beta.02 (2022-03-26)
------------------------
(through PR1261)
@@ -161,6 +186,9 @@ NOTE: Tube fin simulation is currently broken, and will be fixed in a future bet
* Set default color for all components to #BBBBBB, with Shine=30 (closes issue 1192)
* Update Mac installer style to more standard "drag app to Applications folder"
+
+
+
OpenRocket 22.02.beta.01 (2022-02-25)
------------------------
@@ -239,6 +267,10 @@ OpenRocket 22.02.beta.01 (2022-02-25)
..._plus many, many additional bug fixes and refinements_
+
+
+
+
OpenRocket 15.03 (2015-03-28)
-----------------------------
@@ -258,6 +290,10 @@ Bug Fixes
* Always use the correct filename extension when saving
+
+
+
+
OpenRocket 14.11 (2014-11-02)
-----------------------------
@@ -269,6 +305,10 @@ Bug Fixes
* Fixed a couple of bugs.
+
+
+
+
OpenRocket 14.06 (2014-06-25)
-----------------------------
@@ -282,6 +322,10 @@ Bug Fixes
* Fixed annoying IndexOutOfBounds bug in tables.
+
+
+
+
OpenRocket 14.05 (2014-05-21)
-----------------------------
@@ -296,6 +340,10 @@ Bug Fixes
* Updated thrustcurves
* Updated 3d libraries to 2.1.5
+
+
+
+
OpenRocket 14.03 (2014-03-20)
-----------------------------
@@ -308,6 +356,10 @@ Bug Fixes
* Fixes to the flight configuration tab and motor selection dialog
* Updated thrustcurves
+
+
+
+
OpenRocket 13.11.2 (2014-01-01)
-------------------------------
@@ -318,6 +370,10 @@ Bug Fixes
* Fix couple of layout issues
* Updated Spanish, French and Chinese translations
+
+
+
+
OpenRocket 13.11.1 (2013-11-15)
-------------------------------
@@ -329,6 +385,10 @@ Bug Fixes
* Fixed various exceptions in flight configuration tables due to column reordering
* Fixed NPE when deleting a configuration
+
+
+
+
OpenRocket 13.11 (2013-11-08)
------------------------------
@@ -343,6 +403,10 @@ Bug Fixes
* Updated jogl to correct 3d problems on various platforms
* Fixed NPE introduced by changes in Java 1.7.0_45-b18
+
+
+
+
OpenRocket 13.09.1 (2013-10-05)
-------------------------------
@@ -350,6 +414,9 @@ This release contains a number of bug fixes, updated 3D JOGL
libraries. Added preliminary thrustcurves for Aerotech C3 and D2 18mm
reloads.
+
+
+
OpenRocket 13.09 (2013-09-08)
-----------------------------
@@ -357,6 +424,9 @@ OpenRocket 13.09 (2013-09-08)
This release contains a number of bug fixes, updated 3D JOGL
libraries, and separates simulation edit and plot dialogs.
+
+
+
OpenRocket 13.05 (2013-05-04)
-----------------------------
@@ -384,6 +454,9 @@ New Features
scroll with mouse wheel. If the alt key is used with either of these, only the domain is zoomed. Richard
contributed a more logical mouse controlled zoom - right click and drag will zoom (either domain, range or both).
+
+
+
OpenRocket 12.09.1 (2012-06-28)
-------------------------------
@@ -392,6 +465,9 @@ Bug-fix release for 12.09, fixing numerous bugs. Only new feature is
the possiblity to automatically open the latest design file on startup
(in Edit -> Preferences -> Options).
+
+
+
OpenRocket 12.09 (2012-09-16)
------------------------------
@@ -411,6 +487,9 @@ Numerous new features by many contributors
- Calibration rulers added to printed templates
- Translations in Czech and Polish, numerous updates
+
+
+
OpenRocket 12.03 (2012-03-17)
------------------------------
@@ -430,6 +509,9 @@ release you can open files and examine existing simulations, stability
data and motor files. The Android port is thanks to work by Kevin
Ruland.
+
+
+
OpenRocket 1.1.9 (2011-11-24)
------------------------------
@@ -440,6 +522,9 @@ to work by Richard Graham. Printing of transitions, nose cone
profiles and fin marking guides is available thanks to Doug Pedrick.
It also contains some usability features and bug fixes.
+
+
+
OpenRocket 1.1.8 (2011-08-25)
------------------------------
@@ -448,6 +533,9 @@ This release contains bug fixes to the optimization methods.
It also contains a workaround to a JRE bug that prevents running
OpenRocket on Java 7.
+
+
+
OpenRocket 1.1.7 (2011-08-12)
------------------------------
@@ -456,6 +544,9 @@ This release contains automatic rocket design optimization
functionality. However, be cautious when using it and take the
results with a grain of salt.
+
+
+
OpenRocket 1.1.6 (2011-07-22)
------------------------------
@@ -465,6 +556,9 @@ translations by Tripoli Spain, Tripoli France and Stefan Lobas
(ERIG e.V.). The release also contains rocket design scaling support
and numerous bug fixes.
+
+
+
OpenRocket 1.1.5 (2011-06-10)
------------------------------
@@ -473,12 +567,18 @@ Removed native printing support. Printing is now handled via PDF
viewer, which should make printing much more reliable and less
bug-prone.
+
+
+
OpenRocket 1.1.4 (2011-03-05)
------------------------------
Initial printing support by Doug Pedrick, and various bug fixes.
+
+
+
OpenRocket 1.1.3 (2010-10-06)
------------------------------
@@ -486,12 +586,18 @@ OpenRocket 1.1.3 (2010-10-06)
Support for drag-drop moving and copying of components. Fixes a
severe bug in the undo system.
+
+
+
OpenRocket 1.1.2 (2010-09-07)
------------------------------
Fixes a severe bug that prevented adding stages to rockets.
+
+
+
OpenRocket 1.1.1 (2010-09-03)
------------------------------
@@ -501,6 +607,9 @@ curve loading and selection, faster startup time and bug fixes.
Old simulation listeners are incompatible with this release.
+
+
+
OpenRocket 1.1.0 (2010-03-21)
------------------------------
@@ -508,6 +617,9 @@ OpenRocket 1.1.0 (2010-03-21)
Support for loading RockSim rocket design files (.rkt) thanks to
Doug Pedrick.
+
+
+
OpenRocket 1.0.0 (2010-03-10)
------------------------------
@@ -515,6 +627,9 @@ OpenRocket 1.0.0 (2010-03-10)
Added numerous new motor thrustcurves from thrustcurve.org, and fixed
a few more bugs.
+
+
+
OpenRocket 0.9.6 (2010-02-17)
------------------------------
@@ -523,6 +638,9 @@ Updated aerodynamic calculation methods to be more in line with the
Barrowman method and enhanced simulation time step selection. Fixed
numerous bugs.
+
+
+
OpenRocket 0.9.5 (2009-11-28)
------------------------------
@@ -530,6 +648,9 @@ OpenRocket 0.9.5 (2009-11-28)
Fixed a serious defect which prevented adding a tube coupler and
centering ring on the same body tube. Other minor improvements.
+
+
+
OpenRocket 0.9.4 (2009-11-24)
------------------------------
@@ -538,6 +659,9 @@ Added through-the-wall fin tabs, attaching components to tube
couplers, material editing and automatic update checks, and fixed
numerous of the most commonly occurring bugs.
+
+
+
OpenRocket 0.9.3 (2009-09-01)
------------------------------
@@ -546,6 +670,9 @@ Numerous bug fixes and enhancements including data exporting, showing
flight events in plots, example rocket designs, splitting clustered
inner tubes and automated bug reporting.
+
+
+
OpenRocket 0.9.2 (2009-07-13)
------------------------------
@@ -554,6 +681,9 @@ Fixed imperial unit conversions. Significant UI enhancements to the
motor configuration edit dialog, motor selection dialog and file
open/save.
+
+
+
OpenRocket 0.9.1 (2009-06-09)
------------------------------
@@ -561,8 +691,14 @@ OpenRocket 0.9.1 (2009-06-09)
Bug fixes to file dialog and saving; initial support for cut/copy/paste
of simulations.
+
+
+
OpenRocket 0.9.0 (2009-05-24)
------------------------------
Initial release.
+
+
+
\ No newline at end of file
diff --git a/core/build.xml b/core/build.xml
index 007c10508..01893b763 100644
--- a/core/build.xml
+++ b/core/build.xml
@@ -1,7 +1,8 @@
-
+
+
@@ -34,6 +35,7 @@
+
diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties
index 3ecbb3271..919c15396 100644
--- a/core/resources/l10n/messages.properties
+++ b/core/resources/l10n/messages.properties
@@ -356,6 +356,13 @@ generalprefs.lbl.language = Interface language
generalprefs.languages.default = System default
generalprefs.lbl.languageEffect = The language will change the next time you start OpenRocket.
+! Welcome dialog
+welcome.dlg.title = Welcome to OpenRocket
+welcome.dlg.lbl.thankYou = Thank you for downloading OpenRocket
+welcome.dlg.lbl.seeReleaseNotes = See the release notes below to find what's new.
+welcome.dlg.checkbox.dontShowAgain = Don't show this dialog again
+welcome.dlg.btn.close.ttip = Cool! Now leave me alone\u2026
+
! Software update checker
update.dlg.error.title = Unable to retrieve update information
update.dlg.error = An error occurred while communicating with the server.
@@ -366,6 +373,8 @@ 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.lbl.title = A new version of OpenRocket is available!
+update.dlg.btn.remindMeLater = Remind Me Later
+update.dlg.checkbox.skipThisVersion = Skip This Version
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
diff --git a/core/src/net/sf/openrocket/communication/Communicator.java b/core/src/net/sf/openrocket/communication/Communicator.java
index f762f0239..45fef263f 100644
--- a/core/src/net/sf/openrocket/communication/Communicator.java
+++ b/core/src/net/sf/openrocket/communication/Communicator.java
@@ -9,7 +9,7 @@ public abstract class Communicator {
protected static final String BUG_REPORT_URL;
protected static final String UPDATE_URL;
- protected static final String UPDATE_ADDITIONAL_URL; // Extra URL needed for the update checker
+ protected static final String UPDATE_URL_LATEST; // Extra URL needed for the latest GitHub release
static {
String url;
@@ -21,10 +21,10 @@ public abstract class Communicator {
url = System.getProperty("openrocket.debug.updateurl");
if (url == null) {
url = "https://api.github.com/repos/openrocket/openrocket/releases";
- UPDATE_ADDITIONAL_URL = "https://api.github.com/repos/openrocket/openrocket/releases/latest";
+ UPDATE_URL_LATEST = "https://api.github.com/repos/openrocket/openrocket/releases/latest";
}
else {
- UPDATE_ADDITIONAL_URL = null;
+ UPDATE_URL_LATEST = null;
}
UPDATE_URL = url;
}
diff --git a/core/src/net/sf/openrocket/communication/GitHubAPIUtil.java b/core/src/net/sf/openrocket/communication/GitHubAPIUtil.java
new file mode 100644
index 000000000..7800baee5
--- /dev/null
+++ b/core/src/net/sf/openrocket/communication/GitHubAPIUtil.java
@@ -0,0 +1,112 @@
+package net.sf.openrocket.communication;
+
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.startup.Application;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.json.Json;
+import javax.json.JsonReader;
+import javax.json.stream.JsonParsingException;
+import javax.net.ssl.HttpsURLConnection;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.net.ConnectException;
+import java.net.MalformedURLException;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.Map;
+
+/**
+ * Utility functions for the GitHub API.
+ */
+public class GitHubAPIUtil {
+ private static final Logger log = LoggerFactory.getLogger(GitHubAPIUtil.class);
+ private static final Translator trans = Application.getTranslator();
+
+ /**
+ * Generate a URL with a set of parameters included.
+ * E.g. url = github.com/openrocket/openrocket/releases, params = {"lorem", "ipsum"}
+ * => formatted url: github.com/openrocket/openrocket/releases?lorem=ipsum
+ * @param url base URL
+ * @param params parameters to include
+ * @return formatted URL (= base URL with parameters)
+ */
+ public static String generateUrlWithParameters(String url, Map params) {
+ StringBuilder formattedUrl = new StringBuilder(url);
+ formattedUrl.append("?"); // Identifier for start of query string (for parameters)
+
+ // Append the parameters to the URL
+ int idx = 0;
+ for (Map.Entry e : params.entrySet()) {
+ formattedUrl.append(String.format("%s=%s", e.getKey(), e.getValue()));
+ if (idx < params.size() - 1) {
+ formattedUrl.append("&"); // Identifier for more parameters
+ }
+ idx++;
+ }
+ return formattedUrl.toString();
+ }
+
+ /**
+ * Fetches the JSON info from the specified GitHub API URL.
+ * @param urlLink GitHub API link of the desired releases
+ * @return JSON-formatted string (can be a JSON-array or JSON-object)
+ * @throws Exception if an error occurred (e.g. no internet connection)
+ */
+ public static String fetchPageInfo(String urlLink) throws Exception {
+ HttpsURLConnection connection = null;
+ try {
+ // Set up connection info to the GitHub release page
+ URL url = new URL(urlLink);
+ connection = (HttpsURLConnection) url.openConnection();
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Accept", "application/json");
+ connection.setUseCaches(false);
+ connection.setAllowUserInteraction(false);
+ connection.setConnectTimeout(Communicator.CONNECTION_TIMEOUT);
+ connection.setReadTimeout(Communicator.CONNECTION_TIMEOUT);
+
+ // Connect to the GitHub page and get the status response code
+ connection.connect();
+ int status = connection.getResponseCode();
+ log.debug("Update checker response code: " + status);
+
+ // Invalid response code
+ if (status != 200) {
+ log.warn(String.format("Bad response code from server: %d", status));
+ throw new Exception(String.format(trans.get("update.fetcher.badResponse"), status));
+ }
+
+ // Read the response JSON data into a StringBuilder
+ StringBuilder sb = new StringBuilder();
+ BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+ String line;
+ while ((line = br.readLine()) != null) {
+ sb.append(line).append("\n");
+ }
+ br.close();
+
+ return sb.toString();
+ } catch (UnknownHostException | SocketTimeoutException | ConnectException e) {
+ log.warn(String.format("Could not connect to URL: %s. Please check your internet connection.", urlLink));
+ throw new Exception(trans.get("update.fetcher.badConnection"));
+ } catch (MalformedURLException e) {
+ log.warn("Malformed URL: " + urlLink);
+ throw new Exception(String.format(trans.get("update.fetcher.malformedURL"), urlLink));
+ } catch (IOException e) {
+ throw new Exception(String.format("Exception - %s: %s", e, e.getMessage()));
+ } finally { // Close the connection to the release page
+ if (connection != null) {
+ try {
+ connection.disconnect();
+ } catch (Exception ex) {
+ log.warn("Could not disconnect update checker connection");
+ }
+ }
+ }
+ }
+}
diff --git a/core/src/net/sf/openrocket/communication/ReleaseNotesHandler.java b/core/src/net/sf/openrocket/communication/ReleaseNotesHandler.java
new file mode 100644
index 000000000..ca24fd731
--- /dev/null
+++ b/core/src/net/sf/openrocket/communication/ReleaseNotesHandler.java
@@ -0,0 +1,56 @@
+package net.sf.openrocket.communication;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.AbstractElementHandler;
+import net.sf.openrocket.file.simplesax.ElementHandler;
+import net.sf.openrocket.file.simplesax.PlainTextHandler;
+import org.xml.sax.SAXException;
+
+import java.util.HashMap;
+import java.util.Objects;
+
+/**
+ * Class that parses ReleaseNotes.md.
+ *
+ * Releases are stored in an HTML
object with as id attribute the release version.
+ * E.g.
...
+ * The content of the div is the release notes for that version.
+ */
+public class ReleaseNotesHandler extends AbstractElementHandler {
+ private final String buildVersion;
+ private String releaseNotes = null;
+
+ /**
+ * @param buildVersion the build version to search the release notes for (e.g. "22.02")
+ */
+ public ReleaseNotesHandler(String buildVersion) {
+ this.buildVersion = buildVersion;
+ }
+
+ @Override
+ public ElementHandler openElement(String element, HashMap
attributes, WarningSet warnings) throws SAXException {
+ if (element.equals("body")) { // The release notes are encapsulated in a root tag (required for XML parsing)
+ return this;
+ }
+ if (element.equals("div") && Objects.equals(attributes.get("id"), this.buildVersion)) {
+ return PlainTextHandler.INSTANCE;
+ }
+ return null;
+ }
+
+ @Override
+ public void closeElement(String element, HashMap attributes, String content, WarningSet warnings) throws SAXException {
+ super.closeElement(element, attributes, content, warnings);
+
+ if (element.equals("div")) {
+ this.releaseNotes = content.trim();
+ }
+ }
+
+ /**
+ * @return the release notes for the build version
+ */
+ public String getReleaseNotes() {
+ return releaseNotes;
+ }
+}
diff --git a/core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java b/core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java
index 692df1834..d587f1c1c 100644
--- a/core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java
+++ b/core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java
@@ -1,14 +1,6 @@
package net.sf.openrocket.communication;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
import java.io.StringReader;
-import java.net.ConnectException;
-import java.net.MalformedURLException;
-import java.net.SocketTimeoutException;
-import java.net.URL;
-import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -31,7 +23,6 @@ import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.stream.JsonParsingException;
-import javax.net.ssl.HttpsURLConnection;
/**
* Class that initiates fetching software update information.
@@ -79,7 +70,7 @@ public class UpdateInfoRetriever {
*/
public boolean isRunning() {
if (this.fetcher == null) {
- throw new IllegalStateException("startFetchUpdateInfo() has not been called");
+ throw new IllegalStateException("Fetcher has not been called yet");
}
return this.fetcher.isAlive();
}
@@ -100,7 +91,7 @@ public class UpdateInfoRetriever {
*/
public UpdateInfo getUpdateInfo() {
if (this.fetcher == null) {
- throw new IllegalStateException("startFetchUpdateInfo() has not been called");
+ throw new IllegalStateException("Fetcher has not been called yet");
}
return this.fetcher.info;
}
@@ -175,15 +166,15 @@ public class UpdateInfoRetriever {
// Get release tags from release page
String relUrl = Communicator.UPDATE_URL;
- relUrl = generateUrlWithParameters(relUrl, params);
+ relUrl = GitHubAPIUtil.generateUrlWithParameters(relUrl, params);
JsonArray arr1 = retrieveReleaseJSONArr(relUrl);
if (arr1 == null) return null;
- if (Communicator.UPDATE_ADDITIONAL_URL == null) return arr1;
+ if (Communicator.UPDATE_URL_LATEST == null) return arr1;
// Get release tags from latest release page
- String latestRelUrl = Communicator.UPDATE_ADDITIONAL_URL;
- latestRelUrl = generateUrlWithParameters(latestRelUrl, params);
+ String latestRelUrl = Communicator.UPDATE_URL_LATEST;
+ latestRelUrl = GitHubAPIUtil.generateUrlWithParameters(latestRelUrl, params);
JsonArray arr2 = retrieveReleaseJSONArr(latestRelUrl);
if (arr2 == null) return null;
@@ -209,72 +200,25 @@ public class UpdateInfoRetriever {
* @throws UpdateCheckerException if an error occurred (e.g. no internet connection)
*/
private JsonArray retrieveReleaseJSONArr(String urlLink) throws UpdateCheckerException {
- JsonArray jsonArr;
-
- HttpsURLConnection connection = null;
try {
- // Set up connection info to the GitHub release page
- URL url = new URL(urlLink);
- connection = (HttpsURLConnection) url.openConnection();
- connection.setRequestMethod("GET");
- connection.setRequestProperty("Accept", "application/json");
- connection.setUseCaches(false);
- connection.setAllowUserInteraction(false);
- connection.setConnectTimeout(Communicator.CONNECTION_TIMEOUT);
- connection.setReadTimeout(Communicator.CONNECTION_TIMEOUT);
+ String pageInfo = GitHubAPIUtil.fetchPageInfo(urlLink);
- // Connect to the GitHub page and get the status response code
- connection.connect();
- int status = connection.getResponseCode();
- log.debug("Update checker response code: " + status);
-
- // Invalid response code
- if (status != 200) {
- log.warn(String.format("Bad response code from server: %d", status));
- throw new UpdateCheckerException(String.format(trans.get("update.fetcher.badResponse"), status));
- }
-
- // Read the response JSON data into a StringBuilder
- StringBuilder sb = new StringBuilder();
- BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
- String line;
- while ((line = br.readLine()) != null) {
- sb.append(line).append("\n");
- }
- br.close();
-
- // Read the release page as a JSON array
- JsonReader reader = Json.createReader(new StringReader(sb.toString()));
+ // Read the release page as a JSON object
+ JsonReader reader = Json.createReader(new StringReader(pageInfo));
// The reader-content can be a JSON array or just a JSON object
try { // Case: JSON array
- jsonArr = reader.readArray();
+ return reader.readArray();
} catch (JsonParsingException e) { // Case: JSON object
JsonArrayBuilder builder = Json.createArrayBuilder();
- reader = Json.createReader(new StringReader(sb.toString()));
+ reader = Json.createReader(new StringReader(pageInfo));
JsonObject obj = reader.readObject();
builder.add(obj);
- jsonArr = builder.build();
- }
- } catch (UnknownHostException | SocketTimeoutException | ConnectException e) {
- log.warn(String.format("Could not connect to URL: %s. Please check your internet connection.", urlLink));
- throw new UpdateCheckerException(trans.get("update.fetcher.badConnection"));
- } catch (MalformedURLException e) {
- log.warn("Malformed URL: " + urlLink);
- throw new UpdateCheckerException(String.format(trans.get("update.fetcher.malformedURL"), urlLink));
- } catch (IOException e) {
- throw new UpdateCheckerException(String.format("Exception - %s: %s", e, e.getMessage()));
- } finally { // Close the connection to the release page
- if (connection != null) {
- try {
- connection.disconnect();
- } catch (Exception ex) {
- log.warn("Could not disconnect update checker connection");
- }
+ return builder.build();
}
+ } catch (Exception e) {
+ throw new UpdateCheckerException(e);
}
-
- return jsonArr;
}
/**
@@ -494,30 +438,6 @@ public class UpdateInfoRetriever {
}
}
- /**
- * Generate a URL with a set of parameters included.
- * E.g. url = github.com/openrocket/openrocket/releases, params = {"lorem", "ipsum"}
- * => formatted url: github.com/openrocket/openrocket/releases?lorem=ipsum
- * @param url base URL
- * @param params parameters to include
- * @return formatted URL (= base URL with parameters)
- */
- private String generateUrlWithParameters(String url, Map params) {
- StringBuilder formattedUrl = new StringBuilder(url);
- formattedUrl.append("?"); // Identifier for start of query string (for parameters)
-
- // Append the parameters to the URL
- int idx = 0;
- for (Map.Entry e : params.entrySet()) {
- formattedUrl.append(String.format("%s=%s", e.getKey(), e.getValue()));
- if (idx < params.size() - 1) {
- formattedUrl.append("&"); // Identifier for more parameters
- }
- idx++;
- }
- return formattedUrl.toString();
- }
-
/**
* Exception for the update checker
*/
@@ -525,6 +445,10 @@ public class UpdateInfoRetriever {
public UpdateCheckerException(String message) {
super(message);
}
+
+ public UpdateCheckerException(Throwable cause) {
+ super(cause);
+ }
}
}
}
diff --git a/core/src/net/sf/openrocket/communication/WelcomeInfoRetriever.java b/core/src/net/sf/openrocket/communication/WelcomeInfoRetriever.java
new file mode 100644
index 000000000..6b4c579d6
--- /dev/null
+++ b/core/src/net/sf/openrocket/communication/WelcomeInfoRetriever.java
@@ -0,0 +1,47 @@
+package net.sf.openrocket.communication;
+
+import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.file.simplesax.SimpleSAX;
+import net.sf.openrocket.util.BuildProperties;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+public abstract class WelcomeInfoRetriever {
+ /**
+ * Retrieves the release notes of the current build version from the ReleaseNotes.md file.
+ * @param version the build version to search the release notes for (e.g. "22.02")
+ * @return the release notes of the current build version
+ * @throws IOException if the file could not be read
+ */
+ public static String retrieveWelcomeInfo(String version) throws IOException {
+ ClassLoader cl = WelcomeInfoRetriever.class.getClassLoader();
+ InputStream in = cl.getResourceAsStream("ReleaseNotes.md");
+ if (in == null) {
+ throw new FileNotFoundException("ReleaseNotes.md not found");
+ }
+ InputSource source = new InputSource(new InputStreamReader(in));
+ ReleaseNotesHandler handler = new ReleaseNotesHandler(version);
+ WarningSet warnings = new WarningSet();
+
+ try {
+ SimpleSAX.readXML(source, handler, warnings);
+ return handler.getReleaseNotes();
+ } catch (SAXException e) {
+ throw new IOException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Retrieves the release notes of the current build version from the ReleaseNotes.md file.
+ * @return the release notes of the current build version
+ * @throws IOException if the file could not be read
+ */
+ public static String retrieveWelcomeInfo() throws IOException {
+ return retrieveWelcomeInfo(BuildProperties.getVersion());
+ }
+}
diff --git a/core/src/net/sf/openrocket/startup/Preferences.java b/core/src/net/sf/openrocket/startup/Preferences.java
index be58fb2a5..26b9b1095 100644
--- a/core/src/net/sf/openrocket/startup/Preferences.java
+++ b/core/src/net/sf/openrocket/startup/Preferences.java
@@ -55,10 +55,12 @@ public abstract class Preferences implements ChangeSource {
public static final String USER_LOCAL = "locale";
public static final String PLOT_SHOW_POINTS = "ShowPlotPoints";
-
+
+ private static final String IGNORE_WELCOME = "IgnoreWelcome";
+
private static final String CHECK_UPDATES = "CheckUpdates";
- private static final String IGNORE_VERSIONS = "IgnoreVersions";
+ private static final String IGNORE_UPDATE_VERSIONS = "IgnoreUpdateVersions";
private static final String CHECK_BETA_UPDATES = "CheckBetaUpdates";
public static final String MOTOR_DIAMETER_FILTER = "MotorDiameterMatch";
@@ -141,9 +143,31 @@ public abstract class Preferences implements ChangeSource {
public abstract void putString(String directory, String key, String value);
public abstract java.util.prefs.Preferences getNode(String nodeName);
-
+
/*
- * ******************************************************************************************
+ * Welcome dialog
+ */
+
+ /**
+ * Sets to ignore opening the welcome dialog for the supplied OpenRocket build version.
+ * @param version build version to ignore opening the welcome dialog for (e.g. "22.02")
+ * @param ignore true to ignore, false to show the welcome dialog
+ */
+ public final void setIgnoreWelcome(String version, boolean ignore) {
+ this.putBoolean(IGNORE_WELCOME + "_" + version, ignore);
+ }
+
+ /**
+ * Returns whether to ignore opening the welcome dialog for the supplied OpenRocket build version.
+ * @param version build version (e.g. "22.02")
+ * @return true if no welcome dialog should be opened for the supplied version
+ */
+ public final boolean getIgnoreWelcome(String version) {
+ return this.getBoolean(IGNORE_WELCOME + "_" + version, false);
+ }
+
+ /*
+ * Software updater
*/
public final boolean getCheckUpdates() {
return this.getBoolean(CHECK_UPDATES, BuildProperties.getDefaultCheckUpdates());
@@ -153,12 +177,12 @@ 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 List getIgnoreUpdateVersions() {
+ return List.of(this.getString(IGNORE_UPDATE_VERSIONS, "").split("\n"));
}
- public final void setIgnoreVersions(List versions) {
- this.putString(IGNORE_VERSIONS, String.join("\n", versions));
+ public final void setIgnoreUpdateVersions(List versions) {
+ this.putString(IGNORE_UPDATE_VERSIONS, String.join("\n", versions));
}
public final boolean getCheckBetaUpdates() {
@@ -168,6 +192,11 @@ public abstract class Preferences implements ChangeSource {
public final void setCheckBetaUpdates(boolean check) {
this.putBoolean(CHECK_BETA_UPDATES, check);
}
+
+
+ /*
+ * ******************************************************************************************
+ */
public final boolean getConfirmSimDeletion() {
return this.getBoolean(CONFIRM_DELETE_SIMULATION, true);
diff --git a/core/test/net/sf/openrocket/communication/WelcomeInfoTest.java b/core/test/net/sf/openrocket/communication/WelcomeInfoTest.java
new file mode 100644
index 000000000..529c7ee23
--- /dev/null
+++ b/core/test/net/sf/openrocket/communication/WelcomeInfoTest.java
@@ -0,0 +1,27 @@
+package net.sf.openrocket.communication;
+
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class WelcomeInfoTest extends BaseTestCase {
+
+ /**
+ * Note: this unit test will fail if you don't run it using 'ant unittest', because otherwise
+ * it can't load the ReleaseNotes.md file.
+ */
+ @Test
+ public void testWelcomeInfo() throws Exception {
+ // Test the welcome info for the current build version
+ String welcomeInfo = WelcomeInfoRetriever.retrieveWelcomeInfo();
+ assertNotNull(welcomeInfo);
+ assertTrue(welcomeInfo.length() > 0);
+
+ // Test the release info for a bogus release version
+ welcomeInfo = WelcomeInfoRetriever.retrieveWelcomeInfo("bogus release");
+ assertNull(welcomeInfo);
+ }
+}
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java
index e00f96152..50b0ee066 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/UpdateInfoDialog.java
@@ -30,7 +30,6 @@ 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;
@@ -58,6 +57,7 @@ public class UpdateInfoDialog extends JDialog {
JPanel panel = new JPanel(new MigLayout("insets n n 8px n, fill"));
+ // OpenRocket logo on the left
panel.add(new JLabel(Icons.getScaledIcon(Icons.loadImageIcon("pix/icon/icon-about.png", "OpenRocket"), 0.6)),
"spany, top, gapright 20px, cell 0 0");
@@ -124,7 +124,7 @@ public class UpdateInfoDialog extends JDialog {
// Lower row buttons
//// Remind me later button
- JButton btnLater = new SelectColorButton("Remind Me Later");
+ JButton btnLater = new SelectColorButton(trans.get("update.dlg.btn.remindMeLater"));
btnLater.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -134,15 +134,15 @@ public class UpdateInfoDialog extends JDialog {
panel.add(btnLater, "skip 1, split 2");
//// Skip this version button
- JButton btnSkip = new SelectColorButton("Skip This Version");
+ JButton btnSkip = new SelectColorButton(trans.get("update.dlg.checkbox.skipThisVersion"));
btnSkip.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- List ignoreVersions = new ArrayList<>(preferences.getIgnoreVersions());
+ List ignoreVersions = new ArrayList<>(preferences.getIgnoreUpdateVersions());
String ignore = release.getReleaseName();
if (!ignoreVersions.contains(ignore)) {
ignoreVersions.add(ignore);
- preferences.setIgnoreVersions(ignoreVersions);
+ preferences.setIgnoreUpdateVersions(ignoreVersions);
}
UpdateInfoDialog.this.dispose();
}
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/WelcomeDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/WelcomeDialog.java
new file mode 100644
index 000000000..db19183c1
--- /dev/null
+++ b/swing/src/net/sf/openrocket/gui/dialogs/WelcomeDialog.java
@@ -0,0 +1,115 @@
+package net.sf.openrocket.gui.dialogs;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.gui.components.StyledLabel;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.Icons;
+import net.sf.openrocket.gui.widgets.SelectColorButton;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.BuildProperties;
+import net.sf.openrocket.util.MarkdownUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextPane;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import java.awt.Desktop;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+/**
+ * Dialog that opens when you start up OpenRocket. It will display the release notes of the current version.
+ */
+public class WelcomeDialog extends JDialog {
+ private static final Translator trans = Application.getTranslator();
+ private static final Logger log = LoggerFactory.getLogger(WelcomeDialog.class);
+
+ /**
+ * @param releaseNotes the release notes to display for the current version
+ */
+ public WelcomeDialog(String releaseNotes) {
+ super(null, trans.get("welcome.dlg.title"), ModalityType.APPLICATION_MODAL);
+
+ JPanel panel = new JPanel(new MigLayout("insets n n 8px n, fill"));
+
+ // OpenRocket logo on the left
+ panel.add(new JLabel(Icons.getScaledIcon(Icons.loadImageIcon("pix/icon/icon-about.png", "OpenRocket"), 0.6)),
+ "spany, top, gapright 20px, cell 0 0");
+
+ // Thank you for downloading!
+ panel.add(new StyledLabel(trans.get("welcome.dlg.lbl.thankYou") + " " + BuildProperties.getVersion() + "!",
+ 2, StyledLabel.Style.BOLD), "spanx, wrap");
+
+ // See the release notes below for what's new
+ panel.add(new StyledLabel(trans.get("welcome.dlg.lbl.seeReleaseNotes"),
+ 1, StyledLabel.Style.PLAIN), "skip 1, spanx, wrap para");
+
+ // Release notes
+ final JTextPane textPane = new JTextPane();
+ textPane.setEditable(false);
+ textPane.setContentType("text/html");
+ textPane.setMargin(new Insets(10, 10, 10, 10));
+ textPane.putClientProperty(JTextPane.HONOR_DISPLAY_PROPERTIES, true);
+
+ String sb = "" +
+ MarkdownUtil.toHtml(releaseNotes) + "
" +
+ "";
+ textPane.addHyperlinkListener(new HyperlinkListener() {
+ @Override
+ public void hyperlinkUpdate(HyperlinkEvent e) {
+ if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
+ Desktop desktop = Desktop.getDesktop();
+ try {
+ desktop.browse(e.getURL().toURI());
+ } catch (Exception ex) {
+ log.warn("Exception hyperlink: " + ex.getMessage());
+ }
+ }
+ }
+ });
+
+ textPane.setText(sb);
+ textPane.setCaretPosition(0); // Scroll to the top
+
+ panel.add(new JScrollPane(textPane), "skip 1, left, spanx, grow, push, gapbottom 6px, wrap");
+
+ // Don't show this dialog again
+ JCheckBox dontShowAgain = new JCheckBox(trans.get("welcome.dlg.checkbox.dontShowAgain"));
+ dontShowAgain.setSelected(Application.getPreferences().getIgnoreWelcome(BuildProperties.getVersion())); // Normally this should never be true, but just in case
+ panel.add(dontShowAgain, "skip 1");
+ dontShowAgain.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Application.getPreferences().setIgnoreWelcome(BuildProperties.getVersion(), dontShowAgain.isSelected());
+ }
+ });
+
+ // Close button
+ JButton closeBtn = new SelectColorButton(trans.get("button.close"));
+ closeBtn.setToolTipText(trans.get("welcome.dlg.btn.close.ttip"));
+ closeBtn.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ WelcomeDialog.this.dispose();
+ }
+ });
+ panel.add(closeBtn, "pushx, right, wrap");
+
+ panel.setPreferredSize(new Dimension(800, 600));
+ this.add(panel);
+
+ this.pack();
+ this.setLocationRelativeTo(null);
+ GUIUtil.setDisposableDialogOptions(this, closeBtn);
+ }
+}
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 440c21a03..9631603a1 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java
@@ -342,7 +342,7 @@ public class GeneralPreferencesPanel extends PreferencesPanel {
ReleaseInfo release = info.getLatestRelease();
// Do nothing if the release is part of the ignore versions
- if (preferences.getIgnoreVersions().contains(release.getReleaseName())) {
+ if (preferences.getIgnoreUpdateVersions().contains(release.getReleaseName())) {
return;
}
diff --git a/swing/src/net/sf/openrocket/startup/SwingStartup.java b/swing/src/net/sf/openrocket/startup/SwingStartup.java
index 954abcc44..4f00838c5 100644
--- a/swing/src/net/sf/openrocket/startup/SwingStartup.java
+++ b/swing/src/net/sf/openrocket/startup/SwingStartup.java
@@ -4,6 +4,7 @@ import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
+import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.stream.IntStream;
@@ -19,10 +20,11 @@ import net.sf.openrocket.arch.SystemInfo.Platform;
import net.sf.openrocket.communication.UpdateInfo;
import net.sf.openrocket.communication.UpdateInfoRetriever;
import net.sf.openrocket.communication.UpdateInfoRetriever.ReleaseStatus;
+import net.sf.openrocket.communication.WelcomeInfoRetriever;
import net.sf.openrocket.database.Databases;
import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
+import net.sf.openrocket.gui.dialogs.WelcomeDialog;
import net.sf.openrocket.gui.main.BasicFrame;
-import net.sf.openrocket.gui.main.MRUDesignFile;
import net.sf.openrocket.gui.main.Splash;
import net.sf.openrocket.gui.main.SwingExceptionHandler;
import net.sf.openrocket.gui.util.GUIUtil;
@@ -217,6 +219,7 @@ public class SwingStartup {
if (!handleCommandLine(args)) {
BasicFrame startupFrame = BasicFrame.reopen();
BasicFrame.setStartupFrame(startupFrame);
+ showWelcomeDialog();
}
// Check whether update info has been fetched or whether it needs more time
@@ -277,7 +280,7 @@ public class SwingStartup {
// Only display something when an update is found
if (info != null && info.getException() == null && info.getReleaseStatus() == ReleaseStatus.OLDER &&
- !preferences.getIgnoreVersions().contains(info.getLatestRelease().getReleaseName())) {
+ !preferences.getIgnoreUpdateVersions().contains(info.getLatestRelease().getReleaseName())) {
UpdateInfoDialog infoDialog = new UpdateInfoDialog(info);
infoDialog.setVisible(true);
}
@@ -290,6 +293,34 @@ public class SwingStartup {
timer.addActionListener(listener);
timer.start();
}
+
+ /**
+ * Shows a welcome dialog displaying the release notes for this build version.
+ */
+ public static void showWelcomeDialog() {
+ // Don't show if this build version is ignored
+ if (Application.getPreferences().getIgnoreWelcome(BuildProperties.getVersion())) {
+ log.debug("Welcome dialog ignored");
+ return;
+ }
+
+ // Fetch this version's release notes
+ String releaseNotes;
+ try {
+ releaseNotes = WelcomeInfoRetriever.retrieveWelcomeInfo();
+ } catch (IOException e) {
+ log.error("Error retrieving welcome info", e);
+ return;
+ }
+ if (releaseNotes == null) {
+ log.debug("No release notes found");
+ return;
+ }
+
+ // Show the dialog
+ WelcomeDialog dialog = new WelcomeDialog(releaseNotes);
+ dialog.setVisible(true);
+ }
/**
* Handles arguments passed from the command line. This may be used either