[#1768] Add a welcome dialog at start-up to show the release notes
This commit is contained in:
parent
7ce87f099e
commit
faa7e43891
@ -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.
|
||||
|
@ -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.
|
||||
* <p>
|
||||
* Releases are stored in an HTML <div> object with as id attribute the release version.
|
||||
* E.g. <div id="15.03">...</div>
|
||||
* 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<String, String> attributes, WarningSet warnings) throws SAXException {
|
||||
if (element.equals("body")) { // The release notes are encapsulated in a root <body> 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<String, String> 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
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.FileInputStream;
|
||||
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.
|
||||
* @return the release notes of the current build version
|
||||
* @throws IOException if the file could not be read
|
||||
*/
|
||||
public static String retrieveWelcomeInfo() throws IOException {
|
||||
InputStream in = new FileInputStream("ReleaseNotes.md");
|
||||
InputSource source = new InputSource(new InputStreamReader(in));
|
||||
ReleaseNotesHandler handler = new ReleaseNotesHandler(BuildProperties.getVersion());
|
||||
WarningSet warnings = new WarningSet();
|
||||
|
||||
try {
|
||||
SimpleSAX.readXML(source, handler, warnings);
|
||||
return handler.getReleaseNotes();
|
||||
} catch (SAXException e) {
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
@ -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<String> getIgnoreVersions() {
|
||||
return List.of(this.getString(IGNORE_VERSIONS, "").split("\n"));
|
||||
public final List<String> getIgnoreUpdateVersions() {
|
||||
return List.of(this.getString(IGNORE_UPDATE_VERSIONS, "").split("\n"));
|
||||
}
|
||||
|
||||
public final void setIgnoreVersions(List<String> versions) {
|
||||
this.putString(IGNORE_VERSIONS, String.join("\n", versions));
|
||||
public final void setIgnoreUpdateVersions(List<String> 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);
|
||||
|
@ -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");
|
||||
|
||||
@ -138,11 +138,11 @@ public class UpdateInfoDialog extends JDialog {
|
||||
btnSkip.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
List<String> ignoreVersions = new ArrayList<>(preferences.getIgnoreVersions());
|
||||
List<String> 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();
|
||||
}
|
||||
|
115
swing/src/net/sf/openrocket/gui/dialogs/WelcomeDialog.java
Normal file
115
swing/src/net/sf/openrocket/gui/dialogs/WelcomeDialog.java
Normal file
@ -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 = "<html>" +
|
||||
MarkdownUtil.toHtml(releaseNotes) + "<br><br>" +
|
||||
"</html>";
|
||||
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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user