From: Niki Roo Date: Sun, 5 Mar 2017 12:18:30 +0000 (+0100) Subject: Version 1.4.0 X-Git-Tag: fanfix-1.4.0~1 X-Git-Url: http://git.nikiroo.be/?p=fanfix.git;a=commitdiff_plain;h=b42117f163c9c0dd96424d43730fb95fb088b4be;hp=ba33e96ec7a51c7457d80133b7d202590b8dc005 Version 1.4.0 - Remember the word count and the date of creation of Fanfix stories - UI: option to show the word count instead of the author below the book title - CBZ: do not include the first page twice anymore for no-cover websites - UI: update version check (we now check for new versions) --- diff --git a/VERSION b/VERSION index 3a3cd8c..88c5fb8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.1 +1.4.0 diff --git a/changelog.md b/changelog.md index 20b5870..1e638e3 100644 --- a/changelog.md +++ b/changelog.md @@ -1,10 +1,11 @@ # Fanfix -## Version (in progress) +## Version 1.4.0 - Remember the word count and the date of creation of Fanfix stories - UI: option to show the word count instead of the author below the book title - CBZ: do not include the first page twice anymore for no-cover websites +- UI: update version check (we now check for new versions) ## Version 1.3.1 diff --git a/libs/nikiroo-utils-1.3.3-sources.jar b/libs/nikiroo-utils-1.3.4-sources.jar similarity index 74% rename from libs/nikiroo-utils-1.3.3-sources.jar rename to libs/nikiroo-utils-1.3.4-sources.jar index a7c9ff1..f4b5883 100644 Binary files a/libs/nikiroo-utils-1.3.3-sources.jar and b/libs/nikiroo-utils-1.3.4-sources.jar differ diff --git a/src/be/nikiroo/fanfix/Instance.java b/src/be/nikiroo/fanfix/Instance.java index fdd73b8..1266ac7 100644 --- a/src/be/nikiroo/fanfix/Instance.java +++ b/src/be/nikiroo/fanfix/Instance.java @@ -2,6 +2,7 @@ package be.nikiroo.fanfix; import java.io.File; import java.io.IOException; +import java.util.Date; import be.nikiroo.fanfix.bundles.Config; import be.nikiroo.fanfix.bundles.ConfigBundle; @@ -9,6 +10,7 @@ import be.nikiroo.fanfix.bundles.StringIdBundle; import be.nikiroo.fanfix.bundles.UiConfig; import be.nikiroo.fanfix.bundles.UiConfigBundle; import be.nikiroo.fanfix.output.BasicOutput.OutputType; +import be.nikiroo.utils.IOUtils; import be.nikiroo.utils.resources.Bundles; /** @@ -25,49 +27,49 @@ public class Instance { private static boolean debug; private static File coverDir; private static File readerTmp; + private static String configDir; static { // Most of the rest is dependent upon this: config = new ConfigBundle(); - String configDir = System.getProperty("CONFIG_DIR"); + configDir = System.getProperty("CONFIG_DIR"); if (configDir == null) { configDir = System.getenv("CONFIG_DIR"); } + if (configDir == null) { configDir = new File(System.getProperty("user.home"), ".fanfix") .getPath(); } - if (configDir != null) { - if (!new File(configDir).exists()) { - new File(configDir).mkdirs(); - } else { - Bundles.setDirectory(configDir); - } - - try { - config = new ConfigBundle(); - config.updateFile(configDir); - } catch (IOException e) { - syserr(e); - } - try { - uiconfig = new UiConfigBundle(); - uiconfig.updateFile(configDir); - } catch (IOException e) { - syserr(e); - } - try { - trans = new StringIdBundle(getLang()); - trans.updateFile(configDir); - } catch (IOException e) { - syserr(e); - } - + if (!new File(configDir).exists()) { + new File(configDir).mkdirs(); + } else { Bundles.setDirectory(configDir); } + try { + config = new ConfigBundle(); + config.updateFile(configDir); + } catch (IOException e) { + syserr(e); + } + try { + uiconfig = new UiConfigBundle(); + uiconfig.updateFile(configDir); + } catch (IOException e) { + syserr(e); + } + try { + trans = new StringIdBundle(getLang()); + trans.updateFile(configDir); + } catch (IOException e) { + syserr(e); + } + + Bundles.setDirectory(configDir); + uiconfig = new UiConfigBundle(); trans = new StringIdBundle(getLang()); try { @@ -183,6 +185,45 @@ public class Instance { return readerTmp; } + /** + * Check if we need to check that a new version of Fanfix is available. + * + * @return TRUE if we need to + */ + public static boolean isVersionCheckNeeded() { + try { + long wait = config.getInteger(Config.UPDATE_INTERVAL, 1) * 24 * 60 * 60; + if (wait >= 0) { + String lastUpString = IOUtils.readSmallFile(new File(configDir, + "LAST_UPDATE")); + long delay = new Date().getTime() + - Long.parseLong(lastUpString); + if (delay > wait) { + return true; + } + } else { + return false; + } + } catch (Exception e) { + // No file or bad file: + return true; + } + + return false; + } + + /** + * Notify that we checked for a new version of Fanfix. + */ + public static void setVersionChecked() { + try { + IOUtils.writeSmallFile(new File(configDir), "LAST_UPDATE", + Long.toString(new Date().getTime())); + } catch (IOException e) { + syserr(e); + } + } + /** * Report an error to the user * diff --git a/src/be/nikiroo/fanfix/Main.java b/src/be/nikiroo/fanfix/Main.java index 06287f1..85d7492 100644 --- a/src/be/nikiroo/fanfix/Main.java +++ b/src/be/nikiroo/fanfix/Main.java @@ -189,17 +189,38 @@ public class Main { Progress pg = new Progress(); mainProgress.addProgress(pg, mainProgress.getMax()); + VersionCheck updates = VersionCheck.check(); + if (updates.isNewVersionAvailable()) { + // Sent to syserr so not to cause problem if one tries to capture a + // story content in text mode + System.err + .println("A new version of the program is available at https://github.com/nikiroo/fanfix/releases"); + System.err.println(""); + for (Version v : updates.getNewer()) { + System.err.println("\tVersion " + v); + System.err.println("\t-------------"); + System.err.println(""); + for (String item : updates.getChanges().get(v)) { + System.err.println("\t- " + item); + } + System.err.println(""); + } + } + if (exitCode != 255) { switch (action) { case IMPORT: exitCode = imprt(urlString, pg); + updates.ok(); // we consider it read break; case EXPORT: exitCode = export(luid, typeString, target, pg); + updates.ok(); // we consider it read break; case CONVERT: exitCode = convert(urlString, typeString, target, plusInfo == null ? false : plusInfo, pg); + updates.ok(); // we consider it read break; case LIST: exitCode = list(typeString); @@ -222,6 +243,7 @@ public class Main { + "\nhttps://github.com/nikiroo/fanfix/" + "\n\tWritten by Nikiroo", Version.getCurrentVersion())); + updates.ok(); // we consider it read break; case START: UIUtils.setLookAndFeel(); diff --git a/src/be/nikiroo/fanfix/VersionCheck.java b/src/be/nikiroo/fanfix/VersionCheck.java new file mode 100644 index 0000000..3359bac --- /dev/null +++ b/src/be/nikiroo/fanfix/VersionCheck.java @@ -0,0 +1,140 @@ +package be.nikiroo.fanfix; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import be.nikiroo.utils.Version; + +public class VersionCheck { + private static final String url = "https://github.com/nikiroo/fanfix/raw/master/changelog.md"; + + private Version current; + private List newer; + private Map> changes; + + /** + * Create a new {@link VersionCheck}. + * + * @param current + * the current version of the program + * @param newer + * the list of available {@link Version}s newer the current one + * @param changes + * the list of changes + */ + private VersionCheck(Version current, List newer, + Map> changes) { + this.current = current; + this.newer = newer; + this.changes = changes; + } + + /** + * Check if there are more recent {@link Version}s of this program + * available. + * + * @return TRUE if there is at least one + */ + public boolean isNewVersionAvailable() { + return !newer.isEmpty(); + } + + /** + * The current {@link Version} of the program. + * + * @return the current {@link Version} + */ + public Version getCurrentVersion() { + return current; + } + + /** + * The list of available {@link Version}s newer than the current one. + * + * @return the newer {@link Version}s + */ + public List getNewer() { + return newer; + } + + /** + * The list of changes for each available {@link Version} newer than the + * current one. + * + * @return the list of changes + */ + public Map> getChanges() { + return changes; + } + + /** + * Ignore the check result. + */ + public void ignore() { + + } + + /** + * Accept the information, and do not check again until the minimum wait + * time has elapsed. + */ + public void ok() { + Instance.setVersionChecked(); + } + + /** + * Check if there are available {@link Version}s of this program more recent + * than the current one. + * + * @return a {@link VersionCheck} + */ + public static VersionCheck check() { + Version current = Version.getCurrentVersion(); + List newer = new ArrayList(); + Map> changes = new HashMap>(); + + if (Instance.isVersionCheckNeeded()) { + try { + InputStream in = Instance.getCache().openNoCache(new URL(url), + null); + BufferedReader reader = new BufferedReader( + new InputStreamReader(in, "UTF-8")); + try { + for (String line = reader.readLine(); line != null; line = reader + .readLine()) { + if (line.startsWith("## Version ")) { + String v = line.substring("## Version ".length()); + Version version = new Version(v); + if (version.isNewerThan(current)) { + newer.add(version); + changes.put(version, new ArrayList()); + } + } else if (!newer.isEmpty() && !line.isEmpty()) { + Version version = newer.get(newer.size() - 1); + List ch = changes.get(version); + if (!ch.isEmpty() && !line.startsWith("- ")) { + int i = ch.size() - 1; + ch.set(i, ch.get(i) + " " + line.trim()); + } else { + ch.add(line.substring("- ".length()).trim()); + } + } + } + } finally { + reader.close(); + } + } catch (IOException e) { + Instance.syserr(e); + } + } + + return new VersionCheck(current, newer, changes); + } +} diff --git a/src/be/nikiroo/fanfix/bundles/Config.java b/src/be/nikiroo/fanfix/bundles/Config.java index b68265e..6a728c4 100644 --- a/src/be/nikiroo/fanfix/bundles/Config.java +++ b/src/be/nikiroo/fanfix/bundles/Config.java @@ -8,44 +8,46 @@ import be.nikiroo.utils.resources.Meta; * @author niki */ public enum Config { - @Meta(what = "language", where = "", format = "language (example: en-GB) or nothing for default system language", info = "Force the language (can be overwritten again with the env variable $LANG)") + @Meta(what = "language (example: en-GB, fr-BE...) or nothing for default system language", where = "", format = "Locale|''", info = "Force the language (can be overwritten again with the env variable $LANG)") LANG, // - @Meta(what = "reader type", where = "", format = "CLI or LOCAL", info = "Select the default reader to use to read stories (CLI = simple output to console, LOCAL = use local system file handler)") + @Meta(what = "reader type (CLI = simple output to console, LOCAL = use local system file handler)", where = "", format = "'CLI'|'LOCAL'", info = "Select the default reader to use to read stories") READER_TYPE, // - @Meta(what = "directory", where = "", format = "absolute path, $HOME variable supported, / is always accepted as dir separator", info = "The directory where to store temporary files, defaults to directory 'tmp' in the conig directory (usually $HOME/.fanfix)") + @Meta(what = "absolute path, $HOME variable supported, / is always accepted as dir separator", where = "", format = "Directory", info = "The directory where to store temporary files, defaults to directory 'tmp' in the conig directory (usually $HOME/.fanfix)") CACHE_DIR, // - @Meta(what = "delay in hours", where = "", format = "integer | 0: no cache | -1: infinite time cache which is default", info = "The delay after which a cached resource that is thought to change ~often is considered too old and triggers a refresh") + @Meta(what = "delay in hours, or 0 for no cache, or -1 for infinite time (default)", where = "", format = "int", info = "The delay after which a cached resource that is thought to change ~often is considered too old and triggers a refresh") CACHE_MAX_TIME_CHANGING, // - @Meta(what = "delay in hours", where = "", format = "integer | 0: no cache | -1: infinite time cache which is default", info = "The delay after which a cached resource that is thought to change rarely is considered too old and triggers a refresh") + @Meta(what = "delay in hours, or 0 for no cache, or -1 for infinite time (default)", where = "", format = "int", info = "The delay after which a cached resource that is thought to change rarely is considered too old and triggers a refresh") CACHE_MAX_TIME_STABLE, // - @Meta(what = "string", where = "", format = "", info = "The user-agent to use to download files") + @Meta(what = "string", where = "", format = "String", info = "The user-agent to use to download files") USER_AGENT, // - @Meta(what = "directory", where = "", format = "absolute path, $HOME variable supported, / is always accepted as dir separator", info = "The directory where to get the default story covers") + @Meta(what = "absolute path, $HOME variable supported, / is always accepted as dir separator", where = "", format = "Directory", info = "The directory where to get the default story covers") DEFAULT_COVERS_DIR, // - @Meta(what = "directory", where = "", format = "absolute path, $HOME variable supported, / is always accepted as dir separator", info = "The directory where to store the library") + @Meta(what = "absolute path, $HOME variable supported, / is always accepted as dir separator", where = "", format = "Directory", info = "The directory where to store the library") LIBRARY_DIR, // - @Meta(what = "boolean", where = "", format = "'true' or 'false'", info = "Show debug information on errors") + @Meta(what = "boolean", where = "", format = "'true'|'false'", info = "Show debug information on errors") DEBUG_ERR, // - @Meta(what = "image format", where = "", format = "PNG, JPG, BMP...", info = "Image format to use for cover images") + @Meta(what = "image format", where = "", format = "'PNG'|JPG'|'BMP'", info = "Image format to use for cover images") IMAGE_FORMAT_COVER, // - @Meta(what = "image format", where = "", format = "PNG, JPG, BMP...", info = "Image format to use for content images") + @Meta(what = "image format", where = "", format = "'PNG'|JPG'|'BMP'", info = "Image format to use for content images") IMAGE_FORMAT_CONTENT, // - @Meta(what = "", where = "", format = "not used", info = "This key is only present to allow access to suffixes") + // This key is only present to allow access to suffixes, so no Meta LATEX_LANG, // - @Meta(what = "LaTeX output language", where = "LaTeX", format = "", info = "LaTeX full name for English") + @Meta(what = "LaTeX output language", where = "LaTeX", format = "String", info = "LaTeX full name for English") LATEX_LANG_EN, // - @Meta(what = "LaTeX output language", where = "LaTeX", format = "", info = "LaTeX full name for French") + @Meta(what = "LaTeX output language", where = "LaTeX", format = "String", info = "LaTeX full name for French") LATEX_LANG_FR, // - @Meta(what = "other 'by' prefixes before author name", where = "", format = "comma-separated list", info = "used to identify the author") + @Meta(what = "other 'by' prefixes before author name", where = "", format = "comma-separated list|String", info = "used to identify the author") BYS, // - @Meta(what = "Chapter identification languages", where = "", format = "comma-separated list", info = "used to identify a starting chapter in text mode") + @Meta(what = "Chapter identification languages", where = "", format = "comma-separated list|String", info = "used to identify a starting chapter in text mode") CHAPTER, // - @Meta(what = "Chapter identification string", where = "", format = "", info = "used to identify a starting chapter in text mode") + @Meta(what = "Chapter identification string", where = "String", format = "", info = "used to identify a starting chapter in text mode") CHAPTER_EN, // - @Meta(what = "Chapter identification string", where = "", format = "", info = "used to identify a starting chapter in text mode") + @Meta(what = "Chapter identification string", where = "String", format = "", info = "used to identify a starting chapter in text mode") CHAPTER_FR, // - @Meta(what = "Login information", where = "", format = "", info = "used to login on YiffStar to have access to all the stories (should not be necessary anymore)") + @Meta(what = "Login information", where = "", format = "String", info = "used to login on YiffStar to have access to all the stories (should not be necessary anymore)") LOGIN_YIFFSTAR_USER, // - @Meta(what = "Login information", where = "", format = "", info = "used to login on YiffStar to have access to all the stories (should not be necessary anymore)") + @Meta(what = "Login information", where = "", format = "Password", info = "used to login on YiffStar to have access to all the stories (should not be necessary anymore)") LOGIN_YIFFSTAR_PASS, // + @Meta(what = "Minimum time between version update checks in days, or -1 for 'no checks' -- default is 1 day", where = "VersionCheck", format = "int", info = "If the last update check was done at least that many days, check for updates at startup") + UPDATE_INTERVAL, } diff --git a/src/be/nikiroo/fanfix/bundles/config.properties b/src/be/nikiroo/fanfix/bundles/config.properties index 3f8345f..2fa3d32 100644 --- a/src/be/nikiroo/fanfix/bundles/config.properties +++ b/src/be/nikiroo/fanfix/bundles/config.properties @@ -2,63 +2,63 @@ # -# (WHAT: language, FORMAT: language (example: en-GB) or nothing for default system language) +# (WHAT: language (example: en-GB, fr-BE...) or nothing for default system language, FORMAT: Locale|'') # Force the language (can be overwritten again with the env variable $LANG) LANG = -# (WHAT: reader type, FORMAT: CLI or LOCAL) -# Select the default reader to use to read stories (CLI = simple output to console, LOCAL = use local system file handler) +# (WHAT: reader type (CLI = simple output to console, LOCAL = use local system file handler), FORMAT: 'CLI'|'LOCAL') +# Select the default reader to use to read stories READER_TYPE = -# (WHAT: directory, FORMAT: absolute path, $HOME variable supported, / is always accepted as dir separator) +# (WHAT: absolute path, $HOME variable supported, / is always accepted as dir separator, FORMAT: Directory) # The directory where to store temporary files, defaults to directory 'tmp' in the conig directory (usually $HOME/.fanfix) CACHE_DIR = -# (WHAT: delay in hours, FORMAT: integer | 0: no cache | -1: infinite time cache which is default) +# (WHAT: delay in hours, or 0 for no cache, or -1 for infinite time (default), FORMAT: int) # The delay after which a cached resource that is thought to change ~often is considered too old and triggers a refresh CACHE_MAX_TIME_CHANGING = 24 -# (WHAT: delay in hours, FORMAT: integer | 0: no cache | -1: infinite time cache which is default) +# (WHAT: delay in hours, or 0 for no cache, or -1 for infinite time (default), FORMAT: int) # The delay after which a cached resource that is thought to change rarely is considered too old and triggers a refresh CACHE_MAX_TIME_STABLE = -# (WHAT: string) +# (WHAT: string, FORMAT: String) # The user-agent to use to download files USER_AGENT = Mozilla/5.0 (X11; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0 -- ELinks/0.9.3 (Linux 2.6.11 i686; 80x24) -# (WHAT: directory, FORMAT: absolute path, $HOME variable supported, / is always accepted as dir separator) +# (WHAT: absolute path, $HOME variable supported, / is always accepted as dir separator, FORMAT: Directory) # The directory where to get the default story covers DEFAULT_COVERS_DIR = $HOME/bin/epub/ -# (WHAT: directory, FORMAT: absolute path, $HOME variable supported, / is always accepted as dir separator) +# (WHAT: absolute path, $HOME variable supported, / is always accepted as dir separator, FORMAT: Directory) # The directory where to store the library LIBRARY_DIR = $HOME/Books -# (WHAT: boolean, FORMAT: 'true' or 'false') +# (WHAT: boolean, FORMAT: 'true'|'false') # Show debug information on errors DEBUG_ERR = false -# (WHAT: image format, FORMAT: PNG, JPG, BMP...) +# (WHAT: image format, FORMAT: 'PNG'|JPG'|'BMP') # Image format to use for cover images IMAGE_FORMAT_COVER = png -# (WHAT: image format, FORMAT: PNG, JPG, BMP...) +# (WHAT: image format, FORMAT: 'PNG'|JPG'|'BMP') # Image format to use for content images IMAGE_FORMAT_CONTENT = png -# (FORMAT: not used) -# This key is only present to allow access to suffixes -LATEX_LANG = -# (WHAT: LaTeX output language, WHERE: LaTeX) +# (WHAT: LaTeX output language, WHERE: LaTeX, FORMAT: String) # LaTeX full name for English LATEX_LANG_EN = english -# (WHAT: LaTeX output language, WHERE: LaTeX) +# (WHAT: LaTeX output language, WHERE: LaTeX, FORMAT: String) # LaTeX full name for French LATEX_LANG_FR = french -# (WHAT: other 'by' prefixes before author name, FORMAT: comma-separated list) +# (WHAT: other 'by' prefixes before author name, FORMAT: comma-separated list|String) # used to identify the author BYS = by,par,de,©,(c) -# (WHAT: Chapter identification languages, FORMAT: comma-separated list) +# (WHAT: Chapter identification languages, FORMAT: comma-separated list|String) # used to identify a starting chapter in text mode CHAPTER = EN,FR -# (WHAT: Chapter identification string) +# (WHAT: Chapter identification string, WHERE: String) # used to identify a starting chapter in text mode CHAPTER_EN = Chapter -# (WHAT: Chapter identification string) +# (WHAT: Chapter identification string, WHERE: String) # used to identify a starting chapter in text mode CHAPTER_FR = Chapitre -# (WHAT: Login information) +# (WHAT: Login information, FORMAT: String) # used to login on YiffStar to have access to all the stories (should not be necessary anymore) LOGIN_YIFFSTAR_USER = -# (WHAT: Login information) +# (WHAT: Login information, FORMAT: Password) # used to login on YiffStar to have access to all the stories (should not be necessary anymore) LOGIN_YIFFSTAR_PASS = +# (WHAT: Minimum time between version update checks in days, or -1 for 'no checks' -- default is 1 day, WHERE: VersionCheck, FORMAT: int) +# If the last update check was done at least that many days, check for updates at startup +UPDATE_INTERVAL = diff --git a/src/be/nikiroo/fanfix/reader/LocalReader.java b/src/be/nikiroo/fanfix/reader/LocalReader.java index 45fca8c..b031de8 100644 --- a/src/be/nikiroo/fanfix/reader/LocalReader.java +++ b/src/be/nikiroo/fanfix/reader/LocalReader.java @@ -4,14 +4,23 @@ import java.awt.Desktop; import java.awt.EventQueue; import java.io.File; import java.io.IOException; +import java.net.URISyntaxException; + +import javax.swing.JEditorPane; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.Library; +import be.nikiroo.fanfix.VersionCheck; import be.nikiroo.fanfix.bundles.UiConfig; import be.nikiroo.fanfix.data.MetaData; import be.nikiroo.fanfix.data.Story; import be.nikiroo.fanfix.output.BasicOutput.OutputType; import be.nikiroo.utils.Progress; +import be.nikiroo.utils.Version; class LocalReader extends BasicReader { private Library lib; @@ -140,9 +149,62 @@ class LocalReader extends BasicReader { @Override public void start(String type) { + // TODO: improve presentation of update message + final VersionCheck updates = VersionCheck.check(); + StringBuilder builder = new StringBuilder(); + + final JEditorPane updateMessage = new JEditorPane("text/html", ""); + if (updates.isNewVersionAvailable()) { + builder.append("A new version of the program is available at https://github.com/nikiroo/fanfix/releases"); + builder.append("
"); + builder.append("
"); + for (Version v : updates.getNewer()) { + builder.append("\tVersion " + v + ""); + builder.append("
"); + builder.append("
    "); + for (String item : updates.getChanges().get(v)) { + builder.append("
  • " + item + "
  • "); + } + builder.append("
"); + } + + // html content + updateMessage.setText("" // + + builder// + + ""); + + // handle link events + updateMessage.addHyperlinkListener(new HyperlinkListener() { + public void hyperlinkUpdate(HyperlinkEvent e) { + if (e.getEventType().equals( + HyperlinkEvent.EventType.ACTIVATED)) + try { + Desktop.getDesktop().browse(e.getURL().toURI()); + } catch (IOException ee) { + Instance.syserr(ee); + } catch (URISyntaxException ee) { + Instance.syserr(ee); + } + } + }); + updateMessage.setEditable(false); + updateMessage.setBackground(new JLabel().getBackground()); + } + final String typeFinal = type; EventQueue.invokeLater(new Runnable() { public void run() { + if (updates.isNewVersionAvailable()) { + int rep = JOptionPane.showConfirmDialog(null, + updateMessage, "Updates available", + JOptionPane.OK_CANCEL_OPTION); + if (rep == JOptionPane.OK_OPTION) { + updates.ok(); + } else { + updates.ignore(); + } + } + new LocalReaderFrame(LocalReader.this, typeFinal) .setVisible(true); }