3253 reconciled with develop
authorBobHanson <hansonr@stolaf.edu>
Wed, 8 Apr 2020 19:15:51 +0000 (14:15 -0500)
committerBobHanson <hansonr@stolaf.edu>
Wed, 8 Apr 2020 19:15:51 +0000 (14:15 -0500)
src/jalview/bin/Cache.java
src/jalview/gui/JvSwingUtils.java
src/jalview/gui/Preferences.java
src/jalview/io/BackupFiles.java
src/jalview/io/BackupFilesPresetEntry.java [new file with mode: 0644]
src/jalview/io/IntKeyStringValueEntry.java [new file with mode: 0644]
src/jalview/io/PIRFile.java
src/jalview/jbgui/GPreferences.java

index 5aff236..b70c160 100755 (executable)
  */
 package jalview.bin;
 
-import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI;
-import jalview.datamodel.PDBEntry;
-import jalview.gui.Preferences;
-import jalview.schemes.ColourSchemeLoader;
-import jalview.schemes.ColourSchemes;
-import jalview.schemes.UserColourScheme;
-import jalview.structure.StructureImportSettings;
-import jalview.urls.IdOrgSettings;
-import jalview.util.ColorUtils;
-import jalview.util.Platform;
-import jalview.ws.sifts.SiftsSettings;
-
 import java.awt.Color;
 import java.awt.Dimension;
 import java.io.BufferedReader;
@@ -40,6 +28,7 @@ import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.net.URL;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Collections;
@@ -55,6 +44,18 @@ import org.apache.log4j.Level;
 import org.apache.log4j.Logger;
 import org.apache.log4j.SimpleLayout;
 
+import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI;
+import jalview.datamodel.PDBEntry;
+import jalview.gui.Preferences;
+import jalview.schemes.ColourSchemeLoader;
+import jalview.schemes.ColourSchemes;
+import jalview.schemes.UserColourScheme;
+import jalview.structure.StructureImportSettings;
+import jalview.urls.IdOrgSettings;
+import jalview.util.ColorUtils;
+import jalview.util.Platform;
+import jalview.ws.sifts.SiftsSettings;
+
 /**
  * Stores and retrieves Jalview Application Properties Lists and fields within
  * list entries are separated by '|' symbols unless otherwise stated (|) clauses
@@ -206,6 +207,8 @@ import org.apache.log4j.SimpleLayout;
  * panel in web service preferences</li>
  * </ul>
  * 
+ * @author $author$
+ * @version $Revision$
  */
 public class Cache implements ApplicationSingletonI
 {
@@ -296,12 +299,10 @@ public class Cache implements ApplicationSingletonI
   };
 
   /** Default file is ~/.jalview_properties */
+  // BH 2020 private, not static
   private String propertiesFile;
 
-  /**
-   * flag to possibly allow properties to be written to a property file
-   */
-  private boolean propsAreReadOnly = Platform.isJS();
+  private static boolean propsAreReadOnly = Platform.isJS();
 
   private final static String JS_PROPERTY_PREFIX = "jalview_";
 
@@ -326,14 +327,14 @@ public class Cache implements ApplicationSingletonI
       jalview.bin.Cache.log = Logger.getLogger("jalview.bin.Jalview");
 
       laxis.setLevel(Level.toLevel(
-              getDefault("logs.Axis.Level", Level.INFO.toString())));
-      lcastor.setLevel(Level.toLevel(
-              getDefault("logs.Castor.Level", Level.INFO.toString())));
+              Cache.getDefault("logs.Axis.Level", Level.INFO.toString())));
+      lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
+              Level.INFO.toString())));
       lcastor = Logger.getLogger("org.exolab.castor.xml");
-      lcastor.setLevel(Level.toLevel(
-              getDefault("logs.Castor.Level", Level.INFO.toString())));
+      lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
+              Level.INFO.toString())));
       // lcastor = Logger.getLogger("org.exolab.castor.xml.Marshaller");
-      // lcastor.setLevel(Level.toLevel(getDefault("logs.Castor.Level",
+      // lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
       // Level.INFO.toString())));
       jalview.bin.Cache.log.setLevel(Level.toLevel(Cache
               .getDefault("logs.Jalview.level", Level.INFO.toString())));
@@ -361,24 +362,19 @@ public class Cache implements ApplicationSingletonI
   private void loadPropertiesImpl(String propsFile)
   {
     propertiesFile = propsFile;
-    if (!propsAreReadOnly)
+    if (propsFile == null && !propsAreReadOnly)
     {
-      // Java only
-      if (propsFile == null)
-      {
-        propertiesFile = System.getProperty("user.home")
-                + File.separatorChar + ".jalview_properties";
+      propertiesFile = System.getProperty("user.home") + File.separatorChar
+              + ".jalview_properties";
       }
       else
       {
         // don't corrupt the file we've been given.
         propsAreReadOnly = true;
       }
-    }
 
     if (propertiesFile == null)
-    { // BH 2019 read properties from the Info object associated with this
-      // applet
+    { // BH 2019
       Platform.readInfoProperties(JS_PROPERTY_PREFIX,
               applicationProperties);
     }
@@ -430,15 +426,13 @@ public class Cache implements ApplicationSingletonI
 
     // LOAD THE AUTHORS FROM THE authors.props file
     String authorDetails = (Platform.isJS() ? null
-            : "jar:".concat(Cache.class.getProtectionDomain()
-                    .getCodeSource().getLocation().toString()
-                    .concat("!/authors.props")));
+            : resolveResourceURLFor("/authors.props"));
 
     try
     {
       if (authorDetails != null)
       {
-        java.net.URL localJarFileURL = new java.net.URL(authorDetails);
+        URL localJarFileURL = new URL(authorDetails);
         InputStream in = localJarFileURL.openStream();
         applicationProperties.load(in);
         in.close();
@@ -455,81 +449,45 @@ public class Cache implements ApplicationSingletonI
       applicationProperties.remove("YEAR");
     }
 
-    // FIND THE VERSION NUMBER AND BUILD DATE FROM jalview.jar
-    // MUST FOLLOW READING OF LOCAL PROPERTIES FILE AS THE
-    // VERSION MAY HAVE CHANGED SINCE LAST USING JALVIEW
-    String buildDetails = (Platform.isJS() ? null
-            : "jar:".concat(Cache.class.getProtectionDomain()
-                    .getCodeSource().getLocation().toString()
-                    .concat("!/.build_properties")));
-    if (buildDetails != null)
-    {
-      try
-      {
-        java.net.URL localJarFileURL = new java.net.URL(buildDetails);
-        InputStream in = localJarFileURL.openStream();
-        applicationProperties.load(in);
-        in.close();
-      } catch (Exception ex)
-      {
-        System.out.println("Error reading build details: " + ex);
-        buildDetails = null;
-      }
-    }
-    if (buildDetails == null)
-    {
-      applicationProperties.remove("VERSION");
-    }
-    String jnlpVersion = System.getProperty("jalview.version");
-    String codeVersion = getProperty("VERSION");
-    String codeInstallation = getProperty("INSTALLATION");
-    if (codeVersion == null)
-    {
-      // THIS SHOULD ONLY BE THE CASE WHEN TESTING!!
-      codeVersion = "Test";
-      jnlpVersion = "Test";
-      codeInstallation = "";
-    }
-    else
-    {
-      codeInstallation = " (" + codeInstallation + ")";
-    }
-    new BuildDetails(codeVersion, null, codeInstallation);
+    loadBuildProperties(false);
 
-    SiftsSettings.setMapWithSifts(getDefault("MAP_WITH_SIFTS", false));
+    SiftsSettings
+            .setMapWithSifts(Cache.getDefault("MAP_WITH_SIFTS", false));
 
     SiftsSettings.setSiftDownloadDirectory(jalview.bin.Cache
             .getDefault("sifts_download_dir", DEFAULT_SIFTS_DOWNLOAD_DIR));
 
     SiftsSettings.setFailSafePIDThreshold(
-            getDefault("sifts_fail_safe_pid_threshold",
+            jalview.bin.Cache.getDefault("sifts_fail_safe_pid_threshold",
                     DEFAULT_FAIL_SAFE_PID_THRESHOLD));
 
     SiftsSettings.setCacheThresholdInDays(
-            getDefault("sifts_cache_threshold_in_days",
+            jalview.bin.Cache.getDefault("sifts_cache_threshold_in_days",
                     DEFAULT_CACHE_THRESHOLD_IN_DAYS));
 
     IdOrgSettings.setUrl(getDefault(Preferences.ID_ORG_HOSTURL,
             "http://www.jalview.org/services/identifiers"));
     IdOrgSettings.setDownloadLocation(ID_ORG_FILE);
 
-    System.out
-            .println("Jalview Version: " + codeVersion + codeInstallation);
-
     StructureImportSettings.setDefaultStructureFileFormat(jalview.bin.Cache
             .getDefault(Preferences.PDB_DOWNLOAD_FORMAT, PDB_DOWNLOAD_FORMAT));
     StructureImportSettings
             .setDefaultPDBFileParser(DEFAULT_PDB_FILE_PARSER);
     // StructureImportSettings
-    // .setDefaultPDBFileParser(jalview.bin.getDefault(
+    // .setDefaultPDBFileParser(jalview.bin.Cache.getDefault(
     // "DEFAULT_PDB_FILE_PARSER", DEFAULT_PDB_FILE_PARSER));
-    // jnlpVersion will be null if we're using InstallAnywhere
+
+    String jnlpVersion = System.getProperty("jalview.version");
+
+    // jnlpVersion will be null if a latest version check for the channel needs to
+    // be done
     // Dont do this check if running in headless mode
-    if (jnlpVersion == null && !Jalview.isHeadlessMode()
-            && getDefault("VERSION_CHECK", true))
-    {
 
-      class VersionChecker extends Thread
+    if (jnlpVersion == null && getDefault("VERSION_CHECK", true)
+            && (System.getProperty("java.awt.headless") == null || System
+                    .getProperty("java.awt.headless").equals("false")))
+    {
+      new Thread()
       {
         @Override
         public void run()
@@ -577,10 +535,7 @@ public class Cache implements ApplicationSingletonI
 
           setProperty("LATEST_VERSION", remoteVersion);
         }
-      }
-
-      VersionChecker vc = new VersionChecker();
-      vc.start();
+      }.start();
     }
     else
     {
@@ -594,12 +549,85 @@ public class Cache implements ApplicationSingletonI
       }
     }
 
-    setProperty("VERSION", codeVersion);
-
     // LOAD USERDEFINED COLOURS
-    initUserColourSchemes(getProperty(Preferences.USER_DEFINED_COLOURS));
+    Cache.initUserColourSchemes(getProperty("USER_DEFINED_COLOURS"));
+    jalview.io.PIRFile.useModellerOutput = Cache.getDefault("PIR_MODELLER",
+            false);
   }
 
+    /**
+     * construct a resource URL for the given absolute resource pathname
+     * 
+     * @param resourcePath
+     * @return
+     */
+    private static String resolveResourceURLFor(String resourcePath)
+    {
+      String url = null;
+      if (Platform.isJS() || !Cache.class.getProtectionDomain()
+              .getCodeSource().getLocation().toString().endsWith(".jar"))
+      {
+        try
+        {
+          url = Cache.class.getResource(resourcePath).toString();
+        } catch (Exception ex)
+        {
+          System.err.println("Failed to resolve resource " + resourcePath + ": "
+                  + ex.getMessage());
+        }
+      }
+      else
+      {
+        url = "jar:".concat(Cache.class.getProtectionDomain().getCodeSource()
+                .getLocation().toString().concat("!" + resourcePath));
+      }
+      return url;
+    }
+
+    public static void loadBuildProperties(boolean reportVersion)
+    {
+      String codeInstallation = getProperty("INSTALLATION");
+      boolean printVersion = codeInstallation == null;
+
+      /*
+       * read build properties - from the Jalview jar for a Java distribution,
+       * or from codebase file in test or JalviewJS context
+       */
+      try
+      {
+      String buildDetails = resolveResourceURLFor("/.build_properties");
+      URL localJarFileURL = new URL(buildDetails);
+        InputStream in = localJarFileURL.openStream();
+        getInstance().applicationProperties.load(in);
+        in.close();
+      } catch (Exception ex)
+      {
+        System.out.println("Error reading build details: " + ex);
+        getInstance().applicationProperties.remove("VERSION");
+    }
+    String codeVersion = getProperty("VERSION");
+    codeInstallation = getProperty("INSTALLATION");
+
+    if (codeVersion == null)
+    {
+      // THIS SHOULD ONLY BE THE CASE WHEN TESTING!!
+      codeVersion = "Test";
+      codeInstallation = "";
+    }
+    else
+    {
+      codeInstallation = " (" + codeInstallation + ")";
+    }
+    setProperty("VERSION", codeVersion);
+    new BuildDetails(codeVersion, null, codeInstallation);
+    if (printVersion && reportVersion)
+    {
+      System.out
+            .println("Jalview Version: " + codeVersion + codeInstallation);
+    }
+  }
+
+  // BH 2020 was static  
   private void deleteBuildProperties()
   {
     applicationProperties.remove("LATEST_VERSION");
@@ -623,8 +651,22 @@ public class Cache implements ApplicationSingletonI
   public static String getProperty(String key)
   {
     return getInstance().applicationProperties.getProperty(key);
+
+// old, original idea:
+//    String prop = applicationProperties.getProperty(key);
+//    if (prop == null && Platform.isJS())
+//    {
+//      prop = applicationProperties.getProperty(Platform.getUniqueAppletID()
+//              + "_" + JS_PROPERTY_PREFIX + key);
+//    }
+//    return prop;
+
   }
 
+  
+  //These methods are used when checking if the saved preference is different
+  // to the default setting 
+  
   /**
    * Returns the boolean property value for the given property name. If the
    * value is absent then the default value is returned instead.
@@ -633,9 +675,10 @@ public class Cache implements ApplicationSingletonI
    * @param def
    * @return
    */
-  public static boolean getDefault(String property, final boolean def)
+  public static boolean getDefault(String property, boolean def)
   {
     String string = getProperty(property);
+    // BH simplification only    
     return string == null ? def : Boolean.parseBoolean(string);
   }
 
@@ -648,13 +691,15 @@ public class Cache implements ApplicationSingletonI
    * @param def
    * @return
    */
-  public static int getDefault(String property, final int def)
+  public static int getDefault(String property, int def)
   {
     String string = getProperty(property);
     if (string != null)
     {
       try
       {
+          // BH simplification only
+          
         return Integer.parseInt(string);
       } catch (NumberFormatException e)
       {
@@ -667,40 +712,6 @@ public class Cache implements ApplicationSingletonI
   }
 
   /**
-   * retrieve a dimension, such as for Jmol
-   * 
-   * @param property
-   * @param def
-   * @return
-   */
-  public static Dimension getDefaultDim(String property, Dimension def)
-  {
-    String s = getProperty(property);
-    if (s != null)
-    {
-      if (s.indexOf(',') < 0)
-      {
-        s = s.trim().replace(' ', ',');
-        if (s.indexOf(',') < 0)
-        {
-          s += "," + s;
-        }
-      }
-      try
-      {
-        int pt = s.indexOf(",");
-        return new Dimension(Integer.parseInt(s.substring(0, pt)),
-                Integer.parseInt(s.substring(pt + 1)));
-      } catch (NumberFormatException e)
-      {
-        System.out.println("Error parsing Dimension property '" + property
-                + "' with value '" + s + "'");
-      }
-    }
-    return def;
-  }
-
-  /**
    * Returns the value of the given property, or the supplied default value if
    * the property is not set
    * 
@@ -708,7 +719,7 @@ public class Cache implements ApplicationSingletonI
    * @param def
    * @return
    */
-  public static String getDefault(String property, final String def)
+  public static String getDefault(String property, String def)
   {
     String value = getProperty(property);
     return value == null ? def : value;
@@ -731,7 +742,10 @@ public class Cache implements ApplicationSingletonI
 
   /**
    * Sets a property value for the running application, without saving it to the
-   * properties file
+   * properties file. 
+   * 
+   * Used extensively in AppletParams and Preferences.ok_actionPerformed
+   * 
    * 
    * @param key
    * @param obj
@@ -741,6 +755,7 @@ public class Cache implements ApplicationSingletonI
     getInstance().setPropertyImpl(key, obj, false);
   }
 
+
   /**
    * Sets a property value, and optionally also saves the current properties to
    * file
@@ -782,7 +797,10 @@ public class Cache implements ApplicationSingletonI
 
   /**
    * Removes the named property for the running application, without saving the
-   * properties file
+   * properties file.
+   * 
+   * Called by Preferences.ok_actionPerformed specifically for SEQUENCE_LINKS and STORED_LINKS. 
+   * 
    * 
    * @param key
    */
@@ -976,7 +994,8 @@ public class Cache implements ApplicationSingletonI
                 .newInstance(new Object[]
                 { "Jalview Desktop",
                     (vrs = jalview.bin.Cache.getProperty("VERSION") + "_"
-                            + getDefault("BUILD_DATE", "unknown")),
+                            + jalview.bin.Cache.getDefault("BUILD_DATE",
+                                    "unknown")),
                     "UA-9060947-1" });
         jgoogleanalyticstracker
                 .getMethod("trackAsynchronously", new Class[]
@@ -1059,18 +1078,15 @@ public class Cache implements ApplicationSingletonI
    * parseable.
    * 
    * @param property
-   * @param defaultColour
+   * @param defcolour
    * @return
-   * @see Cache#setColourPropertyNoSave(String, Color)
-   * @see ColorUtils#parseColourString(String)
    */
-  public static Color getDefaultColour(String property,
-          final Color defaultColour)
+  public static Color getDefaultColour(String property, Color defcolour)
   {
     String colprop = getProperty(property);
     if (colprop == null)
     {
-      return defaultColour;
+      return defcolour;
     }
     Color col = ColorUtils.parseColourString(colprop);
     if (col == null)
@@ -1078,13 +1094,17 @@ public class Cache implements ApplicationSingletonI
       log.warn("Couldn't parse '" + colprop + "' as a colour for "
               + property);
     }
-    return (col == null) ? defaultColour : col;
+    return (col == null) ? defcolour : col;
   }
 
   /**
    * Stores a colour as a Jalview property, converted to hex values for rgb.
    * Properties are not saved to file.
    * 
+   * 
+   * 
+   * Used extensively in Preferences.ok_actionPerformed
+   * 
    * @param property
    * @param colour
    */
@@ -1094,6 +1114,17 @@ public class Cache implements ApplicationSingletonI
   }
 
   /**
+   * store a colour as a Jalview user default property
+   * 
+   * @param property
+   * @param colour
+   */
+  public static void setColourProperty(String property, Color colour)
+  {
+    setProperty(property, jalview.util.Format.getHexString(colour));
+  }
+
+  /**
    * Stores a formatted date in a jalview property, using a fixed locale.
    * Updated properties are written out to the properties file.
    * 
@@ -1221,15 +1252,114 @@ public class Cache implements ApplicationSingletonI
     {
       if (coloursFound.toString().length() > 1)
       {
+        // BH moved to Preferences for consistency
         setProperty(Preferences.USER_DEFINED_COLOURS,
                 coloursFound.toString());
       }
       else
       {
+        // BH moved to Preferences for consistency
         getInstance().applicationProperties
                 .remove(Preferences.USER_DEFINED_COLOURS);
       }
     }
   }
 
+  /**
+   * Initial logging information helper for various versions output
+   * 
+   * @param prefix
+   * @param value
+   * @param defaultValue
+   */
+  private static void appendIfNotNull(StringBuilder sb, String prefix,
+          String value, String suffix, String defaultValue)
+  {
+    if (value == null && defaultValue == null)
+    {
+      return;
+    }
+    String line = prefix + (value != null ? value : defaultValue) + suffix;
+    sb.append(line);
+  }
+
+  /**
+   * 
+   * @return Jalview version, build details and JVM platform version for console
+   */
+  public static String getVersionDetailsForConsole()
+  {
+    StringBuilder sb = new StringBuilder();
+    sb.append("Jalview Version: " + jalview.bin.Cache.getDefault("VERSION", "TEST"));
+    sb.append("\n");
+    sb.append("Jalview Installation: "
+            + jalview.bin.Cache.getDefault("INSTALLATION", "unknown"));
+    sb.append("\n");
+    sb.append("Build Date: " + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
+    sb.append("\n");
+    sb.append("Java version: " + System.getProperty("java.version"));
+    sb.append("\n");
+    sb.append(System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " + System.getProperty("os.version"));
+    sb.append("\n");
+    appendIfNotNull(sb, "Install4j version: ",
+            System.getProperty("sys.install4jVersion"), "\n", null);
+    appendIfNotNull(sb, "Install4j template version: ",
+            System.getProperty("installer_template_version"), "\n", null);
+    appendIfNotNull(sb, "Launcher version: ",
+            System.getProperty("launcher_version"), "\n", null);
+    if (jalview.bin.Cache.getDefault("VERSION", "TEST").equals("DEVELOPMENT")) {
+      appendIfNotNull(sb, "Getdown appdir: ",
+              System.getProperty("getdownappdir"), "\n", null);
+      appendIfNotNull(sb, "Java home: ", System.getProperty("java.home"),
+              "\n", "unknown");
+    }
+    return sb.toString();
+  }
+
+  /**
+   * 
+   * @return build details as reported in splashscreen
+   */
+  public static String getBuildDetailsForSplash()
+  {
+    // consider returning more human friendly info
+    // eg 'built from Source' or update channel
+    return jalview.bin.Cache.getDefault("INSTALLATION", "unknown");
+  }
+
+  /**
+   * retrieve a dimension, such as for Jmol
+   * 
+   * @param property
+   * @param def
+   * @return
+   */
+  public static Dimension getDefaultDim(String property, Dimension def)
+  {
+    String s = getProperty(property);
+    if (s != null)
+    {
+      if (s.indexOf(',') < 0)
+      {
+        s = s.trim().replace(' ', ',');
+        if (s.indexOf(',') < 0)
+        {
+          s += "," + s;
+        }
+      }
+      try
+      {
+        int pt = s.indexOf(",");
+        return new Dimension(Integer.parseInt(s.substring(0, pt)),
+                Integer.parseInt(s.substring(pt + 1)));
+      } catch (NumberFormatException e)
+      {
+        System.out.println("Error parsing Dimension property '" + property
+                + "' with value '" + s + "'");
+      }
+    }
+    return def;
+  }
+
+
 }
index fc2ecde..e7f8343 100644 (file)
@@ -75,19 +75,8 @@ public final class JvSwingUtils
             "Tootip text to format must not be null!");
     ttext = ttext.trim();
     boolean maxLengthExceeded = false;
-    boolean isHTML = ttext.startsWith("<html>");
-    if (isHTML)
-    {
-      ttext = ttext.substring(6);
-    }
-    if (ttext.endsWith("</html>"))
-    {
-      isHTML = true;
-      ttext = ttext.substring(0, ttext.length() - 7);
-    }
-    boolean hasBR = ttext.contains("<br>");
-    enclose |= isHTML || hasBR;
-    if (hasBR)
+
+    if (ttext.contains("<br>"))
     {
       String[] htmllines = ttext.split("<br>");
       for (String line : htmllines)
@@ -331,13 +320,13 @@ public final class JvSwingUtils
    * @param entries
    * @param tooltips
    */
-  public static JComboBox<String> buildComboWithTooltips(
-          List<String> entries, List<String> tooltips)
+  public static JComboBox<Object> buildComboWithTooltips(
+          List<Object> entries, List<String> tooltips)
   {
-    JComboBox<String> combo = new JComboBox<>();
+    JComboBox<Object> combo = new JComboBox<>();
     final ComboBoxTooltipRenderer renderer = new ComboBoxTooltipRenderer();
     combo.setRenderer(renderer);
-    for (String attName : entries)
+    for (Object attName : entries)
     {
       combo.addItem(attName);
     }
index 207fcb8..6d46ce7 100755 (executable)
@@ -25,6 +25,7 @@ import jalview.bin.Cache;
 import jalview.gui.Help.HelpId;
 import jalview.gui.StructureViewer.ViewerType;
 import jalview.io.BackupFiles;
+import jalview.io.BackupFilesPresetEntry;
 import jalview.io.FileFormatI;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
@@ -84,10 +85,51 @@ import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
 @SuppressWarnings("serial")
 public class Preferences extends GPreferences
 {
-  public static final String ADD_SS_ANN = "ADD_SS_ANN";
+
+  // original to develop
+
+  public static final String ENABLE_SPLIT_FRAME = "ENABLE_SPLIT_FRAME";
+
+  public static final String SCALE_PROTEIN_TO_CDNA = "SCALE_PROTEIN_TO_CDNA";
+
+  public static final String DEFAULT_COLOUR = "DEFAULT_COLOUR";
+
+  public static final String DEFAULT_COLOUR_PROT = "DEFAULT_COLOUR_PROT";
+
+  public static final String DEFAULT_COLOUR_NUC = "DEFAULT_COLOUR_NUC";
 
   public static final String ADD_TEMPFACT_ANN = "ADD_TEMPFACT_ANN";
 
+  public static final String ADD_SS_ANN = "ADD_SS_ANN";
+
+  public static final String USE_RNAVIEW = "USE_RNAVIEW";
+
+  public static final String STRUCT_FROM_PDB = "STRUCT_FROM_PDB";
+
+  public static final String STRUCTURE_DISPLAY = "STRUCTURE_DISPLAY";
+
+  public static final String CHIMERA_PATH = "CHIMERA_PATH";
+
+  public static final String SORT_ANNOTATIONS = "SORT_ANNOTATIONS";
+
+  public static final String SHOW_AUTOCALC_ABOVE = "SHOW_AUTOCALC_ABOVE";
+
+  public static final String SHOW_OCCUPANCY = "SHOW_OCCUPANCY";
+
+  public static final String SHOW_OV_HIDDEN_AT_START = "SHOW_OV_HIDDEN_AT_START";
+
+  public static final String USE_LEGACY_GAP = "USE_LEGACY_GAP";
+
+  public static final String GAP_COLOUR = "GAP_COLOUR";
+
+  public static final String HIDDEN_COLOUR = "HIDDEN_COLOUR";
+
+  private static final int MIN_FONT_SIZE = 1;
+
+  private static final int MAX_FONT_SIZE = 30;
+
+  // new for applet
+
   public static final String ALLOW_UNPUBLISHED_PDB_QUERYING = "ALLOW_UNPUBLISHED_PDB_QUERYING";
 
   public static final String ANNOTATIONCOLOUR_MAX = "ANNOTATIONCOLOUR_MAX";
@@ -100,20 +142,12 @@ public class Preferences extends GPreferences
 
   public static final String AUTOASSOCIATE_PDBANDSEQS = "AUTOASSOCIATE_PDBANDSEQS";
 
-  public static final String CENTRE_COLUMN_LABELS = "CENTRE_COLUMN_LABELS";
+  public static final String BLOSUM62_PCA_FOR_NUCLEOTIDE = "BLOSUM62_PCA_FOR_NUCLEOTIDE";
 
-  public static final String CHIMERA_PATH = "CHIMERA_PATH";
+  public static final String CENTRE_COLUMN_LABELS = "CENTRE_COLUMN_LABELS";
 
   public static final String DBREFFETCH_USEPICR = "DBREFFETCH_USEPICR";
 
-  public static final String DEFAULT_COLOUR = "DEFAULT_COLOUR";
-
-  public static final String DEFAULT_COLOUR_NUC = "DEFAULT_COLOUR_NUC";
-
-  public static final String DEFAULT_COLOUR_PROT = "DEFAULT_COLOUR_PROT";
-
-  public static final String ENABLE_SPLIT_FRAME = "ENABLE_SPLIT_FRAME";
-
   public static final String FIGURE_AUTOIDWIDTH = "FIGURE_AUTOIDWIDTH";
 
   public static final String FIGURE_FIXEDIDWIDTH = "FIGURE_FIXEDIDWIDTH";
@@ -126,12 +160,8 @@ public class Preferences extends GPreferences
 
   public static final String FONT_STYLE = "FONT_STYLE";
 
-  public static final String GAP_COLOUR = "GAP_COLOUR";
-
   public static final String GAP_SYMBOL = "GAP_SYMBOL";
 
-  public static final String HIDDEN_COLOUR = "HIDDEN_COLOUR";
-
   public static final String HIDE_INTRONS = "HIDE_INTRONS";
 
   public static final String ID_ITALICS = "ID_ITALICS";
@@ -156,12 +186,8 @@ public class Preferences extends GPreferences
 
   public static final String RIGHT_ALIGN_IDS = "RIGHT_ALIGN_IDS";
 
-  public static final String SCALE_PROTEIN_TO_CDNA = "SCALE_PROTEIN_TO_CDNA";
-
   public static final String SHOW_ANNOTATIONS = "SHOW_ANNOTATIONS";
 
-  public static final String SHOW_AUTOCALC_ABOVE = "SHOW_AUTOCALC_ABOVE";
-
   public static final String SHOW_CONSENSUS = "SHOW_CONSENSUS";
 
   public static final String SHOW_CONSENSUS_HISTOGRAM = "SHOW_CONSENSUS_HISTOGRAM";
@@ -176,13 +202,13 @@ public class Preferences extends GPreferences
 
   public static final String SHOW_GROUP_CONSERVATION = "SHOW_GROUP_CONSERVATION";
 
-  public static final String SHOW_JVSUFFIX = "SHOW_JVSUFFIX";
+  public static final String SHOW_IDENTITY = "SHOW_IDENTITY";
 
-  public static final String SHOW_NPFEATS_TOOLTIP = "SHOW_NPFEATS_TOOLTIP";
+  public static final String SHOW_FULLSCREEN = "SHOW_FULLSCREEN";
 
-  public static final String SHOW_OCCUPANCY = "SHOW_OCCUPANCY";
+  public static final String SHOW_JVSUFFIX = "SHOW_JVSUFFIX";
 
-  public static final String SHOW_OV_HIDDEN_AT_START = "SHOW_OV_HIDDEN_AT_START";
+  public static final String SHOW_NPFEATS_TOOLTIP = "SHOW_NPFEATS_TOOLTIP";
 
   public static final String SHOW_OVERVIEW = "SHOW_OVERVIEW";
 
@@ -192,32 +218,21 @@ public class Preferences extends GPreferences
 
   public static final String SORT_ALIGNMENT = "SORT_ALIGNMENT";
 
-  public static final String SORT_ANNOTATIONS = "SORT_ANNOTATIONS";
-
   public static final String SORT_BY_TREE = "SORT_BY_TREE";
 
-  public static final String STRUCT_FROM_PDB = "STRUCT_FROM_PDB";
-
-  public static final String STRUCTURE_DISPLAY = "STRUCTURE_DISPLAY";
-
   public static final String STRUCTURE_DIMENSIONS = "STRUCTURE_DIMENSIONS";
 
   public static final String UNIPROT_DOMAIN = "UNIPROT_DOMAIN";
 
   public static final String USE_FULL_SO = "USE_FULL_SO";
 
-  public static final String USE_LEGACY_GAP = "USE_LEGACY_GAP";
-
-  public static final String USE_RNAVIEW = "USE_RNAVIEW";
-
   public static final String USER_DEFINED_COLOURS = "USER_DEFINED_COLOURS";
 
   public static final String WRAP_ALIGNMENT = "WRAP_ALIGNMENT";
 
 
-  private static final int MIN_FONT_SIZE = 1;
-
-  private static final int MAX_FONT_SIZE = 30;
+  public static final Dimension DEFAULT_STRUCTURE_DIMENSIONS = new Dimension(
+          600, 600);
 
   /**
    * Holds name and link separated with | character. Sequence ID must be
@@ -237,15 +252,6 @@ public class Preferences extends GPreferences
 
   public static final List<String> groupURLLinks; // not implemented
 
-  public static final String BLOSUM62_PCA_FOR_NUCLEOTIDE = "BLOSUM62_PCA_FOR_NUCLEOTIDE";
-
-  public static final String SHOW_IDENTITY = "SHOW_IDENTITY";
-
-  public static final String SHOW_FULLSCREEN = "SHOW_FULLSCREEN";
-
-  public static final Dimension DEFAULT_STRUCTURE_DIMENSIONS = new Dimension(
-          600, 600);
-
   static
   {
     // get links selected to be in the menu (SEQUENCE_LINKS)
@@ -936,7 +942,9 @@ public class Preferences extends GPreferences
             Boolean.toString(modellerOutput.isSelected()));
     Cache.setPropertyNoSave("EXPORT_EMBBED_BIOJSON",
             Boolean.toString(embbedBioJSON.isSelected()));
-    Cache.setPropertyNoSave(FIGURE_AUTOIDWIDTH,
+    jalview.io.PIRFile.useModellerOutput = modellerOutput.isSelected();
+
+    Cache.setPropertyNoSave("FIGURE_AUTOIDWIDTH",
             Boolean.toString(autoIdWidth.isSelected()));
     userIdWidth_actionPerformed();
     Cache.setPropertyNoSave("FIGURE_FIXEDIDWIDTH", userIdWidth.getText());
@@ -954,27 +962,31 @@ public class Preferences extends GPreferences
     if (!Platform.isJS())
     {
       wsPrefs.updateAndRefreshWsMenuConfig(false);
+    }
+
       /*
        * Save Backups settings
        */
-      Cache.setPropertyNoSave(BackupFiles.CONFIRM_DELETE_OLD,
-              Boolean.toString(backupfilesConfirmDelete.isSelected()));
-      Cache.setPropertyNoSave(BackupFiles.ENABLED,
+    Cache.setPropertyNoSave(BackupFiles.ENABLED,
               Boolean.toString(enableBackupFiles.isSelected()));
-      Cache.setPropertyNoSave(BackupFiles.NO_MAX,
-              Boolean.toString(backupfilesKeepAll.isSelected()));
-      Cache.setPropertyNoSave(BackupFiles.REVERSE_ORDER,
-              Boolean.toString(suffixReverse.isSelected()));
-      Cache.setPropertyNoSave(BackupFiles.SUFFIX, suffixTemplate.getText());
-      Cache.setPropertyNoSave(BackupFiles.ROLL_MAX, Integer
-              .toString(getSpinnerInt(backupfilesRollMaxSpinner, 4)));
-      Cache.setPropertyNoSave(BackupFiles.SUFFIX_DIGITS,
-              Integer.toString(getSpinnerInt(suffixDigitsSpinner, 3)));
-      Cache.setPropertyNoSave(BackupFiles.NS + "_PRESET", Integer
-              .toString(getComboIntStringKey(backupfilesPresetsCombo)));
+    int preset = getComboIntStringKey(backupfilesPresetsCombo);
+    Cache.setPropertyNoSave(BackupFiles.NS + "_PRESET",
+            Integer.toString(preset));
 
+    if (preset == BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM)
+    {
+      BackupFilesPresetEntry customBFPE = getBackupfilesCurrentEntry();
+      BackupFilesPresetEntry.backupfilesPresetEntriesValues.put(
+              BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM, customBFPE);
+      Cache.setPropertyNoSave(BackupFilesPresetEntry.CUSTOMCONFIG,
+              customBFPE.toString());
     }
 
+    BackupFilesPresetEntry savedBFPE = BackupFilesPresetEntry.backupfilesPresetEntriesValues
+            .get(preset);
+    Cache.setPropertyNoSave(BackupFilesPresetEntry.SAVEDCONFIG,
+            savedBFPE.toString());
+
     Cache.saveProperties();
     Desktop.getInstance().doConfigureStructurePrefs();
     try
@@ -1503,36 +1515,40 @@ public class Preferences extends GPreferences
     {
       ListSelectionModel lsm = (ListSelectionModel) e.getSource();
 
-      int index = lsm.getMinSelectionIndex();
-      if (index == -1)
-      {
-        // no selection, so disable delete/edit buttons
-        editLink.setEnabled(false);
-        deleteLink.setEnabled(false);
-        return;
-      }
-      int modelIndex = linkUrlTable.convertRowIndexToModel(index);
+      updateValueChanged(lsm.getMinSelectionIndex());
+    }
+  }
 
-      // enable/disable edit and delete link buttons
-      if (((UrlLinkTableModel) linkUrlTable.getModel())
-              .isRowDeletable(modelIndex))
-      {
-        deleteLink.setEnabled(true);
-      }
-      else
-      {
-        deleteLink.setEnabled(false);
-      }
+  public void updateValueChanged(int index)
+  {
+    if (index == -1)
+    {
+      // no selection, so disable delete/edit buttons
+      editLink.setEnabled(false);
+      deleteLink.setEnabled(false);
+      return;
+    }
+    int modelIndex = linkUrlTable.convertRowIndexToModel(index);
 
-      if (((UrlLinkTableModel) linkUrlTable.getModel())
-              .isRowEditable(modelIndex))
-      {
-        editLink.setEnabled(true);
-      }
-      else
-      {
-        editLink.setEnabled(false);
-      }
+    // enable/disable edit and delete link buttons
+    if (((UrlLinkTableModel) linkUrlTable.getModel())
+            .isRowDeletable(modelIndex))
+    {
+      deleteLink.setEnabled(true);
+    }
+    else
+    {
+      deleteLink.setEnabled(false);
+    }
+
+    if (((UrlLinkTableModel) linkUrlTable.getModel())
+            .isRowEditable(modelIndex))
+    {
+      editLink.setEnabled(true);
+    }
+    else
+    {
+      editLink.setEnabled(false);
     }
   }
 }
index c697a99..b1b8976 100644 (file)
@@ -18,12 +18,8 @@ import java.util.TreeMap;
  * BackupFiles used for manipulating (naming rolling/deleting) backup/version files when an alignment or project file is saved.
  * User configurable options are:
  * BACKUPFILES_ENABLED - boolean flag as to whether to use this mechanism or act as before, including overwriting files as saved.
- * BACKUPFILES_SUFFIX - a template to insert after the file extension.  Use '%n' to be replaced by a 0-led SUFFIX_DIGITS long integer.
- * BACKUPFILES_NO_MAX - flag to turn off setting a maximum number of backup files to keep.
- * BACKUPFILES_ROLL_MAX - the maximum number of backupfiles to keep for any one alignment or project file.
- * BACKUPFILES_SUFFIX_DIGITS - the number of digits to insert replace %n with (e.g. BACKUPFILES_SUFFIX_DIGITS = 3 would make "001", "002", etc)
- * BACKUPFILES_REVERSE_ORDER - if true then "logfile" style numbering and file rolling will occur. If false then ever-increasing version numbering will occur, but old files will still be deleted if there are more than ROLL_MAX backup files. 
- * BACKUPFILES_CONFIRM_DELETE_OLD - if true then prompt/confirm with the user when deleting older backup/version files.
+ * The rest of the options are now saved as BACKUPFILES_PRESET, BACKUPFILES_SAVED and BACKUPFILES_CUSTOM
+ * (see BackupFilesPresetEntry)
  */
 
 public class BackupFiles
@@ -34,21 +30,8 @@ public class BackupFiles
 
   public static final String ENABLED = NS + "_ENABLED";
 
-  public static final String SUFFIX = NS + "_SUFFIX";
-
-  public static final String NO_MAX = NS + "_NO_MAX";
-
-  public static final String ROLL_MAX = NS + "_ROLL_MAX";
-
-  public static final String SUFFIX_DIGITS = NS + "_SUFFIX_DIGITS";
-
   public static final String NUM_PLACEHOLDER = "%n";
 
-  public static final String REVERSE_ORDER = NS + "_REVERSE_ORDER";
-
-  public static final String CONFIRM_DELETE_OLD = NS
-          + "_CONFIRM_DELETE_OLD";
-
   private static final String DEFAULT_TEMP_FILE = "jalview_temp_file_" + NS;
 
   private static final String TEMP_FILE_EXT = ".tmp";
@@ -102,20 +85,14 @@ public class BackupFiles
   // REVERSE_ORDER
   public BackupFiles(File file)
   {
-    this(file, ".bak" + NUM_PLACEHOLDER, false, 3, 3, false);
-  }
-
-  public BackupFiles(File file, String defaultSuffix, boolean defaultNoMax,
-          int defaultMax, int defaultDigits, boolean defaultReverseOrder)
-  {
     classInit();
     this.file = file;
-    this.suffix = Cache.getDefault(SUFFIX, defaultSuffix);
-    this.noMax = Cache.getDefault(NO_MAX, defaultNoMax);
-    this.max = Cache.getDefault(ROLL_MAX, defaultMax);
-    this.digits = Cache.getDefault(SUFFIX_DIGITS, defaultDigits);
-    this.reverseOrder = Cache.getDefault(REVERSE_ORDER,
-            defaultReverseOrder);
+    BackupFilesPresetEntry bfpe = BackupFilesPresetEntry.getSavedBackupEntry();
+    this.suffix = bfpe.suffix;
+    this.noMax = bfpe.keepAll;
+    this.max = bfpe.rollMax;
+    this.digits = bfpe.digits;
+    this.reverseOrder = bfpe.reverse;
 
     // create a temp file to save new data in
     File temp = null;
@@ -146,7 +123,9 @@ public class BackupFiles
   public static void classInit()
   {
     setEnabled(Cache.getDefault(ENABLED, !Platform.isJS()));
-    setConfirmDelete(Cache.getDefault(CONFIRM_DELETE_OLD, true));
+    BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
+            .getSavedBackupEntry();
+    setConfirmDelete(bfpe.confirmDelete);
   }
 
   public static void setEnabled(boolean flag)
diff --git a/src/jalview/io/BackupFilesPresetEntry.java b/src/jalview/io/BackupFilesPresetEntry.java
new file mode 100644 (file)
index 0000000..4face29
--- /dev/null
@@ -0,0 +1,173 @@
+package jalview.io;
+
+import jalview.bin.Cache;
+import jalview.util.MessageManager;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+public class BackupFilesPresetEntry
+{
+
+  public String suffix;
+
+  public static final int DIGITSMIN = 1;
+
+  public static final int DIGITSMAX = 6;
+
+  public int digits;
+
+  public boolean reverse;
+
+  public boolean keepAll;
+
+  public static final int ROLLMAXMIN = 1;
+
+  public static final int ROLLMAXMAX = 999;
+
+  public int rollMax;
+
+  public boolean confirmDelete;
+
+  public static final String SAVEDCONFIG = BackupFiles.NS + "_SAVED";
+
+  public static final String CUSTOMCONFIG = BackupFiles.NS + "_CUSTOM";
+
+  private static final String stringDelim = "\t";
+
+  public static final int BACKUPFILESSCHEMECUSTOM = 0;
+
+  public static final int BACKUPFILESSCHEMEDEFAULT = 1;
+
+  public BackupFilesPresetEntry(String suffix, int digits, boolean reverse,
+          boolean keepAll, int rollMax, boolean confirmDelete)
+  {
+    this.suffix = suffix == null ? "" : suffix;
+    this.digits = digits < DIGITSMIN ? DIGITSMIN
+            : (digits > DIGITSMAX ? DIGITSMAX : digits);
+    this.reverse = reverse;
+    this.keepAll = keepAll;
+    this.rollMax = rollMax < ROLLMAXMIN ? ROLLMAXMIN
+            : (rollMax > ROLLMAXMAX ? ROLLMAXMAX : rollMax);
+    this.confirmDelete = confirmDelete;
+  }
+
+  public boolean equals(BackupFilesPresetEntry compare)
+  {
+    return suffix.equals(compare.suffix) && digits == compare.digits
+            && reverse == compare.reverse && keepAll == compare.keepAll
+            && rollMax == compare.rollMax
+            && confirmDelete == compare.confirmDelete;
+  }
+
+  @Override
+  public String toString()
+  {
+    StringBuilder sb = new StringBuilder();
+    sb.append(suffix);
+    sb.append(stringDelim);
+    sb.append(digits);
+    sb.append(stringDelim);
+    sb.append(reverse);
+    sb.append(stringDelim);
+    sb.append(keepAll);
+    sb.append(stringDelim);
+    sb.append(rollMax);
+    sb.append(stringDelim);
+    sb.append(confirmDelete);
+    return sb.toString();
+  }
+
+  public static BackupFilesPresetEntry createBackupFilesPresetEntry(
+          String line)
+  {
+    if (line == null)
+    {
+      return null;
+    }
+    StringTokenizer st = new StringTokenizer(line, stringDelim);
+    String suffix = null;
+    int digits = 0;
+    boolean reverse = false;
+    boolean keepAll = false;
+    int rollMax = 0;
+    boolean confirmDelete = false;
+
+    try
+    {
+      suffix = st.nextToken();
+      digits = Integer.valueOf(st.nextToken());
+      reverse = Boolean.valueOf(st.nextToken());
+      keepAll = Boolean.valueOf(st.nextToken());
+      rollMax = Integer.valueOf(st.nextToken());
+      confirmDelete = Boolean.valueOf(st.nextToken());
+    } catch (Exception e)
+    {
+      Cache.log.error("Error parsing backupfiles scheme '" + line + "'");
+    }
+
+    return new BackupFilesPresetEntry(suffix, digits, reverse, keepAll,
+            rollMax, confirmDelete);
+  }
+
+  public static BackupFilesPresetEntry getSavedBackupEntry()
+  {
+    String savedPresetString = Cache
+            .getDefault(BackupFilesPresetEntry.SAVEDCONFIG, null);
+    BackupFilesPresetEntry savedPreset = BackupFilesPresetEntry
+            .createBackupFilesPresetEntry(savedPresetString);
+    if (savedPreset == null)
+    {
+      savedPreset = backupfilesPresetEntriesValues
+              .get(BACKUPFILESSCHEMEDEFAULT);
+    }
+    return savedPreset;
+  }
+
+  public static final IntKeyStringValueEntry[] backupfilesPresetEntries = {
+      new IntKeyStringValueEntry(BACKUPFILESSCHEMEDEFAULT,
+              MessageManager.getString("label.default")),
+      new IntKeyStringValueEntry(2,
+              MessageManager.getString("label.single_file")),
+      new IntKeyStringValueEntry(3,
+              MessageManager.getString("label.keep_all_versions")),
+      new IntKeyStringValueEntry(4,
+              MessageManager.getString("label.rolled_backups")),
+      // ...
+      // IMPORTANT, keep "Custom" entry with key 0 (even though it appears last)
+      new IntKeyStringValueEntry(BACKUPFILESSCHEMECUSTOM,
+              MessageManager.getString("label.custom")) };
+
+  public static final String[] backupfilesPresetEntryDescriptions = {
+      MessageManager.getString("label.default_description"),
+      MessageManager.getString("label.single_file_description"),
+      MessageManager.getString("label.keep_all_versions_description"),
+      MessageManager.getString("label.rolled_backups_description"),
+      MessageManager.getString("label.custom_description") };
+
+  public static final Map<Integer, BackupFilesPresetEntry> backupfilesPresetEntriesValues = new HashMap<Integer, BackupFilesPresetEntry>()
+  {
+    /**
+     * 
+     */
+    private static final long serialVersionUID = 125L;
+
+    {
+      put(1, new BackupFilesPresetEntry(
+              ".bak" + BackupFiles.NUM_PLACEHOLDER, 3, false, false, 3,
+              false));
+      put(2, new BackupFilesPresetEntry("~", 1, false, false, 1, false));
+      put(3, new BackupFilesPresetEntry(".v" + BackupFiles.NUM_PLACEHOLDER,
+              3, false, true, 10, true));
+      put(4, new BackupFilesPresetEntry(
+              "_bak." + BackupFiles.NUM_PLACEHOLDER, 1, true, false, 9,
+              false));
+
+      // This gets replaced by GPreferences
+      put(BACKUPFILESSCHEMECUSTOM,
+              new BackupFilesPresetEntry("", 0, false, false, 0, false));
+    }
+  };
+
+}
diff --git a/src/jalview/io/IntKeyStringValueEntry.java b/src/jalview/io/IntKeyStringValueEntry.java
new file mode 100644 (file)
index 0000000..084dbc5
--- /dev/null
@@ -0,0 +1,21 @@
+package jalview.io;
+
+public class IntKeyStringValueEntry
+{
+  public final int k;
+
+  public final String v;
+
+  public IntKeyStringValueEntry(int k, String v)
+  {
+    this.k = k;
+    this.v = v;
+  }
+
+  @Override
+  public String toString()
+  {
+    return v;
+  }
+
+}
index 3f0fea0..d9ed516 100755 (executable)
  */
 package jalview.io;
 
-import jalview.bin.Cache;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
 import jalview.util.Comparison;
 
 import java.io.IOException;
+import java.util.Vector;
 
 public class PIRFile extends AlignFile
 {
-  // Vector words = new Vector(); // Stores the words in a line after splitting
+  public static boolean useModellerOutput = false;
+
+  Vector words = new Vector(); // Stores the words in a line after splitting
 
   public PIRFile()
   {
@@ -109,7 +111,7 @@ public class PIRFile extends AlignFile
     StringBuffer out = new StringBuffer();
     int i = 0;
     ModellerDescription md;
-    boolean useModellerOutput = Cache.getDefault("PIR_MODELLER", false);
+
     while ((i < s.length) && (s[i] != null))
     {
       String seq = s[i].getSequenceAsString();
@@ -145,6 +147,7 @@ public class PIRFile extends AlignFile
       }
       else
       {
+
         if (useModellerOutput)
         {
           out.append(">P1;" + s[i].getName());
index d9a6cea..fd81745 100755 (executable)
@@ -31,6 +31,8 @@ import jalview.gui.JvSwingUtils;
 import jalview.gui.StructureViewer.ViewerType;
 import jalview.io.BackupFilenameParts;
 import jalview.io.BackupFiles;
+import jalview.io.BackupFilesPresetEntry;
+import jalview.io.IntKeyStringValueEntry;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 
@@ -52,8 +54,8 @@ import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Arrays;
+import java.util.List;
 
 import javax.swing.AbstractCellEditor;
 import javax.swing.BorderFactory;
@@ -64,7 +66,6 @@ import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
 import javax.swing.JFileChooser;
 import javax.swing.JLabel;
-import javax.swing.JList;
 import javax.swing.JPanel;
 import javax.swing.JRadioButton;
 import javax.swing.JScrollPane;
@@ -92,7 +93,6 @@ import javax.swing.table.TableCellRenderer;
  * @author $author$
  * @version $Revision$
  */
-@SuppressWarnings("serial")
 public class GPreferences extends JPanel
 {
   private static final Font LABEL_FONT = JvSwingUtils.getLabelFont();
@@ -217,13 +217,13 @@ public class GPreferences extends JPanel
   /*
    * Connections tab components
    */
-  public JTable linkUrlTable = new JTable();
+  protected JTable linkUrlTable = new JTable();
 
-  public JButton editLink = new JButton();
+  protected JButton editLink = new JButton();
 
-  public JButton deleteLink = new JButton();
+  protected JButton deleteLink = new JButton();
 
-  public JTextField filterTB = new JTextField();
+  protected JTextField filterTB = new JTextField();
 
   protected JButton doReset = new JButton();
 
@@ -304,9 +304,15 @@ public class GPreferences extends JPanel
 
   protected JPanel presetsPanel = new JPanel();
 
+  protected JLabel presetsComboLabel = new JLabel();
+
+  protected JCheckBox customiseCheckbox = new JCheckBox();
+
   protected JButton revertButton = new JButton();
 
-  protected JComboBox<IntKeyStringValueEntry> backupfilesPresetsCombo = new JComboBox<>();
+  protected JComboBox<Object> backupfilesPresetsCombo = new JComboBox<>();
+
+  private int backupfilesPresetsComboLastSelected = 0;
 
   protected JPanel suffixPanel = new JPanel();
 
@@ -376,11 +382,11 @@ public class GPreferences extends JPanel
     tabbedPane.add(initConnectionsTab(),
             MessageManager.getString("label.connections"));
 
-       if (!Platform.isJS()) 
-       {
-         tabbedPane.add(initBackupsTab(), 
-                       MessageManager.getString("label.backups"));
-       }
+    if (!Platform.isJS())
+    {
+      tabbedPane.add(initBackupsTab(),
+              MessageManager.getString("label.backups"));
+    }
 
     tabbedPane.add(initLinksTab(),
             MessageManager.getString("label.urllinks"));
@@ -663,6 +669,8 @@ public class GPreferences extends JPanel
                     GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
                     new Insets(0, 2, 5, 5), 70, 1));
 
+    versioncheck.setVisible(false);
+
     // Add padding so the panel doesn't look ridiculous
     JPanel spacePanel = new JPanel();
     connectTab.add(spacePanel,
@@ -1678,7 +1686,7 @@ public class GPreferences extends JPanel
                                                                   // in height
                                                                   // on Windows
                                                                   // OS
-                                                                 // Was 320
+                                                                  // Was 320, 96
     annsettingsPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
     annsettingsPanel.setBorder(new EtchedBorder());
     visualTab.add(annsettingsPanel);
@@ -1786,34 +1794,40 @@ public class GPreferences extends JPanel
 
   protected void loadLastSavedBackupsOptions()
   {
+    BackupFilesPresetEntry savedPreset = BackupFilesPresetEntry
+            .getSavedBackupEntry();
     enableBackupFiles
             .setSelected(Cache.getDefault(BackupFiles.ENABLED, !Platform.isJS()));
+
+    BackupFilesPresetEntry backupfilesCustomEntry = BackupFilesPresetEntry
+            .createBackupFilesPresetEntry(Cache
+                    .getDefault(BackupFilesPresetEntry.CUSTOMCONFIG, null));
+    if (backupfilesCustomEntry == null)
+    {
+      backupfilesCustomEntry = BackupFilesPresetEntry.backupfilesPresetEntriesValues
+              .get(BackupFilesPresetEntry.BACKUPFILESSCHEMEDEFAULT);
+    }
+    BackupFilesPresetEntry.backupfilesPresetEntriesValues.put(
+            BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM,
+            backupfilesCustomEntry);
+
     setComboIntStringKey(backupfilesPresetsCombo,
-            Cache.getDefault(BackupFiles.NS + "_PRESET", 1));
-    suffixTemplate.setText(Cache.getDefault(BackupFiles.SUFFIX,
-            ".bak" + BackupFiles.NUM_PLACEHOLDER));
-    suffixDigitsSpinner
-            .setValue(Cache.getDefault(BackupFiles.SUFFIX_DIGITS, 3));
-    suffixReverse.setSelected(
-            Cache.getDefault(BackupFiles.REVERSE_ORDER, false));
-    backupfilesKeepAll
-            .setSelected(Cache.getDefault(BackupFiles.NO_MAX, false));
-    backupfilesRollMaxSpinner
-            .setValue(Cache.getDefault(BackupFiles.ROLL_MAX, 3));
-    backupfilesConfirmDelete.setSelected(
-            Cache.getDefault(BackupFiles.CONFIRM_DELETE_OLD, true));
+            Cache.getDefault(BackupFiles.NS + "_PRESET",
+                    BackupFilesPresetEntry.BACKUPFILESSCHEMEDEFAULT));
+
+    backupsSetOptions(savedPreset);
 
     backupsOptionsSetEnabled();
     updateBackupFilesExampleLabel();
   }
 
-  protected boolean warnAboutSuffixReverseChange()
+  private boolean warnAboutSuffixReverseChange()
   {
-    boolean savedSuffixReverse = Cache.getDefault(BackupFiles.REVERSE_ORDER,
-            false);
-    int savedSuffixDigits = Cache.getDefault(BackupFiles.SUFFIX_DIGITS, 3);
-    String savedSuffixTemplate = Cache.getDefault(BackupFiles.SUFFIX,
-            ".bak" + BackupFiles.NUM_PLACEHOLDER);
+    BackupFilesPresetEntry bfpe = BackupFilesPresetEntry
+            .getSavedBackupEntry();
+    boolean savedSuffixReverse = bfpe.reverse;
+    int savedSuffixDigits = bfpe.digits;
+    String savedSuffixTemplate = bfpe.suffix;
 
     boolean nowSuffixReverse = suffixReverse.isSelected();
     int nowSuffixDigits = getSpinnerInt(suffixDigitsSpinner, 3);
@@ -1890,7 +1904,6 @@ public class GPreferences extends JPanel
     gbc.gridy++; // row 1
     backupsTab.add(presetsPanel, gbc);
 
-    // gbc.anchor = GridBagConstraints.NORTHWEST;
     // now using whole row
     gbc.gridwidth = 2;
     gbc.gridheight = 1;
@@ -1912,50 +1925,10 @@ public class GPreferences extends JPanel
     return backupsTab;
   }
 
-  protected static final int BACKUPFILESSCHEMECUSTOMISE = 0;
-
-  private static final IntKeyStringValueEntry[] backupfilesPresetEntries = {
-      new IntKeyStringValueEntry(1,
-              MessageManager.getString("label.default")),
-      new IntKeyStringValueEntry(2,
-              MessageManager.getString("label.single_file")),
-      new IntKeyStringValueEntry(3,
-              MessageManager.getString("label.keep_all_versions")),
-      new IntKeyStringValueEntry(4,
-              MessageManager.getString("label.rolled_backups")),
-      // ...
-      // IMPORTANT, keep "Custom" entry with key 0 (even though it appears last)
-      new IntKeyStringValueEntry(BACKUPFILESSCHEMECUSTOMISE,
-              MessageManager.getString("label.customise")) };
-
-  private static final Map<Integer, BackupFilesPresetEntry> backupfilesPresetEntriesValues = new HashMap<Integer, BackupFilesPresetEntry>()
-  {
-    /**
-     * 
-     */
-    private static final long serialVersionUID = 125L;
-
-    {
-      put(1, new BackupFilesPresetEntry(
-              ".bak" + BackupFiles.NUM_PLACEHOLDER, 3, false, false, 3,
-              false));
-      put(2, new BackupFilesPresetEntry("~", 1, false, false, 1, false));
-      put(3, new BackupFilesPresetEntry(".v" + BackupFiles.NUM_PLACEHOLDER,
-              3, false, true, 10, true));
-      put(4, new BackupFilesPresetEntry(
-              "_bak." + BackupFiles.NUM_PLACEHOLDER, 1, true, false, 9,
-              false));
-    }
-  };
-
   private JPanel initBackupsTabPresetsPanel()
   {
 
     String title = MessageManager.getString("label.schemes");
-    // TitledBorder tb = new TitledBorder(new EmptyBorder(0, 0, 0, 0), title);
-    // TitledBorder tb = new TitledBorder(title);
-    // tb.setTitleFont(LABEL_FONT);
-    // presetsPanel.setBorder(tb);
 
     presetsPanel.setLayout(new GridBagLayout());
 
@@ -1970,24 +1943,54 @@ public class GPreferences extends JPanel
     // "Scheme: "
     gbc.gridx = 0;
     gbc.gridy = 0;
-    presetsPanel.add(new JLabel(title + ":"), gbc);
 
-    for (int i = 0; i < backupfilesPresetEntries.length; i++)
+    presetsComboLabel = new JLabel(title + ":");
+    presetsPanel.add(presetsComboLabel, gbc);
+
+    List<Object> entries = Arrays.asList(
+            (Object[]) BackupFilesPresetEntry.backupfilesPresetEntries);
+    List<String> tooltips = Arrays.asList(
+            BackupFilesPresetEntry.backupfilesPresetEntryDescriptions);
+    backupfilesPresetsCombo = JvSwingUtils.buildComboWithTooltips(entries,
+            tooltips);
+    /*
+    for (int i = 0; i < BackupFilesPresetEntry.backupfilesPresetEntries.length; i++)
     {
-      backupfilesPresetsCombo.addItem(backupfilesPresetEntries[i]);
+      backupfilesPresetsCombo
+              .addItem(BackupFilesPresetEntry.backupfilesPresetEntries[i]);
     }
+    */
 
-    // put "Previously saved scheme" item in italics (it's not really
-    // selectable, as such -- it deselects itself when selected) and
-    // "Customise" in bold
-    backupfilesPresetsCombo
-            .setRenderer(new BackupFilesPresetsComboBoxRenderer());
     backupfilesPresetsCombo.addActionListener(new ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        backupsTabUpdatePresets();
+        int key = getComboIntStringKey(backupfilesPresetsCombo);
+        if (!customiseCheckbox.isSelected())
+        {
+          backupfilesPresetsComboLastSelected = key;
+        }
+        if (key == BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM)
+        {
+          if (customiseCheckbox.isSelected())
+          {
+            // got here by clicking on customiseCheckbox so don't change the
+            // values
+            backupfilesCustomOptionsSetEnabled();
+          }
+          else
+          {
+            backupsTabUpdatePresets();
+            backupfilesCustomOptionsSetEnabled();
+          }
+        }
+        else
+        {
+          customiseCheckbox.setSelected(false);
+          backupsTabUpdatePresets();
+          backupfilesCustomOptionsSetEnabled();
+        }
       }
     });
 
@@ -1996,20 +1999,55 @@ public class GPreferences extends JPanel
     presetsPanel.add(backupfilesPresetsCombo, gbc);
 
     revertButton.setText(MessageManager.getString("label.cancel_changes"));
+    revertButton.setToolTipText(
+            MessageManager.getString("label.cancel_changes_description"));
     revertButton.addActionListener(new ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        loadLastSavedBackupsOptions();
+        backupsSetOptions(
+                BackupFilesPresetEntry.backupfilesPresetEntriesValues.get(
+                        BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM));
+        backupfilesCustomOptionsSetEnabled();
       }
 
     });
     revertButton.setFont(LABEL_FONT);
 
+    customiseCheckbox.setFont(LABEL_FONT);
+    customiseCheckbox.setText(MessageManager.getString("label.customise"));
+    customiseCheckbox.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        int currently = getComboIntStringKey(backupfilesPresetsCombo);
+        if (customiseCheckbox.isSelected())
+        {
+          backupfilesPresetsComboLastSelected = currently;
+          setComboIntStringKey(backupfilesPresetsCombo,
+                  BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM);
+        }
+        else
+        {
+          setComboIntStringKey(backupfilesPresetsCombo,
+                  backupfilesPresetsComboLastSelected);
+
+        }
+        backupfilesCustomOptionsSetEnabled();
+      }
+    });
+    customiseCheckbox.setToolTipText(
+            MessageManager.getString("label.customise_description"));
+
+    // customise checkbox
+    gbc.gridx = 0;
+    gbc.gridy++;
+    presetsPanel.add(customiseCheckbox, gbc);
+
     // "Cancel changes" button (aligned with combo box above)
     gbc.gridx = 1;
-    gbc.gridy++;
     presetsPanel.add(revertButton, gbc);
 
     return presetsPanel;
@@ -2018,7 +2056,7 @@ public class GPreferences extends JPanel
   private JPanel initBackupsTabFilenameExamplesPanel()
   {
     String title = MessageManager
-            .getString("label.summary_of_backups_scheme");
+            .getString("label.scheme_examples");
     TitledBorder tb = new TitledBorder(title);
     exampleFilesPanel.setBorder(tb);
     exampleFilesPanel.setLayout(new GridBagLayout());
@@ -2040,49 +2078,72 @@ public class GPreferences extends JPanel
     return exampleFilesPanel;
   }
 
-  protected void backupsTabUpdatePresets()
+  private void backupsTabUpdatePresets()
   {
     IntKeyStringValueEntry entry = (IntKeyStringValueEntry) backupfilesPresetsCombo
             .getSelectedItem();
-    int key = entry.getKey();
-    String value = entry.getValue();
+    int key = entry.k;
+    String value = entry.v;
 
-    // BACKUPFILESSCHEMECUSTOMISE (==0) reserved for "Custom"
-    if (key != BACKUPFILESSCHEMECUSTOMISE)
+    if (BackupFilesPresetEntry.backupfilesPresetEntriesValues
+            .containsKey(key))
     {
-      if (backupfilesPresetEntriesValues.containsKey(key))
-      {
-        backupsSetOptions(backupfilesPresetEntriesValues.get(key));
+      backupsSetOptions(
+              BackupFilesPresetEntry.backupfilesPresetEntriesValues
+                      .get(key));
       }
       else
       {
-        System.out.println("Preset '" + value + "' not implemented");
+      Cache.log.error(
+              "Preset '" + value + "' [key:" + key + "] not implemented");
       }
-    }
 
-    backupfilesCustomOptionsSetEnabled();
+    // Custom options will now be enabled when the customiseCheckbox is checked
+    // (performed above)
+    // backupfilesCustomOptionsSetEnabled();
     updateBackupFilesExampleLabel();
   }
 
-  protected int getComboIntStringKey(JComboBox<IntKeyStringValueEntry> c)
+  protected int getComboIntStringKey(
+          JComboBox<Object> backupfilesPresetsCombo2)
   {
-    IntKeyStringValueEntry e = (IntKeyStringValueEntry) c.getSelectedItem();
-    return e != null ? e.getKey() : 0;
+    IntKeyStringValueEntry e;
+    try
+    {
+      e = (IntKeyStringValueEntry) backupfilesPresetsCombo2
+              .getSelectedItem();
+    } catch (Exception ex)
+  {
+      Cache.log.error(
+              "Problem casting Combo entry to IntKeyStringValueEntry.");
+      e = null;
+    }
+    return e != null ? e.k : 0;
   }
 
-  protected void setComboIntStringKey(JComboBox<IntKeyStringValueEntry> c,
+  protected void setComboIntStringKey(
+          JComboBox<Object> backupfilesPresetsCombo2,
           int key)
   {
-    for (int i = 0; i < c.getItemCount(); i++)
+    for (int i = 0; i < backupfilesPresetsCombo2.getItemCount(); i++)
     {
-      IntKeyStringValueEntry e = c.getItemAt(i);
-      if (e.getKey() == key)
+      IntKeyStringValueEntry e;
+      try
       {
-        c.setSelectedIndex(i);
+        e = (IntKeyStringValueEntry) backupfilesPresetsCombo2.getItemAt(i);
+      } catch (Exception ex)
+    {
+        Cache.log.error(
+                "Problem casting Combo entry to IntKeyStringValueEntry. Skipping item. ");
+        continue;
+      }
+      if (e.k == key)
+      {
+        backupfilesPresetsCombo2.setSelectedIndex(i);
         break;
       }
     }
-    backupsTabUpdatePresets();
+    // backupsTabUpdatePresets();
   }
 
   private JPanel initBackupsTabSuffixPanel()
@@ -2106,16 +2167,18 @@ public class GPreferences extends JPanel
       {
         updateBackupFilesExampleLabel();
         backupfilesCustomOptionsSetEnabled();
+        backupfilesRevertButtonSetEnabled(true);
       }
 
     });
-    KeyListener kl = new KeyListener()
+    suffixTemplate.addKeyListener(new KeyListener()
     {
       @Override
       public void keyReleased(KeyEvent e)
       {
         updateBackupFilesExampleLabel();
         backupfilesCustomOptionsSetEnabled();
+        backupfilesRevertButtonSetEnabled(true);
       }
 
       @Override
@@ -2135,26 +2198,25 @@ public class GPreferences extends JPanel
         }
       }
 
-    };
-    suffixTemplate.addKeyListener(kl);
+    });
 
     // digits spinner
     suffixDigitsLabel
             .setText(MessageManager.getString("label.index_digits"));
     suffixDigitsLabel.setHorizontalAlignment(SwingConstants.LEFT);
     suffixDigitsLabel.setFont(LABEL_FONT);
-    int defaultmin = 1;
-    int defaultmax = 6;
     ChangeListener c = new ChangeListener()
     {
       @Override
       public void stateChanged(ChangeEvent e)
       {
+        backupfilesRevertButtonSetEnabled(true);
         updateBackupFilesExampleLabel();
       }
 
     };
-    setIntegerSpinner(suffixDigitsSpinner, defaultmin, defaultmax, 3, c);
+    setIntegerSpinner(suffixDigitsSpinner, BackupFilesPresetEntry.DIGITSMIN,
+            BackupFilesPresetEntry.DIGITSMAX, 3, c);
 
     suffixReverse.setLabels(MessageManager.getString("label.reverse_roll"),
             MessageManager.getString("label.increment_index"));
@@ -2171,12 +2233,13 @@ public class GPreferences extends JPanel
         }
         if (okay)
         {
+          backupfilesRevertButtonSetEnabled(true);
           updateBackupFilesExampleLabel();
         }
         else
         {
-          boolean savedSuffixReverse = Cache
-                  .getDefault(BackupFiles.REVERSE_ORDER, false);
+          boolean savedSuffixReverse = BackupFilesPresetEntry
+                  .getSavedBackupEntry().reverse;
           suffixReverse.setSelected(savedSuffixReverse);
         }
       }
@@ -2223,7 +2286,7 @@ public class GPreferences extends JPanel
     return suffixPanel;
   }
 
-  protected boolean confirmSuffixReverseChange()
+  private boolean confirmSuffixReverseChange()
   {
     boolean ret = false;
     String warningMessage = MessageManager
@@ -2252,6 +2315,7 @@ public class GPreferences extends JPanel
       @Override
       public void actionPerformed(ActionEvent e)
       {
+        backupfilesRevertButtonSetEnabled(true);
         updateBackupFilesExampleLabel();
       }
     });
@@ -2260,6 +2324,7 @@ public class GPreferences extends JPanel
       @Override
       public void actionPerformed(ActionEvent e)
       {
+        backupfilesRevertButtonSetEnabled(true);
         keepRollMaxOptionsEnabled();
         updateBackupFilesExampleLabel();
       }
@@ -2270,15 +2335,26 @@ public class GPreferences extends JPanel
       @Override
       public void stateChanged(ChangeEvent e)
       {
+        backupfilesRevertButtonSetEnabled(true);
         updateBackupFilesExampleLabel();
       }
 
     };
-    setIntegerSpinner(backupfilesRollMaxSpinner, 1, 999, 4, true, c);
+    setIntegerSpinner(backupfilesRollMaxSpinner,
+            BackupFilesPresetEntry.ROLLMAXMIN,
+            BackupFilesPresetEntry.ROLLMAXMAX, 4, true, c);
 
     backupfilesConfirmDelete.setLabels(
             MessageManager.getString("label.always_ask"),
             MessageManager.getString("label.auto_delete"));
+    backupfilesConfirmDelete.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        backupfilesRevertButtonSetEnabled(true);
+      }
+    });
     // update the enabled section
     keepRollMaxOptionsEnabled();
 
@@ -2314,13 +2390,6 @@ public class GPreferences extends JPanel
     kgbc.gridwidth = GridBagConstraints.REMAINDER;
     kgbc.fill = GridBagConstraints.HORIZONTAL;
     kgbc.weightx = 1.0;
-    /*
-    keepfilesPanel.add(backupfilesConfirmDelete.getTrueButton(), kgbc);
-    
-    // fourth row (indented)
-    kgbc.gridy = 3;
-    keepfilesPanel.add(backupfilesConfirmDelete.getFalseButton(), kgbc);
-    */
 
     JPanel jp = new JPanel();
     jp.setLayout(new FlowLayout());
@@ -2376,6 +2445,7 @@ public class GPreferences extends JPanel
     int uppersurround = 0;
     StringBuilder exampleSB = new StringBuilder();
     boolean firstLine = true;
+    int lineNumber = 0;
     if (reverse)
     {
 
@@ -2386,6 +2456,7 @@ public class GPreferences extends JPanel
         if (index == min + lowersurround && index < max - uppersurround - 1)
         {
           exampleSB.append("\n...");
+          lineNumber++;
         }
         else if (index > min + lowersurround && index < max - uppersurround)
         {
@@ -2400,6 +2471,7 @@ public class GPreferences extends JPanel
           else
           {
             exampleSB.append("\n");
+            lineNumber++;
           }
           exampleSB.append(BackupFilenameParts.getBackupFilename(index,
                   base, suffix, digits));
@@ -2439,6 +2511,7 @@ public class GPreferences extends JPanel
         if (index == min + lowersurround && index < max - uppersurround - 1)
         {
           exampleSB.append("\n...");
+          lineNumber++;
         }
         else if (index > min + lowersurround && index < max - uppersurround)
         {
@@ -2453,6 +2526,7 @@ public class GPreferences extends JPanel
           else
           {
             exampleSB.append("\n");
+            lineNumber++;
           }
           exampleSB.append(BackupFilenameParts.getBackupFilename(index,
                   base, suffix, digits));
@@ -2481,6 +2555,19 @@ public class GPreferences extends JPanel
 
     }
 
+    // add some extra empty lines to pad out the example files box. ugh, please
+    // tell
+    // me how to do this better
+    int remainingLines = lowersurround + uppersurround + 1 - lineNumber;
+    if (remainingLines > 0)
+    {
+      for (int i = 0; i < remainingLines; i++)
+      {
+        exampleSB.append("\n ");
+        lineNumber++;
+      }
+    }
+
     backupfilesExampleLabel.setText(exampleSB.toString());
   }
 
@@ -2492,10 +2579,10 @@ public class GPreferences extends JPanel
     {
       try
       {
-        i = Integer.parseInt((String) s.getValue());
+        i = ((Integer) s.getValue()).intValue();
       } catch (Exception e)
       {
-        System.out.println(
+        Cache.log.error(
                 "Exception casting the initial value of s.getValue()");
       }
     }
@@ -2511,6 +2598,10 @@ public class GPreferences extends JPanel
     {
       max = def;
     }
+    if (def < min)
+    {
+      def = min;
+    }
     SpinnerModel sModel = new SpinnerNumberModel(def, min, max, 1);
     s.setModel(sModel);
 
@@ -2527,12 +2618,12 @@ public class GPreferences extends JPanel
       i = (Integer) s.getValue();
     } catch (Exception e)
     {
-      System.out.println("Failed casting (Integer) JSpinner s.getValue()");
+      Cache.log.error("Failed casting (Integer) JSpinner s.getValue()");
     }
     return i;
   }
 
-  protected void keepRollMaxOptionsEnabled()
+  private void keepRollMaxOptionsEnabled()
   {
     boolean enabled = backupfilesKeepAll.isEnabled()
             && !backupfilesKeepAll.isSelected();
@@ -2541,10 +2632,10 @@ public class GPreferences extends JPanel
     backupfilesConfirmDelete.setEnabled(enabled);
   }
 
-  protected void backupfilesKeepAllSetEnabled(boolean tryEnabled)
+  private void backupfilesKeepAllSetEnabled(boolean tryEnabled)
   {
     boolean enabled = tryEnabled && enableBackupFiles.isSelected()
-            && getComboIntStringKey(backupfilesPresetsCombo) == 0
+            && customiseCheckbox.isSelected()
             && suffixTemplate.getText()
                     .indexOf(BackupFiles.NUM_PLACEHOLDER) > -1;
     keepfilesPanel.setEnabled(enabled);
@@ -2565,18 +2656,48 @@ public class GPreferences extends JPanel
   private void backupfilesSuffixTemplateSetEnabled(boolean tryEnabled)
   {
     boolean enabled = tryEnabled && enableBackupFiles.isSelected()
-            && getComboIntStringKey(backupfilesPresetsCombo) == 0;
+            && customiseCheckbox.isSelected();
     suffixPanel.setEnabled(enabled);
     suffixTemplateLabel.setEnabled(enabled);
     suffixTemplate.setEnabled(enabled);
     backupfilesSuffixTemplateDigitsSetEnabled();
   }
 
+  private void backupfilesRevertButtonSetEnabled(boolean tryEnabled)
+  {
+    boolean enabled = tryEnabled && enableBackupFiles.isSelected()
+            && customiseCheckbox.isSelected() && backupfilesCustomChanged();
+    revertButton.setEnabled(enabled);
+  }
+
+  private boolean backupfilesCustomChanged()
+  {
+    BackupFilesPresetEntry custom = BackupFilesPresetEntry.backupfilesPresetEntriesValues
+            .get(BackupFilesPresetEntry.BACKUPFILESSCHEMECUSTOM);
+    BackupFilesPresetEntry current = getBackupfilesCurrentEntry();
+    return !custom.equals(current);
+  }
+
+  protected BackupFilesPresetEntry getBackupfilesCurrentEntry()
+  {
+    String suffix = suffixTemplate.getText();
+    int digits = getSpinnerInt(suffixDigitsSpinner, 3);
+    boolean reverse = suffixReverse.isSelected();
+    boolean keepAll = backupfilesKeepAll.isSelected();
+    int rollMax = getSpinnerInt(backupfilesRollMaxSpinner, 3);
+    boolean confirmDelete = backupfilesConfirmDelete.isSelected();
+
+    BackupFilesPresetEntry bfpe = new BackupFilesPresetEntry(suffix, digits,
+            reverse, keepAll, rollMax, confirmDelete);
+
+    return bfpe;
+  }
+
   protected void backupfilesCustomOptionsSetEnabled()
   {
-    int scheme = getComboIntStringKey(backupfilesPresetsCombo);
-    boolean enabled = scheme == 0 && enableBackupFiles.isSelected();
+    boolean enabled = customiseCheckbox.isSelected();
 
+    backupfilesRevertButtonSetEnabled(enabled);
     backupfilesSuffixTemplateSetEnabled(enabled);
     backupfilesKeepAllSetEnabled(enabled);
   }
@@ -2592,7 +2713,10 @@ public class GPreferences extends JPanel
   {
     boolean enabled = enableBackupFiles.isSelected();
     presetsPanel.setEnabled(enabled);
+    presetsComboLabel.setEnabled(enabled);
     backupfilesPresetsCombo.setEnabled(enabled);
+    customiseCheckbox.setEnabled(enabled);
+    revertButton.setEnabled(enabled);
   }
 
   protected void backupsOptionsSetEnabled()
@@ -2781,7 +2905,6 @@ public class GPreferences extends JPanel
       button.setHorizontalAlignment(SwingConstants.CENTER);
       this.button.addActionListener(new ActionListener()
       {
-        @SuppressWarnings("synthetic-access")
         @Override
         public void actionPerformed(ActionEvent e)
         {
@@ -2807,85 +2930,3 @@ public class GPreferences extends JPanel
   }
 }
 
-class IntKeyStringValueEntry
-{
-  int k;
-
-  String v;
-
-  public IntKeyStringValueEntry(int k, String v)
-  {
-    this.k = k;
-    this.v = v;
-  }
-
-  @Override
-  public String toString()
-  {
-    return this.getValue();
-  }
-
-  public int getKey()
-  {
-    return k;
-  }
-
-  public String getValue()
-  {
-    return v;
-  }
-}
-
-class BackupFilesPresetEntry
-{
-  String suffix;
-
-  int digits;
-
-  boolean reverse;
-
-  boolean keepAll;
-
-  int rollMax;
-
-  boolean confirmDelete;
-
-  public BackupFilesPresetEntry(String suffix, int digits, boolean reverse,
-          boolean keepAll, int rollMax, boolean confirmDelete)
-  {
-    this.suffix = suffix;
-    this.digits = digits;
-    this.reverse = reverse;
-    this.keepAll = keepAll;
-    this.rollMax = rollMax;
-    this.confirmDelete = confirmDelete;
-  }
-}
-
-class BackupFilesPresetsComboBoxRenderer extends DefaultListCellRenderer
-{
-  /**
-   * 
-   */
-  private static final long serialVersionUID = 88L;
-
-  @Override
-  public Component getListCellRendererComponent(JList<?> list, Object value,
-          int index, boolean isSelected, boolean cellHasFocus)
-  {
-    super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
-    
-    try {
-      IntKeyStringValueEntry e = (IntKeyStringValueEntry) value;
-      if (e.getKey() == GPreferences.BACKUPFILESSCHEMECUSTOMISE)
-      {
-        // "Customise" item
-        this.setFont(this.getFont().deriveFont(Font.BOLD));
-      }
-    } catch (Exception e) {
-      return this;
-    }
-
-    return this;
-  }
-}