diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties index 4b1c2b4b8..f320aa563 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/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/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/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/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); }