Merge branch 'develop' into improvement/JAL-4409_implement_extra_schemes_in_getdown
authorBen Soares <b.soares@dundee.ac.uk>
Mon, 27 May 2024 09:06:01 +0000 (10:06 +0100)
committerBen Soares <b.soares@dundee.ac.uk>
Mon, 27 May 2024 09:06:01 +0000 (10:06 +0100)
78 files changed:
getdown/lib/FJVL_VERSION
getdown/lib/JVL_VERSION
getdown/lib/getdown-core.jar
getdown/lib/getdown-launcher-local.jar
getdown/lib/getdown-launcher.jar
getdown/src/getdown/ant/pom.xml
getdown/src/getdown/core/pom.xml
getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java
getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/EnvConfig.java
getdown/src/getdown/core/src/main/java/com/threerings/getdown/util/Config.java
getdown/src/getdown/core/src/main/java/jalview/bin/Console.java [new file with mode: 0644]
getdown/src/getdown/core/src/main/java/jalview/bin/GetMemory.java
getdown/src/getdown/core/src/main/java/jalview/bin/HiDPISetting.java
getdown/src/getdown/core/src/main/java/jalview/bin/MemorySetting.java
getdown/src/getdown/core/src/main/java/jalview/util/ChannelProperties.java
getdown/src/getdown/core/src/main/java/jalview/util/ErrorLog.java [new file with mode: 0644]
getdown/src/getdown/core/src/main/java/jalview/util/HttpUtils.java [new file with mode: 0644]
getdown/src/getdown/core/src/main/java/jalview/util/LaunchUtils.java
getdown/src/getdown/core/src/main/java/jalview/util/StringUtils.java
getdown/src/getdown/launcher/pom.xml
getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/Getdown.java
getdown/src/getdown/launcher/src/main/java/com/threerings/getdown/launcher/GetdownApp.java
getdown/src/getdown/launcher/src/main/java/jalview/bin/StartupNotificationListener.java
getdown/src/getdown/mvn_cmd
getdown/src/getdown/pom.xml
j11lib/getdown-core.jar
j8lib/getdown-core.jar
src/jalview/analytics/Plausible.java
src/jalview/bin/Cache.java
src/jalview/bin/Commands.java
src/jalview/bin/GetMemory.java
src/jalview/bin/HiDPISetting.java
src/jalview/bin/Jalview.java
src/jalview/bin/JalviewLite.java
src/jalview/bin/MemorySetting.java
src/jalview/bin/argparser/ArgParser.java
src/jalview/ext/ensembl/EnsemblRestClient.java
src/jalview/ext/paradise/Annotate3D.java
src/jalview/ext/pymol/PymolManager.java
src/jalview/gui/CutAndPasteTransfer.java
src/jalview/gui/Desktop.java
src/jalview/gui/IdCanvas.java
src/jalview/gui/UserQuestionnaireCheck.java
src/jalview/io/BioJsHTMLOutput.java
src/jalview/io/FileParse.java
src/jalview/io/HTMLOutput.java
src/jalview/io/IdentifyFile.java
src/jalview/project/Jalview2XML.java
src/jalview/util/ArgParserUtils.java [new file with mode: 0644]
src/jalview/util/ChannelProperties.java
src/jalview/util/ErrorLog.java [new file with mode: 0644]
src/jalview/util/FileUtils.java
src/jalview/util/HttpUtils.java
src/jalview/util/LaunchUtils.java
src/jalview/util/StringUtils.java
src/jalview/util/UserAgent.java [new file with mode: 0644]
src/jalview/ws/dbsources/TDBeacons.java
src/jalview/ws/dbsources/Uniprot.java
src/jalview/ws/ebi/EBIFetchClient.java
src/jalview/ws/jws1/Annotate3D.java
src/jalview/ws/jws2/JabaWsServerQuery.java
src/jalview/ws/sifts/SiftsClient.java
src/jalview/ws/utils/UrlDownloadClient.java
test/jalview/gui/AlignmentPanelTest.java
test/jalview/gui/AnnotationLabelsTest2.java
test/jalview/gui/JvSwingUtilsTest.java
test/jalview/gui/SeqCanvasTest.java
test/jalview/gui/SeqPanelTest.java
test/jalview/io/IdentifyFileTest.java
test/jalview/project/Jalview2xmlTests.java
test/jalview/util/FileUtilsTest.java
test/jalview/util/HttpUtilsTest.java [new file with mode: 0644]
utils/dev_macos_install.sh
utils/install4j/auto_file_associations-i4j10.pl
utils/install4j/auto_file_associations-i4j8.pl [deleted file]
utils/install4j/file_associations_auto-Info_plist.xml
utils/install4j/file_associations_auto-install4j10.xml
utils/install4j/install4j10_template.install4j

index 2d83e61..21df89d 100644 (file)
@@ -1 +1 @@
-1.8.3-1.3.1_FJVL
+1.8.3-1.4.0_FJVL
index 7d618e2..2d02e7a 100644 (file)
@@ -1 +1 @@
-1.8.3-1.3.1_JVL
+1.8.3-1.4.0_JVL
index 3fc97b5..9a6626f 100644 (file)
Binary files a/getdown/lib/getdown-core.jar and b/getdown/lib/getdown-core.jar differ
index 6ba0a6d..3ba56f5 100644 (file)
Binary files a/getdown/lib/getdown-launcher-local.jar and b/getdown/lib/getdown-launcher-local.jar differ
index 7c75a34..e6b43ab 100644 (file)
Binary files a/getdown/lib/getdown-launcher.jar and b/getdown/lib/getdown-launcher.jar differ
index 4c91f74..ce84058 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.threerings.getdown</groupId>
     <artifactId>getdown</artifactId>
-    <version>1.8.3-1.3.1_FJVL</version>
+    <version>1.8.3-1.4.0_FJVL</version>
   </parent>
 
   <artifactId>getdown-ant</artifactId>
index 2e43522..c926ab2 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.threerings.getdown</groupId>
     <artifactId>getdown</artifactId>
-    <version>1.8.3-1.3.1_FJVL</version>
+    <version>1.8.3-1.4.0_FJVL</version>
   </parent>
 
   <artifactId>getdown-core</artifactId>
index 435ebbd..fca6b4d 100644 (file)
@@ -11,8 +11,6 @@ import java.net.MalformedURLException;
 import java.net.Proxy;
 import java.net.SocketAddress;
 import java.net.InetSocketAddress;
-import java.net.URI;
-import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.net.URLConnection;
@@ -31,6 +29,7 @@ import java.util.zip.GZIPInputStream;
 
 import jalview.bin.HiDPISetting;
 import jalview.bin.MemorySetting;
+import jalview.util.HttpUtils;
 import jalview.util.LaunchUtils;
 
 import com.threerings.getdown.util.*;
@@ -1117,61 +1116,22 @@ public class Application
             }
         }
 
-        // test for jalview/s URL. Insert startupNotification URI into start of _appargs
+        // test for jalviewX://... URI. Insert startupNotification URI into start of _appargs
         if (! StringUtil.isBlank(_jalviewUri)) {
           _appargs.add(0, _jalviewUri);
         }
+        /* don't convert jalviewX:// URIs to https:// URLs as Jalview can now do that
         if (_appargs.size() > 0) {
-          String uri = _appargs.get(0);
-          try {
-            log.info("TRYING TO PARSE URL '"+uri+"'");
-            URI jalviewUri = new URI(uri);
-            if (jalviewUri != null) {
-              String scheme = jalviewUri.getScheme();
-              if (scheme != null && (scheme.equals("jalview") || scheme.equals("jalviews"))) {
-                boolean https = jalviewUri.getScheme().equals("jalviews");
-                String host = jalviewUri.getHost();
-                int port = jalviewUri.getPort();
-                String file = jalviewUri.getPath();
-                String ref = jalviewUri.getFragment();
-                String query = jalviewUri.getQuery();
-                
-                _appargs.clear();
-                if (host != null && host.length() > 0) {
-                  URL newUrl = new URL(
-                          (https?"https":"http")
-                          + "://"
-                          + host
-                          + (port > -1? String.valueOf(port) : "")
-                          + jalviewUri.getRawPath()
-                          + (query != null && query.length() > 0 ? "?" + jalviewUri.getRawQuery() : "")
-                          );
-                  _appargs.add(newUrl.toString());
-                } else {
-                  _appargs.add(file);
-                }
-                
-                if (ref != null && ref.length() > 0) {
-                  String[] refArgs = ref.split("&");
-                  for (String refArg : refArgs) {
-                    if (refArg.startsWith("jvmmempc=")) {
-                      jvmmempc = refArg.substring(9);
-                      continue;
-                    }
-                    if (refArg.startsWith("jvmmemmax=")) {
-                      jvmmemmax = refArg.substring(10);
-                      continue;
-                    }
-                    _appargs.add(URLDecoder.decode(refArg, "UTF-8"));
-                  }
-                }
-                
-              }
-            }
-          } catch (URISyntaxException e) {
-            log.error("Malformed jalview URI", uri);
+          String jalviewUri = _appargs.get(0);
+          log.info("Trying to parse uri '"+jalviewUri+"'");
+          if (HttpUtils.isJalviewSchemeUri(jalviewUri)) {
+            String jalviewUrl = HttpUtils.equivalentJalviewUrl(jalviewUri);
+            log.info("Turned url '"+jalviewUri+"' into '"+jalviewUrl+"'");
+            _appargs.clear();
+            _appargs.add(jalviewUrl);
           }
         }
+        */
         
         for (String argString: _appargs) {
           if (argString.startsWith("-jvmmempc=")) {
@@ -1237,9 +1197,8 @@ public class Application
         }
 
         // almost finally check the startup file arguments
-        for (File f : _startupFiles) {
-          _appargs.add(f.getAbsolutePath());
-          break; // Only add one file to open
+        for (String f : _startupFiles) {
+          _appargs.add(HttpUtils.startsWithHttpOrHttps(f)?f:new File(f).getAbsolutePath());
         }
         
         // check if one arg with recognised extension
@@ -1976,54 +1935,67 @@ public class Application
     {
         return new File(appdir, path);
     }
-
-    public static void setStartupFilesFromParameterString(String p) {
+    
+    public static void setStartupFilesFromParameters(List<String> parameters) {
       // multiple files *might* be passed in as space separated quoted filenames
       String q = "\"";
-      if (!StringUtil.isBlank(p)) {
-        String[] filenames;
-        // split quoted params or treat as single string array
-        if (p.startsWith(q) && p.endsWith(q)) {
-          // this fails if, e.g.
-          // p=q("stupidfilename\" " "otherfilename")
-          // let's hope no-one ever ends a filename with '" '
-          filenames = p.substring(q.length(),p.length()-q.length()).split(q+" "+q);
-        } else {
-          // single unquoted filename
-          filenames = new String[]{p};
-        }
-
-        // check for locator file.  Only allow one locator file to be double clicked (if multiple files opened, ignore locator files)
-        String locatorFilename = filenames.length >= 1 ? filenames[0] : null;
-        if (
-                !StringUtil.isBlank(locatorFilename)
-                && locatorFilename.toLowerCase(Locale.ROOT).endsWith("."+Application.LOCATOR_FILE_EXTENSION)
-                ) {
-          setLocatorFile(locatorFilename);
-          // remove the locator filename from the filenames array
-          String[] otherFilenames = new String[filenames.length - 1];
-          System.arraycopy(filenames, 1, otherFilenames, 0, otherFilenames.length);
-          filenames = otherFilenames;
-        }
-
-        for (int i = 0; i < filenames.length; i++) {
-          String filename = filenames[i];
-          // skip any other locator files in a multiple file list
-          if (filename.startsWith("jalview://") || filename.startsWith("jalviews://")) {
-            setJalviewUri(filename);
-          } else if (! filename.toLowerCase(Locale.ROOT).endsWith("."+Application.LOCATOR_FILE_EXTENSION)) {
+      for (String p: parameters) {
+        if (!StringUtil.isBlank(p)) {
+          String filename;
+          // split quoted params or treat as single string array
+          if (p.startsWith(q) && p.endsWith(q)) {
+            filename = p.substring(q.length(),p.length()-q.length());
+          } else {
+            // single unquoted filename
+            filename = p;
+          }
+          
+          /* Now letting Jalview convert these URIs.
+          // convert jalviewX://... URLs
+          if (HttpUtils.isJalviewSchemeUri(filename)) {
+            filename = HttpUtils.equivalentJalviewUrl(filename);
+          }
+          */
+
+          // check for locator file.  Only allow one locator file to be double clicked (if multiple files opened, ignore locator files)
+          if (filename.toLowerCase(Locale.ROOT).endsWith("."+Application.LOCATOR_FILE_EXTENSION)) {
+            // convert jalviewX://... JVL files
+            setLocatorFile(HttpUtils.equivalentJalviewUrl(filename));
+          } else {
+            // skip any other locator files in a multiple file list
             addStartupFile(filename);
           }
         }
       }
     }
-    
+        
+    public static String getStartupFilesParameterString(List<String> parameters, boolean changeJalviewSchemeUris) {
+      StringBuilder sb = new StringBuilder();
+      boolean first = true;
+      for(String f : parameters) {
+        if (first) {
+          first = false;
+        } else {
+          sb.append(' ');
+        }
+        String p = changeJalviewSchemeUris ? HttpUtils.equivalentJalviewUrl(f) : f;
+        if (p.contains(" ")) {
+          sb.append('"');
+          sb.append(p);
+          sb.append('"');
+        } else {
+          sb.append(p);
+        }
+      }
+      return sb.toString();
+    }
+
     public static void setLocatorFile(String filename) {
-      _locatorFile = new File(filename);
+      _locatorFile = filename;
     }
     
     public static void addStartupFile(String filename) {
-      _startupFiles.add(new File(filename));
+      _startupFiles.add(filename);
     }
     
     public static void setJalviewUri(String uri) {
@@ -2040,8 +2012,17 @@ public class Application
       try {
         Config tmpConfig = null;
         Map<String, Object> tmpData = new HashMap<>();
-        if (_locatorFile.exists()) {
-          tmpConfig = Config.parseConfig(_locatorFile,  opts);
+        if (HttpUtils.startsWithHttpOrHttps(_locatorFile)) {
+          URL locatorUrl = new URL(_locatorFile);
+          try (InputStream in = ConnectionUtil.open(proxy, locatorUrl, 0, 0).getInputStream();
+                 InputStreamReader reader = new InputStreamReader(in, UTF_8);
+                 BufferedReader bin = new BufferedReader(reader)) {
+                   tmpConfig = Config.parseConfig(bin, opts);
+          }
+        } else if (new File(_locatorFile).exists()) {
+          tmpConfig = Config.parseConfig(new File(_locatorFile),  opts);
+        }
+        if (tmpConfig != null) {
           // appbase is sanitised in HostWhitelist
           Map<String, Object> tmpConfigData = tmpConfig.getData();
           if (tmpConfig != null) {
@@ -2138,8 +2119,8 @@ public class Application
     protected static final String ENV_VAR_PREFIX = "%ENV.";
     protected static final Pattern ENV_VAR_PATTERN = Pattern.compile("%ENV\\.(.*?)%");
  
-    protected static File _locatorFile;
-    protected static List<File> _startupFiles = new ArrayList<>();
+    protected static String _locatorFile;
+    protected static List<String> _startupFiles = new ArrayList<>();
     protected static String _jalviewUri;
     public static final String LOCATOR_FILE_EXTENSION = "jvl";
 
index 77997d2..862c18e 100644 (file)
@@ -15,6 +15,9 @@ import java.security.cert.X509Certificate;
 import java.util.*;
 
 import com.threerings.getdown.util.StringUtil;
+
+import jalview.util.HttpUtils;
+
 import com.threerings.getdown.data.Application;
 
 /** Configuration that comes from our "environment" (command line args, sys props, etc.). */
@@ -145,10 +148,9 @@ public final class EnvConfig {
         int skipArgs = 2;
         // Look for locator file, pass to Application and remove from appArgs
         String argvLocatorFilename = argv.length > 2 ? argv[2] : null;
-        if (
-                !StringUtil.isBlank(argvLocatorFilename)
-                && argvLocatorFilename.toLowerCase(Locale.ROOT).endsWith("."+Application.LOCATOR_FILE_EXTENSION)
-                ) {
+        if (!StringUtil.isBlank(argvLocatorFilename)
+              && argvLocatorFilename.toLowerCase(Locale.ROOT).endsWith("."+Application.LOCATOR_FILE_EXTENSION)) {
+          argvLocatorFilename = HttpUtils.equivalentJalviewUrl(argvLocatorFilename);
           notes.add(Note.info("locatorFilename in args: '"+argv[2]+"'"));
           Application.setLocatorFile(argvLocatorFilename);
           
index c7e2933..6681c35 100644 (file)
@@ -5,9 +5,13 @@
 
 package com.threerings.getdown.util;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.net.MalformedURLException;
@@ -174,38 +178,73 @@ public class Config
      * one key/value pair in the config file was associated with the same key.
      */
     public static Config parseConfig (File source, ParseOpts opts)
-        throws IOException
-    {
-        Map<String, Object> data = new HashMap<>();
-
-        // I thought that we could use HashMap<String, String[]> and put new String[] {pair[1]} for
-        // the null case, but it mysteriously dies on launch, so leaving it as HashMap<String,
-        // Object> for now
-        for (String[] pair : parsePairs(source, opts)) {
-            Object value = data.get(pair[0]);
-            if (value == null) {
-                data.put(pair[0], pair[1]);
-            } else if (value instanceof String) {
-                data.put(pair[0], new String[] { (String)value, pair[1] });
-            } else if (value instanceof String[]) {
-                String[] values = (String[])value;
-                String[] nvalues = new String[values.length+1];
-                System.arraycopy(values, 0, nvalues, 0, values.length);
-                nvalues[values.length] = pair[1];
-                data.put(pair[0], nvalues);
+            throws IOException
+        {
+            Map<String, Object> data = new HashMap<>();
+
+            // I thought that we could use HashMap<String, String[]> and put new String[] {pair[1]} for
+            // the null case, but it mysteriously dies on launch, so leaving it as HashMap<String,
+            // Object> for now
+            for (String[] pair : parsePairs(source, opts)) {
+                Object value = data.get(pair[0]);
+                if (value == null) {
+                    data.put(pair[0], pair[1]);
+                } else if (value instanceof String) {
+                    data.put(pair[0], new String[] { (String)value, pair[1] });
+                } else if (value instanceof String[]) {
+                    String[] values = (String[])value;
+                    String[] nvalues = new String[values.length+1];
+                    System.arraycopy(values, 0, nvalues, 0, values.length);
+                    nvalues[values.length] = pair[1];
+                    data.put(pair[0], nvalues);
+                }
+            }
+
+            // special magic for the getdown.txt config: if the parsed data contains 'strict_comments =
+            // true' then we reparse the file with strict comments (i.e. # is only assumed to start a
+            // comment in column 0)
+            if (!opts.strictComments && Boolean.parseBoolean((String)data.get("strict_comments"))) {
+                opts.strictComments = true;
+                return parseConfig(source, opts);
             }
-        }
 
-        // special magic for the getdown.txt config: if the parsed data contains 'strict_comments =
-        // true' then we reparse the file with strict comments (i.e. # is only assumed to start a
-        // comment in column 0)
-        if (!opts.strictComments && Boolean.parseBoolean((String)data.get("strict_comments"))) {
-            opts.strictComments = true;
-            return parseConfig(source, opts);
+            return new Config(data);
         }
 
-        return new Config(data);
-    }
+    public static Config parseConfig (Reader source, ParseOpts opts)
+            throws IOException
+        {
+            Map<String, Object> data = new HashMap<>();
+
+            // I thought that we could use HashMap<String, String[]> and put new String[] {pair[1]} for
+            // the null case, but it mysteriously dies on launch, so leaving it as HashMap<String,
+            // Object> for now
+            for (String[] pair : parsePairs(source, opts)) {
+                Object value = data.get(pair[0]);
+                if (value == null) {
+                    data.put(pair[0], pair[1]);
+                } else if (value instanceof String) {
+                    data.put(pair[0], new String[] { (String)value, pair[1] });
+                } else if (value instanceof String[]) {
+                    String[] values = (String[])value;
+                    String[] nvalues = new String[values.length+1];
+                    System.arraycopy(values, 0, nvalues, 0, values.length);
+                    nvalues[values.length] = pair[1];
+                    data.put(pair[0], nvalues);
+                }
+            }
+
+            // special magic for the getdown.txt config: if the parsed data contains 'strict_comments =
+            // true' then we reparse the file with strict comments (i.e. # is only assumed to start a
+            // comment in column 0)
+            if (!opts.strictComments && Boolean.parseBoolean((String)data.get("strict_comments"))) {
+                opts.strictComments = true;
+                source.reset();
+                return parseConfig(source, opts);
+            }
+
+            return new Config(data);
+        }
 
     public Config (Map<String,  Object> data) {
         _data = data;
diff --git a/getdown/src/getdown/core/src/main/java/jalview/bin/Console.java b/getdown/src/getdown/core/src/main/java/jalview/bin/Console.java
new file mode 100644 (file)
index 0000000..66fc865
--- /dev/null
@@ -0,0 +1,11 @@
+package jalview.bin;
+
+public class Console {
+  public static boolean initLogger() {
+    return false;
+  }
+  public static void outPrintln(String s) {
+  }
+  public static void errPrintln(String s) {
+  }
+}
index b01dfb8..1bcc841 100644 (file)
@@ -23,6 +23,8 @@ package jalview.bin;
 import java.lang.management.ManagementFactory;
 import java.lang.management.OperatingSystemMXBean;
 
+import jalview.util.ErrorLog;
+
 /**
  * Isolated class to ascertain physical memory of the system using
  * com.sun.management.OperatingSystemMXBean class's getTotalPhysicalMemorySize
@@ -61,7 +63,7 @@ class GetMemory
     } catch (NoClassDefFoundError e)
     {
       // com.sun.management.OperatingSystemMXBean doesn't exist in this JVM
-      System.err.println(
+      ErrorLog.errPrintln(
               "No com.sun.management.OperatingSystemMXBean: cannot get total physical memory size");
     }
 
index 2bce673..871a6f7 100644 (file)
  */
 package jalview.bin;
 
+import java.awt.HeadlessException;
 import java.util.Locale;
 
-import java.awt.HeadlessException;
+import jalview.util.ErrorLog;
 
 public class HiDPISetting
 {
@@ -117,7 +118,7 @@ public class HiDPISetting
         }
       } catch (NumberFormatException e)
       {
-        System.err.println(setHiDPIScalePropertyName + " property give ("
+        ErrorLog.errPrintln(setHiDPIScalePropertyName + " property give ("
                 + setHiDPIScaleProperty + ") but not parseable as integer");
       }
     }
@@ -135,7 +136,7 @@ public class HiDPISetting
       try
       {
         int existingPropertyVal = Integer.parseInt(existingProperty);
-        System.out.println("Existing " + scalePropertyName + " is "
+        ErrorLog.outPrintln("Existing " + scalePropertyName + " is "
                 + existingPropertyVal);
         if (existingPropertyVal > 1)
         {
@@ -144,8 +145,9 @@ public class HiDPISetting
         }
       } catch (NumberFormatException e)
       {
-        System.out.println("Could not convert property " + scalePropertyName
-                + " vale '" + existingProperty + "' to number");
+        ErrorLog.outPrintln(
+                "Could not convert property " + scalePropertyName
+                        + " vale '" + existingProperty + "' to number");
       }
     }
 
@@ -159,7 +161,11 @@ public class HiDPISetting
       dpi = screenInfo.getScreenResolution();
     } catch (HeadlessException e)
     {
-      System.err.println("Cannot get screen resolution: " + e.getMessage());
+      if (isLinux)
+      {
+        ErrorLog.errPrintln(
+                "Cannot get screen resolution: " + e.getMessage());
+      }
     }
 
     // try and get screen size height and width
@@ -171,8 +177,11 @@ public class HiDPISetting
       mindimension = Math.min(height, width);
     } catch (HeadlessException e)
     {
-      System.err.println(
-              "Cannot get screen size height and width:" + e.getMessage());
+      if (isLinux)
+      {
+        ErrorLog.errPrintln("Cannot get screen size height and width:"
+                + e.getMessage());
+      }
     }
 
     // attempt at a formula for scaling based on screen dpi and mindimension.
index bb545cb..dbef0d9 100644 (file)
@@ -24,6 +24,8 @@ package jalview.bin;
 
 import java.util.Locale;
 
+import jalview.util.ErrorLog;
+
 /**
  * Methods to decide on appropriate memory setting for Jalview based on two
  * optionally provided values: jvmmempc - the maximum percentage of total
@@ -37,8 +39,10 @@ import java.util.Locale;
  */
 public class MemorySetting
 {
+  // This must match the value of Arg.JVMMEMPC.getName()
   public static final String MAX_HEAPSIZE_PERCENT_PROPERTY_NAME = "jvmmempc";
 
+  // This must match the value of Arg.JVMMEMMAX.getName()
   public static final String MAX_HEAPSIZE_PROPERTY_NAME = "jvmmemmax";
 
   private static final int MAX_HEAPSIZE_PERCENT_DEFAULT = 90; // 90%
@@ -354,7 +358,7 @@ public class MemorySetting
     else
     {
       // number too big for a Long. Limit to Long.MAX_VALUE
-      System.out.println("Memory parsing of '" + memString
+      ErrorLog.outPrintln("Memory parsing of '" + memString
               + "' produces number too big.  Limiting to Long.MAX_VALUE="
               + Long.MAX_VALUE);
       return Long.MAX_VALUE;
@@ -395,7 +399,7 @@ public class MemorySetting
     ADJUSTMENT_MESSAGE = reason;
     if (!quiet)
     {
-      System.out.println(reason);
+      ErrorLog.outPrintln(reason);
     }
   }
 
index 4832588..ffcb6a1 100644 (file)
@@ -86,7 +86,7 @@ public class ChannelProperties
     if (channelPropsURL == null)
     {
       // complete failure of channel_properties, set all properties to defaults
-      System.err.println("Failed to find '/" + CHANNEL_PROPERTIES_FILENAME
+      ErrorLog.errPrintln("Failed to find '/" + CHANNEL_PROPERTIES_FILENAME
               + "' file at '"
               + (channelPropsURL == null ? "null"
                       : channelPropsURL.toString())
@@ -97,12 +97,12 @@ public class ChannelProperties
     {
       try
       {
-        InputStream channelPropsIS = channelPropsURL.openStream();
+        InputStream channelPropsIS = HttpUtils.openStream(channelPropsURL);
         tryChannelProps.load(channelPropsIS);
         channelPropsIS.close();
       } catch (IOException e)
       {
-        System.err.println(e.getMessage());
+        ErrorLog.errPrintln(e.getMessage());
         // return false;
       }
     }
@@ -157,10 +157,10 @@ public class ChannelProperties
         channelProps.load(is);
       } catch (FileNotFoundException e)
       {
-        System.err.println(e.getMessage());
+        ErrorLog.errPrintln(e.getMessage());
       } catch (IOException e)
       {
-        System.err.println(e.getMessage());
+        ErrorLog.errPrintln(e.getMessage());
       }
     }
   }
@@ -214,7 +214,7 @@ public class ChannelProperties
       }
       else
       {
-        System.err.println("Failed to get channel property '" + key + "'");
+        ErrorLog.errPrintln("Failed to get channel property '" + key + "'");
       }
     }
     return null;
@@ -266,7 +266,7 @@ public class ChannelProperties
       img = imgIcon == null ? null : imgIcon.getImage();
       if (img == null)
       {
-        System.err.println(
+        ErrorLog.errPrintln(
                 "Failed to load channel image " + key + "=" + path);
         if (!useClassDefaultImage)
         {
@@ -293,7 +293,7 @@ public class ChannelProperties
       {
         return urlMap().getOrDefault(key, null);
       }
-      System.err.println(
+      ErrorLog.errPrintln(
               "Do not use getImageURL(key) before using getImage(key...)");
     }
     return null;
diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/ErrorLog.java b/getdown/src/getdown/core/src/main/java/jalview/util/ErrorLog.java
new file mode 100644 (file)
index 0000000..e94b59e
--- /dev/null
@@ -0,0 +1,58 @@
+package jalview.util;
+
+public class ErrorLog
+{
+  private static boolean hasConsole = true;
+
+  public static void outPrintln(String message)
+  {
+    println(message, false);
+  }
+
+  public static void errPrintln(String message)
+  {
+    println(message, true);
+  }
+
+  public static void println(String message, boolean err)
+  {
+    if (hasConsole)
+    {
+      try
+      {
+        hasConsole = jalview.bin.Console.initLogger();
+        if (hasConsole)
+        {
+          if (err)
+          {
+            jalview.bin.Console.errPrintln(message);
+          }
+          else
+          {
+            jalview.bin.Console.outPrintln(message);
+          }
+        }
+      } catch (Exception e)
+      {
+        e.printStackTrace();
+      } catch (NoClassDefFoundError t)
+      {
+        hasConsole = false;
+        System.err.println(
+                "jalview.util.ErrorLog has no jalview.bin.Console. Using System.err and System.out.");
+      }
+    }
+    if (!hasConsole)
+    {
+      if (err)
+      {
+        System.err.println("jalview.util.ErrorLog: " + message);
+      }
+      else
+      {
+        System.out.println("jalview.util.ErrorLog: " + message);
+
+      }
+    }
+  }
+}
diff --git a/getdown/src/getdown/core/src/main/java/jalview/util/HttpUtils.java b/getdown/src/getdown/core/src/main/java/jalview/util/HttpUtils.java
new file mode 100644 (file)
index 0000000..04a820d
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.ProtocolException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+public class HttpUtils
+{
+
+  /**
+   * Returns true if it is possible to open an input stream at the given URL,
+   * else false. The input stream is closed.
+   * 
+   * @param url
+   * @return
+   */
+  public static boolean isValidUrl(String url)
+  {
+    InputStream is = null;
+    try
+    {
+      is = HttpUtils.openStream(new URL(url));
+      if (is != null)
+      {
+        return true;
+      }
+    } catch (IOException x)
+    {
+      // MalformedURLException, FileNotFoundException
+      return false;
+    } finally
+    {
+      if (is != null)
+      {
+        try
+        {
+          is.close();
+        } catch (IOException e)
+        {
+          // ignore
+        }
+      }
+    }
+    return false;
+  }
+
+  public static boolean startsWithHttpOrHttps(String file)
+  {
+    return file.startsWith("http://") || file.startsWith("https://");
+  }
+
+  /**
+   * wrapper to get/post to a URL or check headers
+   * 
+   * @param url
+   * @param ids
+   * @param readTimeout
+   * @return
+   * @throws IOException
+   * @throws ProtocolException
+   */
+  public static boolean checkUrlAvailable(URL url, int readTimeout)
+          throws IOException, ProtocolException
+  {
+    // jalview.bin.Console.outPrintln(System.currentTimeMillis() + " " + url);
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod("HEAD");
+    connection.setDoInput(true);
+    connection.setUseCaches(false);
+    connection.setConnectTimeout(300);
+    connection.setReadTimeout(readTimeout);
+
+    // HttpURLConnection doesn't follow redirects from http to https. It should!
+    HttpURLConnection conn = followConnection(connection);
+    return conn.getResponseCode() == 200;
+  }
+
+  /**
+   * wrapper to follow a URL connection ALLOWING redirects from http to https
+   * 
+   * @param HttpURLConnection
+   *          conn0
+   * @return HttpUrlConnection conn
+   */
+  public static HttpURLConnection followConnection(HttpURLConnection conn0)
+          throws IOException
+  {
+    URL url = conn0.getURL();
+    if (url == null)
+    {
+      return null;
+    }
+    HttpURLConnection conn = null;
+    int response = conn0.getResponseCode();
+    boolean followed = false;
+    if (response >= 300 && response < 400 && conn0.getFollowRedirects())
+    {
+      // we are only checking for a redirect from http to https
+      if ("http".equals(url.getProtocol()))
+      {
+        URL loc = new URL(conn0.getHeaderField("Location"));
+        if (loc != null && "https".equals(loc.getProtocol()))
+        {
+          conn = (HttpURLConnection) loc.openConnection();
+          conn.setRequestMethod(conn0.getRequestMethod());
+          conn.setDoInput(conn0.getDoInput());
+          conn.setUseCaches(conn0.getUseCaches());
+          conn.setConnectTimeout(conn0.getConnectTimeout());
+          conn.setReadTimeout(conn0.getReadTimeout());
+          conn.setInstanceFollowRedirects(
+                  conn0.getInstanceFollowRedirects());
+          followed = true;
+        }
+      }
+    }
+    return followed && conn != null ? conn : conn0;
+  }
+
+  /**
+   * wrapper to follow a URL connection ALLOWING redirects from http to https
+   * 
+   * @param URL
+   *          url
+   * @return HttpUrlConnection conn
+   */
+  public static HttpURLConnection openConnection(URL url) throws IOException
+  {
+    if (url == null)
+    {
+      return null;
+    }
+    HttpURLConnection conn = null;
+    String protocol = url.getProtocol();
+    if ("http".equals(protocol) || "https".equals(protocol))
+    {
+      HttpURLConnection conn0 = (HttpURLConnection) url.openConnection();
+      if (conn0 != null)
+      {
+        conn = HttpUtils.followConnection(conn0);
+      }
+      else
+      {
+        conn = conn0;
+      }
+    }
+    return conn;
+  }
+
+  /**
+   * wrapper to follow a URL connection ALLOWING redirects from http to https
+   * and return the followed InputStream
+   * 
+   * @param URL
+   *          url
+   * @return HttpUrlConnection conn
+   */
+  public static InputStream openStream(URL url) throws IOException
+  {
+    if (url == null)
+    {
+      return null;
+    }
+    InputStream is = null;
+    String protocol = url.getProtocol();
+    if ("http".equals(protocol) || "https".equals(protocol))
+    {
+      HttpURLConnection conn = HttpUtils
+              .followConnection((HttpURLConnection) url.openConnection());
+      if (conn != null)
+      {
+        is = conn.getInputStream();
+      }
+    }
+    else
+    {
+      is = url.openStream();
+    }
+    return is;
+  }
+
+  /**
+   * check if a jalview:// scheme URL is given
+   * 
+   * @param String
+   *          uri
+   * @return boolean
+   */
+  public static boolean isJalviewSchemeUri(String jalviewUriString)
+  {
+    URI jalviewUri;
+    try
+    {
+      jalviewUri = new URI(jalviewUriString);
+    } catch (URISyntaxException e)
+    {
+      return false;
+    }
+    String scheme = jalviewUri.getScheme();
+    if (scheme == null || !scheme.startsWith("jalview"))
+    {
+      return false;
+    }
+    return scheme.length() == 7 // jalview
+            || scheme.length() == 8 // jalviewX
+            || scheme.substring(7).equals("http") // jalviewhttp
+            || scheme.substring(7).equals("https"); // jalviewhttps
+  }
+
+  /**
+   * convert a jalview scheme URI to its equivalent URL or path
+   * 
+   * @param String
+   *          uri
+   * @return String
+   */
+  public static String equivalentJalviewUrl(String jalviewUriString)
+  {
+    if (!isJalviewSchemeUri(jalviewUriString))
+    {
+      // not a jalviewUriString, hand it back
+      return jalviewUriString;
+    }
+    URI jalviewUri;
+    try
+    {
+      jalviewUri = new URI(jalviewUriString);
+    } catch (URISyntaxException e)
+    {
+      return null;
+    }
+    String scheme = jalviewUri.getScheme();
+    String host = jalviewUri.getHost();
+    if (host != null && host.length() > 0
+            || scheme.substring(7).startsWith("http"))
+    {
+      URI newUri;
+      try
+      {
+        newUri = new URI(scheme.equals("jalviewhttp") ? "http" : "https",
+                jalviewUri.getUserInfo(), host, jalviewUri.getPort(),
+                jalviewUri.getPath(), jalviewUri.getQuery(),
+                jalviewUri.getFragment());
+        // return a URL
+        return newUri.toURL().toString();
+      } catch (URISyntaxException | MalformedURLException e)
+      {
+        ErrorLog.errPrintln("Trying to convert '" + jalviewUriString
+                + "' to URL failed");
+      }
+    }
+    else
+    {
+      // return a file path (not a file URI)
+      return jalviewUri.getPath();
+    }
+    return null;
+  }
+}
index 784eb5a..5894fec 100644 (file)
@@ -31,7 +31,6 @@ import java.util.Properties;
 
 public class LaunchUtils
 {
-
   // setting these is LaunchUtils so don't need to import Platform
   public final static boolean isMac = System.getProperty("os.name")
           .indexOf("Mac") > -1;
@@ -75,7 +74,7 @@ public class LaunchUtils
         return null;
       } catch (IOException e)
       {
-        System.err.println(e.getMessage());
+        ErrorLog.errPrintln(e.getMessage());
         return null;
       }
     }
@@ -105,7 +104,7 @@ public class LaunchUtils
     try
     {
       URL localFileURL = new URL(buildDetails);
-      InputStream in = localFileURL.openStream();
+      InputStream in = HttpUtils.openStream(localFileURL);
       Properties buildProperties = new Properties();
       buildProperties.load(in);
       in.close();
@@ -113,22 +112,21 @@ public class LaunchUtils
               null);
       if (JCV == null)
       {
-        System.out.println(
-                "Could not obtain JAVA_COMPILE_VERSION for comparison");
+        ErrorLog.errPrintln("Could not obtain JAVA_COMPILE_VERSION for comparison");
         return -2;
       }
       JAVA_COMPILE_VERSION = Integer.parseInt(JCV);
     } catch (MalformedURLException e)
     {
-      System.err.println("Could not find " + buildDetails);
+      ErrorLog.errPrintln("Could not find " + buildDetails);
       return -3;
     } catch (IOException e)
     {
-      System.err.println("Could not load " + buildDetails);
+      ErrorLog.errPrintln("Could not load " + buildDetails);
       return -4;
     } catch (NumberFormatException e)
     {
-      System.err.println("Could not parse JAVA_COMPILE_VERSION");
+      ErrorLog.errPrintln("Could not parse JAVA_COMPILE_VERSION");
       return -5;
     }
 
@@ -152,7 +150,7 @@ public class LaunchUtils
       String JV = System.getProperty("java.version");
       if (JV == null)
       {
-        System.out.println("Could not obtain java.version for comparison");
+        ErrorLog.errPrintln("Could not obtain java.version for comparison");
         return -2;
       }
       if (JV.startsWith("1."))
@@ -163,7 +161,7 @@ public class LaunchUtils
               : Integer.parseInt(JV.substring(0, JV.indexOf(".")));
     } catch (NumberFormatException e)
     {
-      System.err.println("Could not parse java.version");
+      ErrorLog.errPrintln("Could not parse java.version");
       return -3;
     }
     return JAVA_VERSION;
@@ -184,7 +182,7 @@ public class LaunchUtils
 
     if (java_compile_version <= 0 || java_version <= 0)
     {
-      System.out.println("Could not make Java version check");
+      ErrorLog.errPrintln("Could not make Java version check");
       return true;
     }
     // Warn if these java.version and JAVA_COMPILE_VERSION conditions exist
index 1c67c92..42c52a7 100644 (file)
@@ -202,18 +202,18 @@ public class StringUtils
       jv.clear();
       if (DEBUG)
       {
-        System.err.println("Array from '" + delimiter
+        ErrorLog.errPrintln("Array from '" + delimiter
                 + "' separated List:\n" + v.length);
         for (int i = 0; i < v.length; i++)
         {
-          System.err.println("item " + i + " '" + v[i] + "'");
+          ErrorLog.errPrintln("item " + i + " '" + v[i] + "'");
         }
       }
       return v;
     }
     if (DEBUG)
     {
-      System.err.println(
+      ErrorLog.errPrintln(
               "Empty Array from '" + delimiter + "' separated List");
     }
     return null;
@@ -249,13 +249,13 @@ public class StringUtils
       {
         System.err
                 .println("Returning '" + separator + "' separated List:\n");
-        System.err.println(v);
+        ErrorLog.errPrintln(v.toString());
       }
       return v.toString();
     }
     if (DEBUG)
     {
-      System.err.println(
+      ErrorLog.errPrintln(
               "Returning empty '" + separator + "' separated List\n");
     }
     return "" + separator;
@@ -586,6 +586,15 @@ public class StringUtils
     return min < text.length() + 1 ? min : -1;
   }
 
+  public static boolean equalsIgnoreCase(String s1, String s2)
+  {
+    if (s1 == null || s2 == null)
+    {
+      return s1 == s2;
+    }
+    return s1.toLowerCase(Locale.ROOT).equals(s2.toLowerCase(Locale.ROOT));
+  }
+
   public static int indexOfFirstWhitespace(String text)
   {
     int index = -1;
index c6b9ff3..876efd2 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.threerings.getdown</groupId>
     <artifactId>getdown</artifactId>
-    <version>1.8.3-1.3.1_FJVL</version>
+    <version>1.8.3-1.4.0_FJVL</version>
   </parent>
 
   <artifactId>getdown-launcher</artifactId>
index 01bf370..ed5570c 100644 (file)
@@ -1060,7 +1060,7 @@ public abstract class Getdown extends Thread
             BufferedReader reader = new BufferedReader(new InputStreamReader(in));
             String line;
             while ((line = reader.readLine()) != null) {
-                out.print(line);
+                out.println(line);
                 out.flush();
             }
         } catch (IOException ioe) {
index fee1d3e..3eb9450 100644 (file)
@@ -35,13 +35,14 @@ import com.threerings.getdown.util.LaunchUtil;
 import com.threerings.getdown.util.StringUtil;
 import static com.threerings.getdown.Log.log;
 import jalview.bin.StartupNotificationListener;
+import jalview.util.HttpUtils;
 
 /**
  * The main application entry point for Getdown.
  */
 public class GetdownApp
 {
-  public static String startupFilesParameterString = "";
+  public static List<String> startupFilesParameters = new ArrayList<>();
   /**
    * The main entry point of the Getdown launcher application.
    */
@@ -120,7 +121,8 @@ public class GetdownApp
     log.info("-- User Home: " + System.getProperty("user.home"));
     log.info("-- Cur dir: " + System.getProperty("user.dir"));
     log.info("-- Launcher version: "+Build.version());
-    log.info("-- startupFilesParameterString: " + startupFilesParameterString);
+    log.info("-- startupFilesParameterString: " + getStartupFilesParameterString(getStartupFilesParameters(), false));
+    log.info("-- getStartupFilesParameterString(): " + getStartupFilesParameterString(getStartupFilesParameters(), true));
     log.info("---------------------------------------------");
 
     Getdown app = new Getdown(envc) {
@@ -284,20 +286,40 @@ public class GetdownApp
       protected JFrame _frame;
     };
     
-    String startupFile = getStartupFilesParameterString();
-    if (!StringUtil.isBlank(startupFile)) {
-      Application.setStartupFilesFromParameterString(startupFile);
+    if (getStartupFilesParameters().size() > 0) {
+      Application.setStartupFilesFromParameters(getStartupFilesParameters());
     }
  
     app.start();
     return app;
   }
   
-  public static void setStartupFilesParameterString(String parameters) {
-    startupFilesParameterString = parameters;
+  public static void addStartupFilesParameter(String parameter) {
+    startupFilesParameters.add(parameter);
   }
   
-  public static String getStartupFilesParameterString() {
-    return startupFilesParameterString;
+  public static List<String> getStartupFilesParameters() {
+    return startupFilesParameters;
+  }
+  
+  public static String getStartupFilesParameterString(List<String> parameters, boolean changeJalviewSchemeUris) {
+    StringBuilder sb = new StringBuilder();
+    boolean first = true;
+    for(String f : parameters) {
+      if (first) {
+        first = false;
+      } else {
+        sb.append(' ');
+      }
+      String p = changeJalviewSchemeUris ? HttpUtils.equivalentJalviewUrl(f) : f;
+      if (p.contains(" ")) {
+        sb.append('"');
+        sb.append(p);
+        sb.append('"');
+      } else {
+        sb.append(p);
+      }
+    }
+    return sb.toString();
   }
 }
index b3cfa9a..cb313c0 100644 (file)
@@ -13,9 +13,9 @@ public class StartupNotificationListener {
       com.install4j.api.launcher.StartupNotification.registerStartupListener(
         new com.install4j.api.launcher.StartupNotification.Listener() {
           @Override
-          public void startupPerformed(String parameters) { 
-            log.info("StartupNotification.Listener.startupPerformed: '"+parameters+"'");
-            GetdownApp.setStartupFilesParameterString(parameters);
+          public void startupPerformed(String parameter) { 
+            log.info("StartupNotification.Listener.startupPerformed: '"+parameter+"'");
+            GetdownApp.addStartupFilesParameter(parameter);
           }
         }
       );
index 10942f8..59cb761 100755 (executable)
@@ -3,7 +3,7 @@
 if [ x$JVLVERSION != x ]; then
   export VERSION=$JVLVERSION
 else
-  export VERSION=1.8.3-1.3.1_JVL
+  export VERSION=1.8.3-1.4.0_JVL
 fi
 
 if [ x${VERSION%_JVL} = x$VERSION ]; then
index cf32333..c3c6fc3 100644 (file)
@@ -10,7 +10,7 @@
   <groupId>com.threerings.getdown</groupId>
   <artifactId>getdown</artifactId>
   <packaging>pom</packaging>
-  <version>1.8.3-1.3.1_FJVL</version>
+  <version>1.8.3-1.4.0_FJVL</version>
 
   <name>getdown</name>
   <description>An application installer and updater.</description>
index 3fc97b5..9a6626f 100644 (file)
Binary files a/j11lib/getdown-core.jar and b/j11lib/getdown-core.jar differ
index 3fc97b5..9a6626f 100644 (file)
Binary files a/j8lib/getdown-core.jar and b/j8lib/getdown-core.jar differ
index ab2de77..2852734 100644 (file)
@@ -29,7 +29,6 @@ import java.lang.invoke.MethodHandles;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.net.URLConnection;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 import java.util.AbstractMap;
@@ -45,6 +44,7 @@ import jalview.bin.Cache;
 import jalview.bin.Console;
 import jalview.util.ChannelProperties;
 import jalview.util.HttpUtils;
+import jalview.util.UserAgent;
 
 public class Plausible
 {
@@ -122,7 +122,7 @@ public class Plausible
     // random clientId to make User-Agent unique (to register analytic)
     clientId = String.format("%08x", new Random().nextInt());
 
-    USER_AGENT = HttpUtils.getUserAgent(
+    USER_AGENT = UserAgent.getUserAgent(
             MethodHandles.lookup().lookupClass().getCanonicalName() + " "
                     + clientId);
   }
@@ -213,8 +213,7 @@ public class Plausible
     try
     {
       URL url = new URL(urlSb.toString());
-      URLConnection urlConnection = url.openConnection();
-      HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
+      HttpURLConnection httpURLConnection = HttpUtils.openConnection(url);
       httpURLConnection.setRequestMethod("POST");
       httpURLConnection.setDoOutput(true);
 
@@ -553,8 +552,7 @@ public class Plausible
     try
     {
       URL url = new URL(CONFIG_API_BASE_URL);
-      URLConnection urlConnection = url.openConnection();
-      HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
+      HttpURLConnection httpURLConnection = HttpUtils.openConnection(url);
       httpURLConnection.setRequestMethod("GET");
       httpURLConnection.setRequestProperty("User-Agent", USER_AGENT);
       httpURLConnection.setConnectTimeout(5000);
index 558b859..e188829 100755 (executable)
@@ -67,6 +67,7 @@ import jalview.structure.StructureImportSettings;
 import jalview.urls.IdOrgSettings;
 import jalview.util.ChannelProperties;
 import jalview.util.ColorUtils;
+import jalview.util.HttpUtils;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.ws.sifts.SiftsSettings;
@@ -412,7 +413,7 @@ public class Cache
         try
         {
           // props file provided as URL
-          fis = new URL(propertiesFile).openStream();
+          fis = HttpUtils.openStream(new URL(propertiesFile));
           if (!Jalview.quiet())
           {
             jalview.bin.Console.outPrintln(
@@ -584,7 +585,7 @@ public class Cache
               URL url = new URL(remoteBuildPropertiesUrl);
 
               BufferedReader in = new BufferedReader(
-                      new InputStreamReader(url.openStream()));
+                      new InputStreamReader(HttpUtils.openStream(url)));
 
               Properties remoteBuildProperties = new Properties();
               remoteBuildProperties.load(in);
@@ -1453,10 +1454,11 @@ public class Cache
                 if (customProxySet &&
                 // we have a username but no password for the scheme being
                 // requested
-                (protocol.equalsIgnoreCase("http")
-                        && (httpUser != null && httpUser.length() > 0
-                                && (httpPassword == null
-                                        || httpPassword.length == 0)))
+                        (protocol.equalsIgnoreCase("http")
+                                && (httpUser != null
+                                        && httpUser.length() > 0
+                                        && (httpPassword == null
+                                                || httpPassword.length == 0)))
                         || (protocol.equalsIgnoreCase("https")
                                 && (httpsUser != null
                                         && httpsUser.length() > 0
index b6a5a25..97ab98e 100644 (file)
@@ -22,6 +22,7 @@ package jalview.bin;
 
 import java.awt.Color;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
@@ -235,7 +236,8 @@ public class Commands
       {
         Arg a = av.getArg();
         SubVals sv = av.getSubVals();
-        String openFile = av.getValue();
+        String openFile0 = av.getValue();
+        String openFile = HttpUtils.equivalentJalviewUrl(openFile0);
         if (openFile == null)
           continue;
 
@@ -286,6 +288,10 @@ public class Commands
         try
         {
           format = new IdentifyFile().identify(openFile, protocol);
+        } catch (FileNotFoundException e0)
+        {
+          addError((protocol == DataSourceType.URL ? "File at URL" : "File")
+                  + " '" + openFile + "' not found");
         } catch (FileFormatException e1)
         {
           addError("Unknown file format for '" + openFile + "'");
@@ -312,6 +318,10 @@ public class Commands
           {
             af = fileLoader.LoadFileWaitTillLoaded(openFile, protocol,
                     format);
+            if (!openFile.equals(openFile0))
+            {
+              af.setTitle(openFile0);
+            }
           } catch (Throwable thr)
           {
             xception = true;
@@ -1301,18 +1311,22 @@ public class Commands
 
   private void colourAlignFrame(AlignFrame af, ColourSchemeI cs)
   {
-    try {
-    SwingUtilities.invokeAndWait(new Runnable()
+    try
     {
-      @Override
-      public void run()
+      SwingUtilities.invokeAndWait(new Runnable()
       {
-        // Note that cs == null removes colour scheme from af
-        af.changeColour(cs);
-      }
-    }); } catch (Exception x) {
-      Console.trace("Interrupted whilst waiting for colorAlignFrame action",x);
-      
+        @Override
+        public void run()
+        {
+          // Note that cs == null removes colour scheme from af
+          af.changeColour(cs);
+        }
+      });
+    } catch (Exception x)
+    {
+      Console.trace("Interrupted whilst waiting for colorAlignFrame action",
+              x);
+
     }
   }
 
index 5332704..1bcc841 100644 (file)
@@ -23,6 +23,8 @@ package jalview.bin;
 import java.lang.management.ManagementFactory;
 import java.lang.management.OperatingSystemMXBean;
 
+import jalview.util.ErrorLog;
+
 /**
  * Isolated class to ascertain physical memory of the system using
  * com.sun.management.OperatingSystemMXBean class's getTotalPhysicalMemorySize
@@ -61,7 +63,7 @@ class GetMemory
     } catch (NoClassDefFoundError e)
     {
       // com.sun.management.OperatingSystemMXBean doesn't exist in this JVM
-      jalview.bin.Console.errPrintln(
+      ErrorLog.errPrintln(
               "No com.sun.management.OperatingSystemMXBean: cannot get total physical memory size");
     }
 
index e14c032..871a6f7 100644 (file)
@@ -23,6 +23,8 @@ package jalview.bin;
 import java.awt.HeadlessException;
 import java.util.Locale;
 
+import jalview.util.ErrorLog;
+
 public class HiDPISetting
 {
   private static final int hidpiThreshold = 160;
@@ -116,9 +118,8 @@ public class HiDPISetting
         }
       } catch (NumberFormatException e)
       {
-        jalview.bin.Console.errPrintln(setHiDPIScalePropertyName
-                + " property give (" + setHiDPIScaleProperty
-                + ") but not parseable as integer");
+        ErrorLog.errPrintln(setHiDPIScalePropertyName + " property give ("
+                + setHiDPIScaleProperty + ") but not parseable as integer");
       }
     }
     if (setHiDPI && setHiDPIScale > 0)
@@ -135,8 +136,8 @@ public class HiDPISetting
       try
       {
         int existingPropertyVal = Integer.parseInt(existingProperty);
-        jalview.bin.Console.outPrintln("Existing " + scalePropertyName
-                + " is " + existingPropertyVal);
+        ErrorLog.outPrintln("Existing " + scalePropertyName + " is "
+                + existingPropertyVal);
         if (existingPropertyVal > 1)
         {
           setHiDPIScale(existingPropertyVal);
@@ -144,7 +145,7 @@ public class HiDPISetting
         }
       } catch (NumberFormatException e)
       {
-        jalview.bin.Console.outPrintln(
+        ErrorLog.outPrintln(
                 "Could not convert property " + scalePropertyName
                         + " vale '" + existingProperty + "' to number");
       }
@@ -162,7 +163,7 @@ public class HiDPISetting
     {
       if (isLinux)
       {
-        jalview.bin.Console.errPrintln(
+        ErrorLog.errPrintln(
                 "Cannot get screen resolution: " + e.getMessage());
       }
     }
@@ -178,9 +179,8 @@ public class HiDPISetting
     {
       if (isLinux)
       {
-        jalview.bin.Console
-                .errPrintln("Cannot get screen size height and width:"
-                        + e.getMessage());
+        ErrorLog.errPrintln("Cannot get screen size height and width:"
+                + e.getMessage());
       }
     }
 
index e343b0f..6d28da1 100755 (executable)
@@ -23,6 +23,7 @@ package jalview.bin;
 import java.awt.Color;
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -103,6 +104,7 @@ import jalview.util.HttpUtils;
 import jalview.util.LaunchUtils;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.util.UserAgent;
 import jalview.ws.jws2.Jws2Discoverer;
 
 /**
@@ -639,7 +641,7 @@ public class Jalview implements JalviewObjectI
     {
       headless = true;
     }
-    System.setProperty("http.agent", HttpUtils.getUserAgent());
+    System.setProperty("http.agent", UserAgent.getUserAgent());
 
     try
     {
@@ -938,9 +940,12 @@ public class Jalview implements JalviewObjectI
       try
       {
         format = new IdentifyFile().identify(file, protocol);
-      } catch (FileFormatException e1)
+      } catch (FileNotFoundException e)
       {
-        // TODO ?
+        Console.error("File at '" + file + "' not found", e);
+      } catch (FileFormatException e)
+      {
+        Console.error("File '" + file + "' format not recognised", e);
       }
 
       AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
@@ -1211,9 +1216,12 @@ public class Jalview implements JalviewObjectI
         try
         {
           format = new IdentifyFile().identify(file, protocol);
+        } catch (FileNotFoundException e)
+        {
+          Console.error("File at '" + file + "' not found", e);
         } catch (FileFormatException e)
         {
-          // TODO what?
+          Console.error("File '" + file + "' format not recognised", e);
         }
       }
 
index b73fffc..7e1296e 100644 (file)
  */
 package jalview.bin;
 
+import java.applet.Applet;
+import java.awt.Button;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.EventQueue;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
 import java.util.Locale;
+import java.util.StringTokenizer;
+import java.util.Vector;
 
 import jalview.analysis.AlignmentUtils;
 import jalview.api.StructureSelectionManagerProvider;
@@ -56,28 +76,6 @@ import jalview.structure.StructureSelectionManager;
 import jalview.util.ColorUtils;
 import jalview.util.HttpUtils;
 import jalview.util.MessageManager;
-
-import java.applet.Applet;
-import java.awt.Button;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.EventQueue;
-import java.awt.Font;
-import java.awt.Frame;
-import java.awt.Graphics;
-import java.awt.event.ActionEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
 import netscape.javascript.JSObject;
 
 /**
@@ -1366,7 +1364,7 @@ public class JalviewLite extends Applet
         try
         {
           BufferedReader reader = new BufferedReader(
-                  new InputStreamReader(url.openStream()));
+                  new InputStreamReader(HttpUtils.openStream(url)));
           String line;
           while ((line = reader.readLine()) != null)
           {
@@ -2253,8 +2251,8 @@ public class JalviewLite extends Applet
         PDBEntry[] pdb = new PDBEntry[pdbs.size()];
         String[][] chains = new String[pdbs.size()][];
         String[] protocols = new String[pdbs.size()];
-        for (int pdbsi = 0, pdbsiSize = pdbs
-                .size(); pdbsi < pdbsiSize; pdbsi++)
+        for (int pdbsi = 0,
+                pdbsiSize = pdbs.size(); pdbsi < pdbsiSize; pdbsi++)
         {
           Object[] o = (Object[]) pdbs.elementAt(pdbsi);
           pdb[pdbsi] = (PDBEntry) o[0];
index 738d1e7..dbef0d9 100644 (file)
@@ -24,7 +24,7 @@ package jalview.bin;
 
 import java.util.Locale;
 
-import jalview.bin.argparser.Arg;
+import jalview.util.ErrorLog;
 
 /**
  * Methods to decide on appropriate memory setting for Jalview based on two
@@ -39,11 +39,11 @@ import jalview.bin.argparser.Arg;
  */
 public class MemorySetting
 {
-  public static final String MAX_HEAPSIZE_PERCENT_PROPERTY_NAME = Arg.JVMMEMPC
-          .getName();
+  // This must match the value of Arg.JVMMEMPC.getName()
+  public static final String MAX_HEAPSIZE_PERCENT_PROPERTY_NAME = "jvmmempc";
 
-  public static final String MAX_HEAPSIZE_PROPERTY_NAME = Arg.JVMMEMMAX
-          .getName();
+  // This must match the value of Arg.JVMMEMMAX.getName()
+  public static final String MAX_HEAPSIZE_PROPERTY_NAME = "jvmmemmax";
 
   private static final int MAX_HEAPSIZE_PERCENT_DEFAULT = 90; // 90%
 
@@ -358,7 +358,7 @@ public class MemorySetting
     else
     {
       // number too big for a Long. Limit to Long.MAX_VALUE
-      jalview.bin.Console.outPrintln("Memory parsing of '" + memString
+      ErrorLog.outPrintln("Memory parsing of '" + memString
               + "' produces number too big.  Limiting to Long.MAX_VALUE="
               + Long.MAX_VALUE);
       return Long.MAX_VALUE;
@@ -399,7 +399,7 @@ public class MemorySetting
     ADJUSTMENT_MESSAGE = reason;
     if (!quiet)
     {
-      jalview.bin.Console.outPrintln(reason);
+      ErrorLog.outPrintln(reason);
     }
   }
 
index 12e1b1d..e7cca35 100644 (file)
@@ -33,11 +33,13 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import jalview.bin.Cache;
 import jalview.bin.Console;
 import jalview.bin.Jalview;
 import jalview.bin.Jalview.ExitCode;
 import jalview.bin.argparser.Arg.Opt;
 import jalview.bin.argparser.Arg.Type;
+import jalview.util.ArgParserUtils;
 import jalview.util.FileUtils;
 import jalview.util.HttpUtils;
 
@@ -317,6 +319,14 @@ public class ArgParser
       return;
     }
 
+    // preprocess for associated files only if no actual --args supplied
+    Console.debug("Supplied args are " + args);
+    if (!dd && !Cache.getDefault("NOARGPREPROCESSING", false))
+    {
+      ArgParserUtils.preProcessArgs(args);
+      Console.debug("Preprocessed args are " + args);
+    }
+
     if (bsa != null)
     {
       this.bootstrapArgs = bsa;
index 709136c..f7651be 100644 (file)
@@ -36,6 +36,7 @@ import javax.ws.rs.HttpMethod;
 
 import org.json.simple.parser.ParseException;
 
+import jalview.util.HttpUtils;
 import jalview.util.Platform;
 import jalview.util.StringUtils;
 
@@ -342,7 +343,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
   {
     // jalview.bin.Console.outPrintln(System.currentTimeMillis() + " " + url);
 
-    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    HttpURLConnection connection = HttpUtils.openConnection(url);
 
     /*
      * POST method allows multiple queries in one request; it is supported for
index 3817ee9..aafed20 100644 (file)
@@ -36,6 +36,7 @@ import org.apache.http.message.BasicNameValuePair;
 import org.json.simple.parser.ContentHandler;
 import org.json.simple.parser.ParseException;
 
+import jalview.util.HttpUtils;
 import jalview.util.JSONUtils;
 import jalview.util.MessageManager;
 import jalview.ws.HttpClientUtils;
@@ -180,7 +181,7 @@ public class Annotate3D
     // return processJsonResponseFor(new
     // InputStreamReader(geturl.openStream()));
     ArrayList<Reader> readers = new ArrayList<>();
-    readers.add(new InputStreamReader(geturl.openStream()));
+    readers.add(new InputStreamReader(HttpUtils.openStream(geturl)));
     return readers.iterator();
   }
 
index ddc8d84..05c5053 100644 (file)
@@ -38,6 +38,7 @@ import jalview.bin.Cache;
 import jalview.bin.Console;
 import jalview.gui.Preferences;
 import jalview.structure.StructureCommandI;
+import jalview.util.HttpUtils;
 import jalview.util.Platform;
 
 public class PymolManager
@@ -167,7 +168,7 @@ public class PymolManager
     try
     {
       URL realUrl = new URL(rpcUrl);
-      HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
+      HttpURLConnection conn = HttpUtils.openConnection(realUrl);
       conn.setRequestProperty("accept", "*/*");
       conn.setRequestProperty("content-type", "text/xml");
       conn.setDoOutput(true);
index bc3c0d2..91f8189 100644 (file)
@@ -28,6 +28,7 @@ import java.awt.datatransfer.Transferable;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseEvent;
+import java.io.FileNotFoundException;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -226,6 +227,9 @@ public class CutAndPasteTransfer extends GCutAndPasteTransfer
     try
     {
       format = new IdentifyFile().identify(text, DataSourceType.PASTE);
+    } catch (FileNotFoundException e0)
+    {
+      // this won't happen
     } catch (FileFormatException e1)
     {
       // leave as null
index bbd4dae..4c30a06 100644 (file)
@@ -54,6 +54,7 @@ import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyVetoException;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.lang.reflect.Field;
@@ -1400,10 +1401,13 @@ public class Desktop extends jalview.jbgui.GDesktop
         try
         {
           format = new IdentifyFile().identify(url, DataSourceType.URL);
+        } catch (FileNotFoundException e)
+        {
+          jalview.bin.Console.error("URL '" + url + "' not found", e);
         } catch (FileFormatException e)
         {
-          // TODO revise error handling, distinguish between
-          // URL not found and response not valid
+          jalview.bin.Console.error(
+                  "File at URL '" + url + "' format not recognised", e);
         }
 
         if (format == null)
index 76020c7..7a4cf84 100755 (executable)
@@ -312,7 +312,7 @@ public class IdCanvas extends JPanel implements ViewportListenerI
     if (alignViewport.getWrapAlignment())
     {
       drawIdsWrapped(g, alignViewport, startSeq, getHeight(),
-              manuallyAdjusted ? panelWidth : -1, forGUI);
+              isManuallyAdjusted() ? panelWidth : -1, forGUI);
       return;
     }
 
index 385eb57..004cf4a 100644 (file)
  */
 package jalview.gui;
 
-import jalview.bin.Cache;
-import jalview.bin.Console;
-import jalview.util.MessageManager;
-
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
 import java.net.URL;
 
-import javax.swing.JOptionPane;
+import jalview.bin.Cache;
+import jalview.bin.Console;
+import jalview.util.HttpUtils;
+import jalview.util.MessageManager;
 
 public class UserQuestionnaireCheck implements Runnable
 {
@@ -63,7 +62,7 @@ public class UserQuestionnaireCheck implements Runnable
     // see if we have already responsed to this questionnaire or get a new
     // qid/rid pair
     BufferedReader br = new BufferedReader(
-            new InputStreamReader(qurl.openStream()));
+            new InputStreamReader(HttpUtils.openStream(qurl)));
     String qresp;
     while ((qresp = br.readLine()) != null)
     {
index 13bfb8c..9d9eaf8 100644 (file)
@@ -37,6 +37,7 @@ import jalview.gui.AlignmentPanel;
 import jalview.gui.OOMWarning;
 import jalview.json.binding.biojs.BioJSReleasePojo;
 import jalview.json.binding.biojs.BioJSRepositoryPojo;
+import jalview.util.HttpUtils;
 import jalview.util.MessageManager;
 
 public class BioJsHTMLOutput extends HTMLOutput
@@ -178,7 +179,7 @@ public class BioJsHTMLOutput extends HTMLOutput
     try
     {
       URL resourceUrl = new URL(url);
-      is = new BufferedInputStream(resourceUrl.openStream());
+      is = new BufferedInputStream(HttpUtils.openStream(resourceUrl));
       BufferedReader br = new BufferedReader(new InputStreamReader(is));
       responseStrBuilder = new StringBuilder();
       String lineContent;
index 1f51d8c..57b2ce5 100755 (executable)
@@ -25,6 +25,7 @@ import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
@@ -35,6 +36,7 @@ import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
+import java.net.UnknownHostException;
 import java.util.zip.GZIPInputStream;
 
 import jalview.api.AlignExportSettingsI;
@@ -42,6 +44,7 @@ import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureSettingsModelI;
 import jalview.bin.Console;
+import jalview.util.HttpUtils;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 
@@ -313,16 +316,18 @@ public class FileParse
   {
     errormessage = "URL NOT FOUND";
     URL url = new URL(urlStr);
-    URLConnection _conn = url.openConnection();
+    URLConnection _conn = HttpUtils.openConnection(url);
     if (_conn instanceof HttpURLConnection)
     {
-      HttpURLConnection conn = (HttpURLConnection) _conn;
+      HttpURLConnection conn = HttpUtils
+              .followConnection((HttpURLConnection) _conn);
       int rc = conn.getResponseCode();
       if (rc != HttpURLConnection.HTTP_OK)
       {
-        throw new IOException(
-                "Response status from " + urlStr + " was " + rc);
+        throw new FileNotFoundException("Response status from " + urlStr
+                + " was " + conn.getResponseCode());
       }
+      _conn = conn;
     }
     else
     {
@@ -422,7 +427,7 @@ public class FileParse
    * @throws IOException
    */
   public FileParse(Object file, DataSourceType sourceType)
-          throws MalformedURLException, IOException
+          throws MalformedURLException, FileNotFoundException, IOException
   {
     if (file instanceof File)
     {
@@ -435,11 +440,12 @@ public class FileParse
   }
 
   private void parse(File file, String fileStr, DataSourceType sourceType,
-          boolean isFileObject) throws IOException
+          boolean isFileObject) throws FileNotFoundException, IOException
   {
     bytes = Platform.getFileBytes(file);
     dataSourceType = sourceType;
     error = false;
+    boolean filenotfound = false;
 
     if (sourceType == DataSourceType.FILE)
     {
@@ -498,6 +504,12 @@ public class FileParse
           String suffixLess = extractSuffix(fileStr);
           if (suffixLess == null)
           {
+            if (e instanceof FileNotFoundException
+                    || e instanceof UnknownHostException)
+            {
+              errormessage = "File at URL '" + fileStr + "' not found";
+              filenotfound = true;
+            }
             throw (e);
           }
           else
@@ -507,7 +519,12 @@ public class FileParse
               checkURLSource(suffixLess);
             } catch (IOException e2)
             {
-              errormessage = "BAD URL WITH OR WITHOUT SUFFIX";
+              errormessage = "BAD URL WITH OR WITHOUT SUFFIX '" + fileStr
+                      + "'";
+              if (e instanceof FileNotFoundException)
+              {
+                filenotfound = true;
+              }
               throw (e); // just pass back original - everything was wrong.
             }
           }
@@ -556,6 +573,12 @@ public class FileParse
     if (dataIn == null || error)
     {
       // pass up the reason why we have no source to read from
+      if (filenotfound)
+      {
+        throw new FileNotFoundException(MessageManager
+                .formatMessage("label.url_not_found", new String[]
+                { errormessage }));
+      }
       throw new IOException(MessageManager.formatMessage(
               "exception.failed_to_read_data_from_source", new String[]
               { errormessage }));
@@ -805,7 +828,8 @@ public class FileParse
       return new BufferedReader(new FileReader((File) file));
     case URL:
       URL url = new URL(file.toString());
-      in = new BufferedReader(new InputStreamReader(url.openStream()));
+      in = new BufferedReader(
+              new InputStreamReader(HttpUtils.openStream(url)));
       break;
     case RELATIVE_URL: // JalviewJS only
       bytes = Platform.getFileAsBytes(file.toString());
index 0b541e2..a17911c 100644 (file)
@@ -35,6 +35,7 @@ import jalview.datamodel.AlignmentExportData;
 import jalview.gui.AlignmentPanel;
 import jalview.gui.IProgressIndicator;
 import jalview.io.exceptions.ImageOutputException;
+import jalview.util.HttpUtils;
 import jalview.util.MessageManager;
 
 public abstract class HTMLOutput implements Runnable
@@ -118,7 +119,7 @@ public abstract class HTMLOutput implements Runnable
     {
       try
       {
-        isReader = new InputStreamReader(url.openStream());
+        isReader = new InputStreamReader(HttpUtils.openStream(url));
         buffReader = new BufferedReader(isReader);
         String line;
         String lineSeparator = System.getProperty("line.separator");
index baee531..8251c22 100755 (executable)
@@ -21,6 +21,7 @@
 package jalview.io;
 
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.Locale;
 
@@ -38,7 +39,7 @@ public class IdentifyFile
   private static final String XMLHEADER = "<?XML VERSION=\"1.0\" ENCODING=\"UTF-8\" STANDALONE=\"YES\"?>";
 
   public FileFormatI identify(Object file, DataSourceType protocol)
-          throws FileFormatException
+          throws FileFormatException, FileNotFoundException
   {
     // BH 2018
     return (file instanceof File ? identify((File) file, protocol)
@@ -83,10 +84,11 @@ public class IdentifyFile
    * @throws FileFormatException
    */
   public FileFormatI identify(String file, DataSourceType sourceType)
-          throws FileFormatException
+          throws FileFormatException, FileNotFoundException
   {
     String emessage = "UNIDENTIFIED FILE PARSING ERROR";
     FileParse parser = null;
+    FileNotFoundException fnf = null;
     try
     {
       parser = new FileParse(file, sourceType);
@@ -94,6 +96,14 @@ public class IdentifyFile
       {
         return identify(parser);
       }
+    } catch (FileNotFoundException e)
+    {
+      fnf = e;
+      emessage = "Could not find '" + file + "'";
+      Console.error("Could not find '" + file + "'", e);
+    } catch (IOException e)
+    {
+      Console.error("Error whilst trying to read " + file, e);
     } catch (Exception e)
     {
       Console.error("Error whilst identifying " + file, e);
@@ -103,6 +113,10 @@ public class IdentifyFile
     {
       throw new FileFormatException(parser.errormessage);
     }
+    if (fnf != null)
+    {
+      throw (fnf);
+    }
     throw new FileFormatException(emessage);
   }
 
@@ -494,6 +508,10 @@ public class IdentifyFile
       try
       {
         type = ider.identify(args[i], DataSourceType.FILE);
+      } catch (FileNotFoundException e)
+      {
+        Console.error(String.format("Error '%s' fetching file %s", args[i],
+                e.getMessage()));
       } catch (FileFormatException e)
       {
         Console.error(
index 2f4052a..f2720e0 100644 (file)
@@ -91,7 +91,6 @@ import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.ContactListI;
 import jalview.datamodel.ContactMatrix;
 import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.DBRefEntry;
@@ -99,7 +98,6 @@ import jalview.datamodel.FloatContactMatrix;
 import jalview.datamodel.GeneLocus;
 import jalview.datamodel.GraphLine;
 import jalview.datamodel.GroupSet;
-import jalview.datamodel.GroupSetI;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Point;
 import jalview.datamodel.RnaViewerModel;
@@ -3130,7 +3128,7 @@ public class Jalview2XML
             // jalview.bin.Console.outPrintln("Jalview2XML: opening url
             // jarInputStream for "
             // + _url);
-            return new JarInputStream(_url.openStream());
+            return new JarInputStream(HttpUtils.openStream(_url));
           }
           else
           {
diff --git a/src/jalview/util/ArgParserUtils.java b/src/jalview/util/ArgParserUtils.java
new file mode 100644 (file)
index 0000000..fabbc76
--- /dev/null
@@ -0,0 +1,172 @@
+package jalview.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import jalview.bin.Cache;
+import jalview.bin.argparser.Arg;
+import jalview.io.FileFormatI;
+import jalview.io.FileFormats;
+
+public class ArgParserUtils
+{
+  private static Set<String> alignmentExtensions = null;
+
+  private static Set<String> annotationsExtensions = null;
+
+  private static Set<String> featuresExtensions = null;
+
+  private static Set<String> treeExtensions = null;
+
+  public static void preProcessArgs(List<String> filenames)
+  {
+    // Running through the arguments to look for '-arg' or '--arg' should
+    // already have happened, not doing it again.
+    if (alignmentExtensions == null)
+    {
+      setValidExtensions();
+    }
+
+    Set<String> filesSet = new HashSet<>(filenames);
+
+    List<Arg> argSet = new ArrayList<>();
+    argSet.add(Arg.ANNOTATIONS);
+    argSet.add(Arg.FEATURES);
+    argSet.add(Arg.TREE);
+
+    Map<Arg, Set<String>> argExtensionsMap = new HashMap<>();
+    argExtensionsMap.put(Arg.ANNOTATIONS, annotationsExtensions);
+    argExtensionsMap.put(Arg.FEATURES, featuresExtensions);
+    argExtensionsMap.put(Arg.TREE, treeExtensions);
+
+    Map<String, BaseInfo> baseInfoMap = new HashMap<>();
+
+    // we make a copy to run through, and delete associated filenames from the
+    // original
+    final List<String> filenamesCopy = new ArrayList<>(filenames);
+    for (String filename : filenamesCopy)
+    {
+      if (filename == null)
+      {
+        continue;
+      }
+      String ext = FileUtils.getExtension(filename);
+      if (ext != null && ext.length() > 0
+              && alignmentExtensions.contains(ext))
+      {
+        BaseInfo bi = new BaseInfo(filename);
+
+        // this includes the dot at the end of the basename
+        String base = FileUtils.getBase(filename);
+
+        for (Arg arg : argSet)
+        {
+          for (String possibleExt : argExtensionsMap.get(arg))
+          {
+            String possibleFile = base + possibleExt;
+            if (filesSet.contains(possibleFile))
+            {
+              bi.putAssociatedFile(arg, possibleFile);
+              filenames.remove(possibleFile);
+              break;
+            }
+          }
+        }
+
+        baseInfoMap.put(filename, bi);
+      }
+    }
+
+    // now we go through the saved associated files and add them back in to the
+    // right places with the appropriate argument
+    for (String filename : baseInfoMap.keySet())
+    {
+      BaseInfo bi = baseInfoMap.get(filename);
+
+      int pos = filenames.indexOf(filename);
+      if (bi.associatedFiles != null)
+      {
+        for (Arg a : bi.associatedFiles.keySet())
+        {
+          String associatedFile = bi.associatedFiles.get(a);
+          if (associatedFile == null)
+          {
+            // shouldn't happen!
+            continue;
+          }
+          filenames.add(pos + 1, a.argString());
+          filenames.add(pos + 2,
+                  HttpUtils.equivalentJalviewUrl(associatedFile));
+        }
+      }
+      // add an --open arg to separate from other files
+      filenames.add(pos, Arg.OPEN.argString());
+    }
+  }
+
+  private static void setValidExtensions()
+  {
+    alignmentExtensions = new HashSet<>();
+    FileFormats ffs = FileFormats.getInstance();
+    List<String> validFormats = ffs.getReadableFormats();
+
+    for (String fname : validFormats)
+    {
+      FileFormatI tff = ffs.forName(fname);
+      String[] extensions = tff.getExtensions().split(",");
+      for (String ext : extensions)
+      {
+        alignmentExtensions.add(ext.toLowerCase(Locale.ROOT));
+      }
+    }
+
+    annotationsExtensions = new HashSet<>();
+    for (String ext : Cache
+            .getDefault("ARGPREPROCESSORANNOTATIONSEXTENSIONS",
+                    "annotation,annotations")
+            .split(","))
+    {
+      annotationsExtensions.add(ext);
+    }
+
+    featuresExtensions = new HashSet<>();
+    for (String ext : Cache.getDefault("ARGPREPROCESSORFEATURESEXTENSIONS",
+            "feature,features").split(","))
+    {
+      featuresExtensions.add(ext);
+    }
+
+    treeExtensions = new HashSet<>();
+    for (String ext : Cache.getDefault("ARGPREPROCESSORTREEEXTENSIONS",
+            "tree,tre,newick,nwk").split(","))
+    {
+      treeExtensions.add(ext);
+    }
+  }
+}
+
+class BaseInfo
+{
+  String filename;
+
+  Map<Arg, String> associatedFiles = null;
+
+  BaseInfo(String filename)
+  {
+    this.filename = filename;
+  }
+
+  void putAssociatedFile(Arg a, String file)
+  {
+    if (associatedFiles == null)
+    {
+      associatedFiles = new HashMap<>();
+    }
+    associatedFiles.put(a, file);
+  }
+}
index c4c083f..ffcb6a1 100644 (file)
@@ -86,8 +86,8 @@ public class ChannelProperties
     if (channelPropsURL == null)
     {
       // complete failure of channel_properties, set all properties to defaults
-      jalview.bin.Console.errPrintln("Failed to find '/"
-              + CHANNEL_PROPERTIES_FILENAME + "' file at '"
+      ErrorLog.errPrintln("Failed to find '/" + CHANNEL_PROPERTIES_FILENAME
+              + "' file at '"
               + (channelPropsURL == null ? "null"
                       : channelPropsURL.toString())
               + "'. Using class defaultProps.");
@@ -97,12 +97,12 @@ public class ChannelProperties
     {
       try
       {
-        InputStream channelPropsIS = channelPropsURL.openStream();
+        InputStream channelPropsIS = HttpUtils.openStream(channelPropsURL);
         tryChannelProps.load(channelPropsIS);
         channelPropsIS.close();
       } catch (IOException e)
       {
-        jalview.bin.Console.errPrintln(e.getMessage());
+        ErrorLog.errPrintln(e.getMessage());
         // return false;
       }
     }
@@ -157,10 +157,10 @@ public class ChannelProperties
         channelProps.load(is);
       } catch (FileNotFoundException e)
       {
-        jalview.bin.Console.errPrintln(e.getMessage());
+        ErrorLog.errPrintln(e.getMessage());
       } catch (IOException e)
       {
-        jalview.bin.Console.errPrintln(e.getMessage());
+        ErrorLog.errPrintln(e.getMessage());
       }
     }
   }
@@ -214,8 +214,7 @@ public class ChannelProperties
       }
       else
       {
-        jalview.bin.Console
-                .errPrintln("Failed to get channel property '" + key + "'");
+        ErrorLog.errPrintln("Failed to get channel property '" + key + "'");
       }
     }
     return null;
@@ -267,7 +266,7 @@ public class ChannelProperties
       img = imgIcon == null ? null : imgIcon.getImage();
       if (img == null)
       {
-        jalview.bin.Console.errPrintln(
+        ErrorLog.errPrintln(
                 "Failed to load channel image " + key + "=" + path);
         if (!useClassDefaultImage)
         {
@@ -294,7 +293,7 @@ public class ChannelProperties
       {
         return urlMap().getOrDefault(key, null);
       }
-      jalview.bin.Console.errPrintln(
+      ErrorLog.errPrintln(
               "Do not use getImageURL(key) before using getImage(key...)");
     }
     return null;
diff --git a/src/jalview/util/ErrorLog.java b/src/jalview/util/ErrorLog.java
new file mode 100644 (file)
index 0000000..e94b59e
--- /dev/null
@@ -0,0 +1,58 @@
+package jalview.util;
+
+public class ErrorLog
+{
+  private static boolean hasConsole = true;
+
+  public static void outPrintln(String message)
+  {
+    println(message, false);
+  }
+
+  public static void errPrintln(String message)
+  {
+    println(message, true);
+  }
+
+  public static void println(String message, boolean err)
+  {
+    if (hasConsole)
+    {
+      try
+      {
+        hasConsole = jalview.bin.Console.initLogger();
+        if (hasConsole)
+        {
+          if (err)
+          {
+            jalview.bin.Console.errPrintln(message);
+          }
+          else
+          {
+            jalview.bin.Console.outPrintln(message);
+          }
+        }
+      } catch (Exception e)
+      {
+        e.printStackTrace();
+      } catch (NoClassDefFoundError t)
+      {
+        hasConsole = false;
+        System.err.println(
+                "jalview.util.ErrorLog has no jalview.bin.Console. Using System.err and System.out.");
+      }
+    }
+    if (!hasConsole)
+    {
+      if (err)
+      {
+        System.err.println("jalview.util.ErrorLog: " + message);
+      }
+      else
+      {
+        System.out.println("jalview.util.ErrorLog: " + message);
+
+      }
+    }
+  }
+}
index e7d274c..f2883a7 100644 (file)
@@ -22,6 +22,8 @@ package jalview.util;
 
 import java.io.File;
 import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.nio.file.FileSystems;
 import java.nio.file.FileVisitOption;
 import java.nio.file.FileVisitResult;
@@ -291,4 +293,72 @@ public class FileUtils
 
     return parentDir.mkdirs();
   }
+
+  /**
+   * get a guessed file extension from a String only
+   * 
+   * @param String
+   *          filename
+   * @return String extension
+   */
+  public static String getExtension(String filename)
+  {
+    return getBaseOrExtension(filename, true);
+  }
+
+  /**
+   * getBase returns everything in a path/URI up to (and including) an extension
+   * dot. Note this is not the same as getBasename() since getBasename() only
+   * gives the filename base, not the path too. If no extension dot is found
+   * (i.e. a dot in character position 2 or more of the filename (after the last
+   * slash) then the whole path is considered the base.
+   * 
+   * @param filename
+   * @return String base
+   */
+  public static String getBase(String filename)
+  {
+    return getBaseOrExtension(filename, false);
+  }
+
+  public static String getBaseOrExtension(String filename0,
+          boolean extension)
+  {
+    if (filename0 == null)
+    {
+      return null;
+    }
+    String filename = filename0;
+    boolean isUrl = false;
+    if (HttpUtils.startsWithHttpOrHttps(filename))
+    {
+      try
+      {
+        URL url = new URL(filename);
+        filename = url.getPath();
+        isUrl = true;
+      } catch (MalformedURLException e)
+      {
+        // continue to treat as a filename
+      }
+    }
+    int dot = filename.lastIndexOf('.');
+    int slash = filename.lastIndexOf('/');
+    if (!File.separator.equals("/") && !isUrl)
+    {
+      slash = filename.lastIndexOf(File.separator);
+    }
+    // only the dot of the filename (not dots in path) and not if it's a .hidden
+    // file
+    boolean hasExtension = dot > slash + 1;
+    if (extension)
+    {
+      return hasExtension ? filename.substring(dot + 1) : null;
+    }
+    else
+    {
+      dot = filename0.lastIndexOf('.');
+      return hasExtension ? filename0.substring(0, dot + 1) : filename0;
+    }
+  }
 }
index 5438d4e..04a820d 100644 (file)
@@ -23,13 +23,12 @@ package jalview.util;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
 import java.net.ProtocolException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URL;
 
-import javax.ws.rs.HttpMethod;
-
-import jalview.bin.Cache;
-
 public class HttpUtils
 {
 
@@ -45,7 +44,7 @@ public class HttpUtils
     InputStream is = null;
     try
     {
-      is = new URL(url).openStream();
+      is = HttpUtils.openStream(new URL(url));
       if (is != null)
       {
         return true;
@@ -91,57 +90,195 @@ public class HttpUtils
     // jalview.bin.Console.outPrintln(System.currentTimeMillis() + " " + url);
 
     HttpURLConnection connection = (HttpURLConnection) url.openConnection();
-
-    connection.setRequestMethod(HttpMethod.HEAD);
-
+    connection.setRequestMethod("HEAD");
     connection.setDoInput(true);
-
     connection.setUseCaches(false);
     connection.setConnectTimeout(300);
     connection.setReadTimeout(readTimeout);
-    return connection.getResponseCode() == 200;
+
+    // HttpURLConnection doesn't follow redirects from http to https. It should!
+    HttpURLConnection conn = followConnection(connection);
+    return conn.getResponseCode() == 200;
+  }
+
+  /**
+   * wrapper to follow a URL connection ALLOWING redirects from http to https
+   * 
+   * @param HttpURLConnection
+   *          conn0
+   * @return HttpUrlConnection conn
+   */
+  public static HttpURLConnection followConnection(HttpURLConnection conn0)
+          throws IOException
+  {
+    URL url = conn0.getURL();
+    if (url == null)
+    {
+      return null;
+    }
+    HttpURLConnection conn = null;
+    int response = conn0.getResponseCode();
+    boolean followed = false;
+    if (response >= 300 && response < 400 && conn0.getFollowRedirects())
+    {
+      // we are only checking for a redirect from http to https
+      if ("http".equals(url.getProtocol()))
+      {
+        URL loc = new URL(conn0.getHeaderField("Location"));
+        if (loc != null && "https".equals(loc.getProtocol()))
+        {
+          conn = (HttpURLConnection) loc.openConnection();
+          conn.setRequestMethod(conn0.getRequestMethod());
+          conn.setDoInput(conn0.getDoInput());
+          conn.setUseCaches(conn0.getUseCaches());
+          conn.setConnectTimeout(conn0.getConnectTimeout());
+          conn.setReadTimeout(conn0.getReadTimeout());
+          conn.setInstanceFollowRedirects(
+                  conn0.getInstanceFollowRedirects());
+          followed = true;
+        }
+      }
+    }
+    return followed && conn != null ? conn : conn0;
+  }
+
+  /**
+   * wrapper to follow a URL connection ALLOWING redirects from http to https
+   * 
+   * @param URL
+   *          url
+   * @return HttpUrlConnection conn
+   */
+  public static HttpURLConnection openConnection(URL url) throws IOException
+  {
+    if (url == null)
+    {
+      return null;
+    }
+    HttpURLConnection conn = null;
+    String protocol = url.getProtocol();
+    if ("http".equals(protocol) || "https".equals(protocol))
+    {
+      HttpURLConnection conn0 = (HttpURLConnection) url.openConnection();
+      if (conn0 != null)
+      {
+        conn = HttpUtils.followConnection(conn0);
+      }
+      else
+      {
+        conn = conn0;
+      }
+    }
+    return conn;
   }
 
-  public static String getUserAgent()
+  /**
+   * wrapper to follow a URL connection ALLOWING redirects from http to https
+   * and return the followed InputStream
+   * 
+   * @param URL
+   *          url
+   * @return HttpUrlConnection conn
+   */
+  public static InputStream openStream(URL url) throws IOException
   {
-    return getUserAgent(null);
+    if (url == null)
+    {
+      return null;
+    }
+    InputStream is = null;
+    String protocol = url.getProtocol();
+    if ("http".equals(protocol) || "https".equals(protocol))
+    {
+      HttpURLConnection conn = HttpUtils
+              .followConnection((HttpURLConnection) url.openConnection());
+      if (conn != null)
+      {
+        is = conn.getInputStream();
+      }
+    }
+    else
+    {
+      is = url.openStream();
+    }
+    return is;
   }
 
-  public static String getUserAgent(String className)
+  /**
+   * check if a jalview:// scheme URL is given
+   * 
+   * @param String
+   *          uri
+   * @return boolean
+   */
+  public static boolean isJalviewSchemeUri(String jalviewUriString)
   {
-    StringBuilder sb = new StringBuilder();
-    sb.append("Jalview");
-    sb.append('/');
-    sb.append(Cache.getDefault("VERSION", "Unknown"));
-    sb.append(" (");
-    sb.append(System.getProperty("os.name"));
-    sb.append("; ");
-    sb.append(System.getProperty("os.arch"));
-    sb.append(' ');
-    sb.append(System.getProperty("os.name"));
-    sb.append(' ');
-    sb.append(System.getProperty("os.version"));
-    sb.append("; ");
-    sb.append("java/");
-    sb.append(System.getProperty("java.version"));
-    sb.append("; ");
-    sb.append("jalview/");
-    sb.append(ChannelProperties.getProperty("channel"));
-    if (className != null)
-    {
-      sb.append("; ");
-      sb.append(className);
+    URI jalviewUri;
+    try
+    {
+      jalviewUri = new URI(jalviewUriString);
+    } catch (URISyntaxException e)
+    {
+      return false;
     }
-    String installation = Cache.applicationProperties
-            .getProperty("INSTALLATION");
-    if (installation != null)
+    String scheme = jalviewUri.getScheme();
+    if (scheme == null || !scheme.startsWith("jalview"))
     {
-      sb.append("; ");
-      sb.append(installation);
+      return false;
     }
-    sb.append(')');
-    sb.append(" help@jalview.org");
-    return sb.toString();
+    return scheme.length() == 7 // jalview
+            || scheme.length() == 8 // jalviewX
+            || scheme.substring(7).equals("http") // jalviewhttp
+            || scheme.substring(7).equals("https"); // jalviewhttps
   }
 
+  /**
+   * convert a jalview scheme URI to its equivalent URL or path
+   * 
+   * @param String
+   *          uri
+   * @return String
+   */
+  public static String equivalentJalviewUrl(String jalviewUriString)
+  {
+    if (!isJalviewSchemeUri(jalviewUriString))
+    {
+      // not a jalviewUriString, hand it back
+      return jalviewUriString;
+    }
+    URI jalviewUri;
+    try
+    {
+      jalviewUri = new URI(jalviewUriString);
+    } catch (URISyntaxException e)
+    {
+      return null;
+    }
+    String scheme = jalviewUri.getScheme();
+    String host = jalviewUri.getHost();
+    if (host != null && host.length() > 0
+            || scheme.substring(7).startsWith("http"))
+    {
+      URI newUri;
+      try
+      {
+        newUri = new URI(scheme.equals("jalviewhttp") ? "http" : "https",
+                jalviewUri.getUserInfo(), host, jalviewUri.getPort(),
+                jalviewUri.getPath(), jalviewUri.getQuery(),
+                jalviewUri.getFragment());
+        // return a URL
+        return newUri.toURL().toString();
+      } catch (URISyntaxException | MalformedURLException e)
+      {
+        ErrorLog.errPrintln("Trying to convert '" + jalviewUriString
+                + "' to URL failed");
+      }
+    }
+    else
+    {
+      // return a file path (not a file URI)
+      return jalviewUri.getPath();
+    }
+    return null;
+  }
 }
index 4b443d3..5894fec 100644 (file)
@@ -29,11 +29,8 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Properties;
 
-import jalview.bin.Console;
-
 public class LaunchUtils
 {
-
   // setting these is LaunchUtils so don't need to import Platform
   public final static boolean isMac = System.getProperty("os.name")
           .indexOf("Mac") > -1;
@@ -77,7 +74,7 @@ public class LaunchUtils
         return null;
       } catch (IOException e)
       {
-        jalview.bin.Console.errPrintln(e.getMessage());
+        ErrorLog.errPrintln(e.getMessage());
         return null;
       }
     }
@@ -107,7 +104,7 @@ public class LaunchUtils
     try
     {
       URL localFileURL = new URL(buildDetails);
-      InputStream in = localFileURL.openStream();
+      InputStream in = HttpUtils.openStream(localFileURL);
       Properties buildProperties = new Properties();
       buildProperties.load(in);
       in.close();
@@ -115,23 +112,21 @@ public class LaunchUtils
               null);
       if (JCV == null)
       {
-        Console.errPrintln(
-                "Could not obtain JAVA_COMPILE_VERSION for comparison");
+        ErrorLog.errPrintln("Could not obtain JAVA_COMPILE_VERSION for comparison");
         return -2;
       }
       JAVA_COMPILE_VERSION = Integer.parseInt(JCV);
     } catch (MalformedURLException e)
     {
-      jalview.bin.Console.errPrintln("Could not find " + buildDetails);
+      ErrorLog.errPrintln("Could not find " + buildDetails);
       return -3;
     } catch (IOException e)
     {
-      jalview.bin.Console.errPrintln("Could not load " + buildDetails);
+      ErrorLog.errPrintln("Could not load " + buildDetails);
       return -4;
     } catch (NumberFormatException e)
     {
-      jalview.bin.Console
-              .errPrintln("Could not parse JAVA_COMPILE_VERSION");
+      ErrorLog.errPrintln("Could not parse JAVA_COMPILE_VERSION");
       return -5;
     }
 
@@ -155,7 +150,7 @@ public class LaunchUtils
       String JV = System.getProperty("java.version");
       if (JV == null)
       {
-        Console.errPrintln("Could not obtain java.version for comparison");
+        ErrorLog.errPrintln("Could not obtain java.version for comparison");
         return -2;
       }
       if (JV.startsWith("1."))
@@ -166,7 +161,7 @@ public class LaunchUtils
               : Integer.parseInt(JV.substring(0, JV.indexOf(".")));
     } catch (NumberFormatException e)
     {
-      jalview.bin.Console.errPrintln("Could not parse java.version");
+      ErrorLog.errPrintln("Could not parse java.version");
       return -3;
     }
     return JAVA_VERSION;
@@ -187,7 +182,7 @@ public class LaunchUtils
 
     if (java_compile_version <= 0 || java_version <= 0)
     {
-      Console.errPrintln("Could not make Java version check");
+      ErrorLog.errPrintln("Could not make Java version check");
       return true;
     }
     // Warn if these java.version and JAVA_COMPILE_VERSION conditions exist
index 89bc36d..42c52a7 100644 (file)
@@ -202,18 +202,18 @@ public class StringUtils
       jv.clear();
       if (DEBUG)
       {
-        jalview.bin.Console.errPrintln("Array from '" + delimiter
+        ErrorLog.errPrintln("Array from '" + delimiter
                 + "' separated List:\n" + v.length);
         for (int i = 0; i < v.length; i++)
         {
-          jalview.bin.Console.errPrintln("item " + i + " '" + v[i] + "'");
+          ErrorLog.errPrintln("item " + i + " '" + v[i] + "'");
         }
       }
       return v;
     }
     if (DEBUG)
     {
-      jalview.bin.Console.errPrintln(
+      ErrorLog.errPrintln(
               "Empty Array from '" + delimiter + "' separated List");
     }
     return null;
@@ -249,13 +249,13 @@ public class StringUtils
       {
         System.err
                 .println("Returning '" + separator + "' separated List:\n");
-        jalview.bin.Console.errPrintln(v);
+        ErrorLog.errPrintln(v.toString());
       }
       return v.toString();
     }
     if (DEBUG)
     {
-      jalview.bin.Console.errPrintln(
+      ErrorLog.errPrintln(
               "Returning empty '" + separator + "' separated List\n");
     }
     return "" + separator;
diff --git a/src/jalview/util/UserAgent.java b/src/jalview/util/UserAgent.java
new file mode 100644 (file)
index 0000000..b488b00
--- /dev/null
@@ -0,0 +1,50 @@
+package jalview.util;
+
+import jalview.bin.Cache;
+
+public class UserAgent
+{
+
+  public static String getUserAgent(String className)
+  {
+    StringBuilder sb = new StringBuilder();
+    sb.append("Jalview");
+    sb.append('/');
+    sb.append(Cache.getDefault("VERSION", "Unknown"));
+    sb.append(" (");
+    sb.append(System.getProperty("os.name"));
+    sb.append("; ");
+    sb.append(System.getProperty("os.arch"));
+    sb.append(' ');
+    sb.append(System.getProperty("os.name"));
+    sb.append(' ');
+    sb.append(System.getProperty("os.version"));
+    sb.append("; ");
+    sb.append("java/");
+    sb.append(System.getProperty("java.version"));
+    sb.append("; ");
+    sb.append("jalview/");
+    sb.append(ChannelProperties.getProperty("channel"));
+    if (className != null)
+    {
+      sb.append("; ");
+      sb.append(className);
+    }
+    String installation = Cache.applicationProperties
+            .getProperty("INSTALLATION");
+    if (installation != null)
+    {
+      sb.append("; ");
+      sb.append(installation);
+    }
+    sb.append(')');
+    sb.append(" help@jalview.org");
+    return sb.toString();
+  }
+
+  public static String getUserAgent()
+  {
+    return getUserAgent(null);
+  }
+
+}
index 7326c6e..8a27ad9 100644 (file)
  */
 package jalview.ws.dbsources;
 
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
+import java.util.Vector;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import com.stevesoft.pat.Regex;
 
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
@@ -32,9 +48,9 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.schemes.ResidueProperties;
+import jalview.util.HttpUtils;
 import jalview.util.StringUtils;
 import jalview.ws.seqfetcher.DbSourceProxyImpl;
-import jalview.xml.binding.embl.ROOT;
 import jalview.xml.binding.uniprot.DbReferenceType;
 import jalview.xml.binding.uniprot.Entry;
 import jalview.xml.binding.uniprot.FeatureType;
@@ -42,23 +58,6 @@ import jalview.xml.binding.uniprot.LocationType;
 import jalview.xml.binding.uniprot.PositionType;
 import jalview.xml.binding.uniprot.PropertyType;
 
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Vector;
-
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.JAXBException;
-import javax.xml.stream.FactoryConfigurationError;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
-
-import com.stevesoft.pat.Regex;
-
 /**
  * This class queries the Uniprot database for sequence data, unmarshals the
  * returned XML, and converts it to Jalview Sequence records (including attached
@@ -152,7 +151,7 @@ public class TDBeacons extends DbSourceProxyImpl
       // String downloadstring = getDomain() + queries + ".json";
 
       URL url = new URL(downloadstring);
-      URLConnection urlconn = url.openConnection();
+      URLConnection urlconn = HttpUtils.openConnection(url);
       InputStream istr = urlconn.getInputStream();
       List<Entry> entries = getUniprotEntries(istr);
       if (entries != null)
index 299224d..b493611 100644 (file)
@@ -49,6 +49,7 @@ import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.schemes.ResidueProperties;
+import jalview.util.HttpUtils;
 import jalview.util.StringUtils;
 import jalview.ws.seqfetcher.DbSourceProxyImpl;
 import jalview.xml.binding.uniprot.DbReferenceType;
@@ -144,10 +145,11 @@ public class Uniprot extends DbSourceProxyImpl
               "(UNIPROT\\|?|UNIPROT_|UNIREF\\d+_|UNIREF\\d+\\|?)", "");
       AlignmentI al = null;
 
-      String downloadstring = getDomain() + "/uniprotkb/" + queries + ".xml";
+      String downloadstring = getDomain() + "/uniprotkb/" + queries
+              + ".xml";
 
       URL url = new URL(downloadstring);
-      HttpURLConnection urlconn = (HttpURLConnection) url.openConnection();
+      HttpURLConnection urlconn = HttpUtils.openConnection(url);
       // anything other than 200 means we don't have data
       // TODO: JAL-3882 reuse the EnsemblRestClient's fair
       // use/backoff logic to retry when the server tells us to go away
index 8aca9a2..87526a1 100644 (file)
  */
 package jalview.ws.ebi;
 
-import java.util.Locale;
-
-import jalview.datamodel.DBRefSource;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
@@ -35,8 +29,14 @@ import java.net.HttpURLConnection;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 import java.util.StringTokenizer;
 
+import jalview.datamodel.DBRefSource;
+import jalview.util.HttpUtils;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+
 /**
  * DOCUMENT ME!
  * 
@@ -210,7 +210,7 @@ public class EBIFetchClient
     try
     {
       URL rcall = new URL(url);
-      HttpURLConnection conn = (HttpURLConnection) rcall.openConnection();
+      HttpURLConnection conn = HttpUtils.openConnection(rcall);
       int responseCode = conn.getResponseCode();
       if (responseCode == 200)
       {
index 4165eae..f4acafa 100644 (file)
  */
 package jalview.ws.jws1;
 
-import jalview.datamodel.AlignmentI;
-import jalview.io.FileFormat;
-import jalview.io.FileParse;
-import jalview.io.FormatAdapter;
-import jalview.io.InputStreamParser;
-import jalview.util.MessageManager;
-
 import java.io.BufferedReader;
 import java.io.FileReader;
 import java.io.IOException;
@@ -37,6 +30,14 @@ import java.net.URL;
 import java.net.URLEncoder;
 import java.util.Iterator;
 
+import jalview.datamodel.AlignmentI;
+import jalview.io.FileFormat;
+import jalview.io.FileParse;
+import jalview.io.FormatAdapter;
+import jalview.io.InputStreamParser;
+import jalview.util.HttpUtils;
+import jalview.util.MessageManager;
+
 public class Annotate3D
 {
   // protected BufferedReader in;
@@ -181,7 +182,7 @@ public class Annotate3D
               "http://paradise-ibmc.u-strasbg.fr/webservices/annotate3d?data="
                       + content);
       BufferedReader is = new BufferedReader(
-              new InputStreamReader(url.openStream()));
+              new InputStreamReader(HttpUtils.openStream(url)));
       String str4;
       while ((str4 = is.readLine()) != null)
       {
index 84aa1a6..559afac 100644 (file)
  */
 package jalview.ws.jws2;
 
-import jalview.bin.Console;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
-import jalview.ws.jws2.jabaws2.Jws2InstanceFactory;
-
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -37,6 +33,10 @@ import compbio.data.msa.Category;
 import compbio.data.msa.JABAService;
 import compbio.ws.client.Jws2Client;
 import compbio.ws.client.Services;
+import jalview.bin.Console;
+import jalview.util.HttpUtils;
+import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.jws2.jabaws2.Jws2InstanceFactory;
 
 /**
  * @author JimP
@@ -244,7 +244,7 @@ public class JabaWsServerQuery implements Runnable
       try
       {
         URL url = new URL(server);
-        url.openStream().close();
+        HttpUtils.openStream(url).close();
         result = true;
       } catch (MalformedURLException e)
       {
index 58e0b29..cb61ca1 100644 (file)
@@ -20,8 +20,6 @@
  */
 package jalview.ws.sifts;
 
-import java.util.Locale;
-
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -41,6 +39,7 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
@@ -68,6 +67,7 @@ import jalview.structure.StructureMapping;
 import jalview.util.Comparison;
 import jalview.util.DBRefUtils;
 import jalview.util.Format;
+import jalview.util.HttpUtils;
 import jalview.util.Platform;
 import jalview.xml.binding.sifts.Entry;
 import jalview.xml.binding.sifts.Entry.Entity;
@@ -335,7 +335,7 @@ public class SiftsClient implements SiftsClientI
     // siftsFileFTPURL);
     // long now = System.currentTimeMillis();
     URL url = new URL(siftsFileFTPURL);
-    URLConnection conn = url.openConnection();
+    URLConnection conn = HttpUtils.openConnection(url);
     InputStream inputStream = conn.getInputStream();
     FileOutputStream outputStream = new FileOutputStream(downloadTo);
     byte[] buffer = new byte[BUFFER_SIZE];
index 91d88c2..362350d 100644 (file)
@@ -21,8 +21,6 @@
 
 package jalview.ws.utils;
 
-import jalview.util.Platform;
-
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -34,6 +32,9 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
 
+import jalview.util.HttpUtils;
+import jalview.util.Platform;
+
 public class UrlDownloadClient
 {
   /**
@@ -57,7 +58,7 @@ public class UrlDownloadClient
       temp = Files.createTempFile(".jalview_", ".tmp");
 
       URL url = new URL(urlstring);
-      rbc = Channels.newChannel(url.openStream());
+      rbc = Channels.newChannel(HttpUtils.openStream(url));
       fos = new FileOutputStream(temp.toString());
       fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
 
index a221bd1..caa4e22 100644 (file)
@@ -29,6 +29,7 @@ import java.awt.Container;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.FontMetrics;
+import java.awt.event.MouseEvent;
 import java.lang.reflect.InvocationTargetException;
 
 import javax.swing.SwingUtilities;
@@ -43,6 +44,7 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.SequenceI;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
+import jalview.util.Platform;
 import jalview.viewmodel.ViewportRanges;
 
 public class AlignmentPanelTest
@@ -273,12 +275,16 @@ public class AlignmentPanelTest
   @Test(groups = { "Functional", "Not-bamboo" })
   public void testGetVisibleWidth()
   {
+    double scaling = jalview.gui.JvSwingUtilsTest.getScaling(af.alignPanel);
     /*
      * width for onscreen rendering is IDPanel width
      */
     int w = af.alignPanel.getVisibleIdWidth(true);
     assertEquals(w, af.alignPanel.getIdPanel().getWidth());
-    assertEquals(w, 115);
+
+    // different scaling (1.0, 2.0) gives different results
+    int expectedWidth = scaling == 1.0 ? 112 : Platform.isMac() ? 115 : 107;
+    assertEquals(w, expectedWidth);
 
     /*
      * width for offscreen rendering is the same
@@ -298,33 +304,58 @@ public class AlignmentPanelTest
      * preference for auto id width overrides fixed width
      */
     Cache.setProperty("FIGURE_AUTOIDWIDTH", Boolean.TRUE.toString());
-    assertEquals(115, af.alignPanel.getVisibleIdWidth(false));
+    w = af.alignPanel.getVisibleIdWidth(false);
+    // allow some leeway for different OS renderings
+    assertTrue(w > 105 && w < 120);
+    // different scaling (1.0, 2.0) gives different results
+    assertEquals(w, expectedWidth);
   }
 
   @Test(groups = { "Functional", "Not-bamboo" })
   public void testresetIdWidth()
   {
+    double scaling = jalview.gui.JvSwingUtilsTest.getScaling(af.alignPanel);
     /*
      * width for onscreen rendering is IDPanel width
      */
     int w = af.alignPanel.getVisibleIdWidth(true);
-    assertEquals(w, af.alignPanel.getIdPanel().getWidth());
-    assertEquals(w, 115);
+    int actual = af.alignPanel.getIdPanel().getWidth();
+    assertEquals(w, actual);
+    // allow some leeway for different OS renderings
+    assertTrue(w > 105 && w < 120);
+    // different scaling (1.0, 2.0) gives different results
+    int expectedWidth = scaling == 1.0 ? 112 : Platform.isMac() ? 115 : 107;
+    assertEquals(w, expectedWidth);
 
     // manually adjust
     af.viewport.setIdWidth(200);
+    // fake mouse drag sets manuallyAdjusted to true (0,0 not moving mouse)
+    MouseEvent drag = new MouseEvent(af.alignPanel,
+            MouseEvent.MOUSE_DRAGGED, System.currentTimeMillis(), 0, 0, 0,
+            MouseEvent.BUTTON1, false);
+    af.alignPanel.idwidthAdjuster.mouseDragged(drag);
+    af.alignPanel.paintComponent(af.alignPanel.getGraphics());
     w = af.alignPanel.calculateIdWidth().width;
     assertTrue(
             af.alignPanel.getIdPanel().getIdCanvas().isManuallyAdjusted());
-    assertEquals(w, af.alignPanel.getIdPanel().getWidth());
+    actual = af.alignPanel.getIdPanel().getWidth();
+    assertEquals(w, actual);
 
     af.viewport.setIdWidth(-1);
+    af.alignPanel.calculateIdWidth();
     af.alignPanel.getIdPanel().getIdCanvas().setManuallyAdjusted(false);
     w = af.alignPanel.calculateIdWidth().width;
+    af.alignPanel.paintComponent(af.alignPanel.getGraphics());
 
-    assertEquals(w, af.alignPanel.getIdPanel().getWidth());
+    actual = af.alignPanel.getIdPanel().getWidth();
+    assertEquals(w, actual);
 
-    assertNotEquals(w, 115);
+    // setting a negative IdWidth and then running calculateIdWidth resets width
+    // to optimal id width
+    // allow some leeway for different OS renderings
+    assertTrue(w > 105 && w < 120);
+    // different scaling (1.0, 2.0) gives different results
+    assertEquals(w, expectedWidth);
   }
 
   @Test(groups = "Functional")
index ad97e8b..21a0217 100644 (file)
@@ -40,9 +40,12 @@ import jalview.gui.StructureViewer.ViewerType;
 import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
 import jalview.structure.StructureImportSettings.TFType;
+import jalview.util.Platform;
 
 public class AnnotationLabelsTest2
 {
+  private static double scaling;
+
   @BeforeClass(alwaysRun = true)
   public static void setUpBeforeClass() throws Exception
   {
@@ -55,6 +58,8 @@ public class AnnotationLabelsTest2
      */
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
     Jalview.main(new String[] { "--nonews", "--nosplash", });
+
+    scaling = JvSwingUtilsTest.getScaling(Desktop.instance);
   }
 
   @AfterMethod(alwaysRun = true)
@@ -95,6 +100,7 @@ public class AnnotationLabelsTest2
   {
     AlignFrame af = new FileLoader()
             .LoadFileWaitTillLoaded(alignmentFilename, DataSourceType.FILE);
+
     try
     {
       Thread.sleep(200); // to allow alignment annotations to open
@@ -110,8 +116,8 @@ public class AnnotationLabelsTest2
     idWidth = av.getIdWidth();
     assertTrue(idWidth > idWidth1min,
             "idWidth (" + idWidth + ") is not greater than " + idWidth1min);
-    assertTrue(idWidth < idWidth1max,
-            "idWidth (" + idWidth + ") is not narrower than" + idWidth1max);
+    assertTrue(idWidth < idWidth1max, "idWidth (" + idWidth
+            + ") is not narrower than " + idWidth1max);
 
     // set wrap
     if (wrap)
@@ -147,10 +153,10 @@ public class AnnotationLabelsTest2
 
     // idWidth = ap.getIdPanel().getWidth();
     idWidth = av.getIdWidth();
-    assertTrue(idWidth > idWidth2min,
+    assertTrue(idWidth >= idWidth2min,
             "idWidth (" + idWidth + ") is not greater than " + idWidth2min);
-    assertTrue(idWidth < idWidth2max,
-            "idWidth (" + idWidth + ") is not narrower than" + idWidth2max);
+    assertTrue(idWidth <= idWidth2max, "idWidth (" + idWidth
+            + ") is not narrower than " + idWidth2max);
   }
 
   @Test(
@@ -176,7 +182,6 @@ public class AnnotationLabelsTest2
     AlignViewport av = af.getCurrentView();
 
     int idWidth = 0;
-
     idWidth = av.getIdWidth();
     assertTrue(idWidth > idWidth1min,
             "idWidth (" + idWidth + ") is not greater than " + idWidth1min);
@@ -231,6 +236,13 @@ public class AnnotationLabelsTest2
       int idWidth2min,
       int idWidth2max,
      */
+    int idWidth2min = scaling == 1.0 ? 114 : 108;
+    int idWidth2max = scaling == 1.0 ? 117 : 114; // was 130
+    if (Platform.isMac())
+    {
+      idWidth2max = 122;
+    }
+
     return new Object[][] {
         //
         /*
@@ -239,12 +251,12 @@ public class AnnotationLabelsTest2
             100,
             "./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3.pdb",
             "./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3_scores.json",
-            true, TFType.PLDDT, null, 115, 130 },
+            true, TFType.PLDDT, null, idWidth2min, idWidth2max },
         { "./test/files/annotation_label_width/sample.a2m", true, 50, 70,
             100,
             "./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3.pdb",
             "./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3_scores.json",
-            true, TFType.PLDDT, null, 115, 130 },
+            true, TFType.PLDDT, null, idWidth2min, idWidth2max },
         /*
          */
     };
index e6f4041..8a9a428 100644 (file)
@@ -23,6 +23,10 @@ package jalview.gui;
 import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertFalse;
 
+import java.awt.Component;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+
 import javax.swing.JScrollBar;
 
 import org.testng.annotations.BeforeClass;
@@ -119,4 +123,17 @@ public class JvSwingUtilsTest
             JvSwingUtils.wrapTooltip(true, tip));
     assertEquals(expected, JvSwingUtils.wrapTooltip(false, tip));
   }
+
+  public static double getScaling(Component c)
+  {
+    Graphics2D g = (Graphics2D) c.getGraphics();
+    if (g == null)
+    {
+      return 0.0;
+    }
+    AffineTransform t = g.getTransform();
+    double scaling = t.getScaleX(); // Assuming square pixels :P
+    return scaling;
+  }
+
 }
index aa50301..46c2201 100644 (file)
  */
 package jalview.gui;
 
-import java.awt.Font;
-import java.awt.FontMetrics;
-
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
+import java.awt.Font;
+import java.awt.FontMetrics;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
 import jalview.io.DataSourceType;
-import jalview.io.DataSourceType;
 import jalview.io.FileLoader;
-
 import junit.extensions.PA;
 
 public class SeqCanvasTest
@@ -76,7 +75,8 @@ public class SeqCanvasTest
     av.setScaleRightWrapped(true);
     FontMetrics fm = testee.getFontMetrics(av.getFont());
     int labelWidth = fm.stringWidth("000") + charWidth;
-    assertEquals(labelWidth, 39); // 3 x 9 + charWidth
+    // some leeway for different OS rendering of text
+    assertTrue(labelWidth >= 36 && labelWidth <= 39);
 
     /*
      * width 400 pixels leaves (400 - 2*labelWidth) for residue columns
@@ -152,7 +152,9 @@ public class SeqCanvasTest
     av.setScaleLeftWrapped(false);
     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
             canvasHeight);
-    assertEquals(wrappedWidth, 23);
+    // some leeway for different OS rendering of text
+    assertTrue(wrappedWidth >= 22 && wrappedWidth <= 23);
+    int difference = wrappedWidth - 23;
 
     /*
      * add 10 pixels to width to fit in another whole residue column
@@ -164,7 +166,7 @@ public class SeqCanvasTest
     canvasWidth += 1;
     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
             canvasHeight);
-    assertEquals(wrappedWidth, 24);
+    assertEquals(wrappedWidth, 24 + difference);
 
     /*
      * turn off East scale to gain 39 more pixels (3 columns remainder 3)
@@ -172,7 +174,7 @@ public class SeqCanvasTest
     av.setScaleRightWrapped(false);
     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
             canvasHeight);
-    assertEquals(wrappedWidth, 27);
+    assertEquals(wrappedWidth, 27 + difference);
 
     /*
      * add 9 pixels to width to gain a residue column
@@ -184,7 +186,7 @@ public class SeqCanvasTest
     canvasWidth += 1;
     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
             canvasHeight);
-    assertEquals(wrappedWidth, 28); // 9px is enough
+    assertEquals(wrappedWidth, 28 + difference); // 9px is enough
 
     /*
      * now West but not East scale - lose 39 pixels or 4 columns
@@ -204,7 +206,7 @@ public class SeqCanvasTest
     canvasWidth += 1;
     wrappedWidth = testee.calculateWrappedGeometry(canvasWidth,
             canvasHeight);
-    assertEquals(wrappedWidth, 25); // 3px is enough
+    assertEquals(wrappedWidth, 25 + difference); // 3px is enough
 
     /*
      * turn off scales left and right, make width exactly 157 columns
@@ -246,7 +248,8 @@ public class SeqCanvasTest
     av.setScaleRightWrapped(true);
     FontMetrics fm = testee.getFontMetrics(av.getFont());
     int labelWidth = fm.stringWidth("000") + charWidth;
-    assertEquals(labelWidth, 39); // 3 x 9 + charWidth
+    // some leeway for different OS rendering of text
+    assertTrue(labelWidth >= 36 && labelWidth <= 39);
     int annotationHeight = testee.getAnnotationHeight();
 
     /*
index 649c78a..4f07314 100644 (file)
@@ -950,9 +950,12 @@ public class SeqPanelTest
     assertEquals(charHeight, 17);
     assertEquals(charWidth, 12);
 
+    double scaling = JvSwingUtilsTest.getScaling(alignFrame.alignPanel);
+
     FontMetrics fm = testee.getFontMetrics(av.getFont());
     int labelWidth = fm.stringWidth("00000") + charWidth;
-    assertEquals(labelWidth, 57); // 5 x 9 + charWidth
+    // some leeway for different OS rendering of text
+    assertTrue(labelWidth >= 52 && labelWidth <= 57);
     assertEquals(testee.seqCanvas.getLabelWidthWest(), labelWidth);
 
     int x = 0;
index 68c099e..1d0785e 100644 (file)
@@ -24,6 +24,8 @@ import static org.testng.AssertJUnit.assertFalse;
 import static org.testng.AssertJUnit.assertSame;
 import static org.testng.AssertJUnit.assertTrue;
 
+import java.io.FileNotFoundException;
+
 import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
@@ -43,7 +45,7 @@ public class IdentifyFileTest
 
   @Test(groups = { "Functional" }, dataProvider = "identifyFiles")
   public void testIdentify(String data, FileFormatI expectedFileType)
-          throws FileFormatException
+          throws FileFormatException, FileNotFoundException
   {
     DataSourceType protocol = DataSourceType.FILE;
     IdentifyFile ider = new IdentifyFile();
@@ -58,7 +60,8 @@ public class IdentifyFileTest
    * @throws FileFormatException
    */
   @Test(groups = "Functional")
-  public void testIdentify_featureFile() throws FileFormatException
+  public void testIdentify_featureFile()
+          throws FileFormatException, FileNotFoundException
   {
     IdentifyFile ider = new IdentifyFile();
 
@@ -135,4 +138,60 @@ public class IdentifyFileTest
     // non-numeric start column:
     assertFalse(id.looksLikeFeatureData("Helix\tSeq1\t-1\t2456\t.\tss"));
   }
+
+  @Test(groups = "Network", dataProvider = "urlTargetsAndExceptions")
+  public void testExceptions(String url,
+          Class<? extends Exception> expectedExceptionClass,
+          FileFormatI expectedFormat)
+  {
+    Class<? extends Exception> actualExceptionClass = null;
+    FileFormatI actualFormat = null;
+    try
+    {
+      actualFormat = new IdentifyFile().identify(url, DataSourceType.URL);
+    } catch (FileFormatException | FileNotFoundException e)
+    {
+      Assert.assertNull(expectedFormat,
+              "Exception occurred when expecting an identifiable format.");
+      Assert.assertNotNull(expectedExceptionClass,
+              "An unexpected exception occurred: '" + e.getMessage() + "'");
+      Assert.assertEquals(e.getClass(), expectedExceptionClass,
+              "Got the wrong kind of exception.");
+      actualExceptionClass = e.getClass();
+    }
+
+    if (expectedExceptionClass != null)
+    {
+      Assert.assertEquals(actualExceptionClass, expectedExceptionClass,
+              "Expected an exception but got the wrong one.");
+    }
+
+  }
+
+  @DataProvider(name = "urlTargetsAndExceptions")
+  public Object[][] urlTargetsAndExceptions()
+  {
+    /*
+    String targetUrl,
+    String finalUrl,
+    String foundInFirstLine,
+    */
+    return new Object[][] {
+        //
+        /*
+        { "http://jalview.org/examples/uniref50.fa", null,
+            FileFormat.Fasta },
+        { "https://www.jalview.org/examples/NOFILE.fa",
+            FileNotFoundException.class, null },
+        { "https://NOSERVER.jalview.org/", FileNotFoundException.class,
+            null },
+         */
+        { "https://www.jalview.org/schools/Jalview_Schools_Workbook_200.jpg",
+            FileFormatException.class, null },
+        /*
+         */
+        //
+    };
+  }
+
 }
index dcf8feb..8b2fa74 100644 (file)
@@ -32,7 +32,6 @@ import java.awt.Color;
 import java.awt.Rectangle;
 import java.io.File;
 import java.io.IOException;
-import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.HashMap;
@@ -102,7 +101,6 @@ import jalview.schemes.StrandColourScheme;
 import jalview.schemes.TCoffeeColourScheme;
 import jalview.structure.StructureImportSettings;
 import jalview.util.MapList;
-import jalview.util.Platform;
 import jalview.util.matcher.Condition;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
@@ -252,8 +250,9 @@ public class Jalview2xmlTests extends Jalview2xmlBase
 
     boolean diffseqcols = false, diffgseqcols = false;
     SequenceI[] sqs = af.getViewport().getAlignment().getSequencesArray();
-    for (int p = 0, pSize = af.getViewport().getAlignment()
-            .getWidth(); p < pSize && (!diffseqcols || !diffgseqcols); p++)
+    for (int p = 0,
+            pSize = af.getViewport().getAlignment().getWidth(); p < pSize
+                    && (!diffseqcols || !diffgseqcols); p++)
     {
       if (_rcs.findColour(sqs[0].getCharAt(p), p, sqs[0], null, 0f) != _rcs
               .findColour(sqs[5].getCharAt(p), p, sqs[5], null, 0f))
@@ -272,8 +271,9 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     assertTrue(__rcs.isSeqAssociated(),
             "Group Annotation colourscheme wasn't sequence associated");
 
-    for (int p = 0, pSize = af.getViewport().getAlignment()
-            .getWidth(); p < pSize && (!diffseqcols || !diffgseqcols); p++)
+    for (int p = 0,
+            pSize = af.getViewport().getAlignment().getWidth(); p < pSize
+                    && (!diffseqcols || !diffgseqcols); p++)
     {
       if (_rgcs.findColour(sqs[1].getCharAt(p), p, sqs[1], null,
               0f) != _rgcs.findColour(sqs[2].getCharAt(p), p, sqs[2], null,
@@ -1477,7 +1477,17 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     assertEquals(ov1.getCanvas().getResidueColour(), Color.white);
     assertEquals(ov1.getCanvas().getHiddenColour(), Color.yellow);
     assertEquals(ov1.getTitle(), "Overview examples/uniref50.fa Original");
-    assertEquals(ov1.getFrameBounds(), new Rectangle(20, 30, 200, 400));
+
+    double scaling = jalview.gui.JvSwingUtilsTest.getScaling(ov1);
+    // int width = scaling == 1.0 ? 225 : 200;
+    // int width = scaling == 1.0 ? 225 : 200;
+    Rectangle ov1Rectangle = ov1.getFrameBounds();
+    assertEquals(ov1Rectangle,
+            new Rectangle(20, 30, ov1Rectangle.width, 400));
+    int width = ov1Rectangle.width;
+    assertTrue(width >= 200 && width <= 225,
+            "Rectangle width was not in the range expected (200<=width<=225; width="
+                    + width + ")");
     assertTrue(ov1.isShowHiddenRegions());
   }
 
@@ -1760,9 +1770,15 @@ public class Jalview2xmlTests extends Jalview2xmlBase
     assertNotNull(af, "Didn't read in the example file correctly.");
     // FIXME JAL-4281 test made platform dependent to pass, but probably
     // shouldn't be platform dependent
-    assertEquals(af.alignPanel.getAlignViewport().getIdWidth(),
-            Platform.isAMacAndNotJS() ? 144 : 138,
-            "Legacy project import should have fixed ID width");
+    int idWidth = af.alignPanel.getAlignViewport().getIdWidth();
+    double scaling = jalview.gui.JvSwingUtilsTest.getScaling(af.alignPanel);
+    // int expectedWidth = Platform.isMac() ? 144 : Platform.isLinux() ? scaling
+    // == 1.0 ? 131 : 128 : 138;
+    int minExpectedWidth = 128;
+    int maxExpectedWidth = 144;
+    assertTrue(minExpectedWidth <= idWidth && maxExpectedWidth >= idWidth,
+            "Legacy project import should have fixed ID width. Not within the expected range ("
+                    + minExpectedWidth + "-" + maxExpectedWidth + ")");
     assertTrue(
             af.alignPanel.getIdPanel().getIdCanvas().isManuallyAdjusted());
 
index 666b33b..3cc9ca6 100644 (file)
@@ -157,4 +157,54 @@ public class FileUtilsTest
     };
   }
 
+  @Test(
+    groups = "Functional",
+    dataProvider = "stringFilenamesBaseAndExtensionsData")
+  public void stringGetBaseAndExtensionTest(String filename,
+          String extension, String base)
+  {
+    String thisBase = FileUtils.getBase(filename);
+    Assert.assertEquals(thisBase, base,
+            "base part of path and filename not as expected");
+    String thisExtension = FileUtils.getExtension(filename);
+    Assert.assertEquals(thisExtension, extension,
+            "extension part of filename not as expected");
+  }
+
+  @DataProvider(name = "stringFilenamesBaseAndExtensionsData")
+  public Object[][] stringFilenamesBaseAndExtensionsData()
+  {
+    return new Object[][] {
+        /*
+         * String full URL or path
+         * String base the above but without the extension if there is one
+         * String extension the filename extension if there is one
+         */
+        /*
+        */
+        { "/examples/uniref50.fa", "fa", "/examples/uniref50." },
+        { "/examples/uniref50", null, "/examples/uniref50" },
+        { "/examples/.uniref50", null, "/examples/.uniref50" },
+        { "/exampl.es/uniref50", null, "/exampl.es/uniref50" },
+        { "/examples/uniref50.", "", "/examples/uniref50." },
+        { "examples/uniref50.fa", "fa", "examples/uniref50." },
+        { "examples/uniref50", null, "examples/uniref50" },
+        { "examples/.uniref50", null, "examples/.uniref50" },
+        { "exampl.es/uniref50", null, "exampl.es/uniref50" },
+        { "examples/uniref50.", "", "examples/uniref50." },
+        { "https://www.jalview.org:443/examples/uniref50.fa", "fa",
+            "https://www.jalview.org:443/examples/uniref50." },
+        { "https://www.jalview.org:443/examples/uniref50", null,
+            "https://www.jalview.org:443/examples/uniref50" },
+        { "https://www.jalview.org:443/examples/.uniref50", null,
+            "https://www.jalview.org:443/examples/.uniref50" },
+        { "https://www.jalview.org:443/exampl.es/uniref50", null,
+            "https://www.jalview.org:443/exampl.es/uniref50" },
+        { "https://www.jalview.org:443/examples/uniref50.", "",
+            "https://www.jalview.org:443/examples/uniref50." },
+        /*
+        */
+        //
+    };
+  }
 }
diff --git a/test/jalview/util/HttpUtilsTest.java b/test/jalview/util/HttpUtilsTest.java
new file mode 100644 (file)
index 0000000..fbd8149
--- /dev/null
@@ -0,0 +1,93 @@
+package jalview.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Locale;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class HttpUtilsTest
+{
+  @Test(groups = { "Network" }, dataProvider = "urlTargetsAndDestinations")
+  public void testFollowConnection(String targetUrl, String finalUrl,
+          String notUsed0, String notUsed1) throws IOException
+  {
+    URL tUrl = new URL(targetUrl);
+    URL fUrl = new URL(finalUrl);
+    HttpURLConnection conn1 = HttpUtils
+            .followConnection((HttpURLConnection) tUrl.openConnection());
+    URL url1 = conn1.getURL();
+    Assert.assertEquals(url1, fUrl, "Final URL is not the same.");
+  }
+
+  @Test(groups = { "Network" }, dataProvider = "urlTargetsAndDestinations")
+  public void testOpenConnection(String targetUrl, String finalUrl,
+          String notUsed0, String notUsed1) throws IOException
+  {
+    URL tUrl = new URL(targetUrl);
+    URL fUrl = new URL(finalUrl);
+    HttpURLConnection conn1 = HttpUtils.openConnection(tUrl);
+    URL url1 = conn1.getURL();
+    Assert.assertEquals(url1, fUrl, "Final URL is not the same.");
+  }
+
+  @Test(groups = { "Network" }, dataProvider = "urlTargetsAndDestinations")
+  public void testOpenStream(String targetUrl, String finalUrl,
+          String inFirstLine, String inDocument) throws IOException
+  {
+    URL tUrl = new URL(targetUrl);
+    URL fUrl = new URL(finalUrl);
+    InputStream is1 = HttpUtils.openStream(tUrl);
+    BufferedReader br1 = new BufferedReader(new InputStreamReader(is1));
+    String firstLine = br1.readLine().toLowerCase(Locale.ROOT);
+    Assert.assertTrue(
+            firstLine.contains(inFirstLine.toLowerCase(Locale.ROOT)),
+            "First line of text '" + firstLine + "' does not contain '"
+                    + inFirstLine + "'");
+    String inDocumentLC = inDocument.toLowerCase(Locale.ROOT);
+    boolean found = false;
+    String line = null;
+    while ((line = br1.readLine()) != null)
+    {
+      if (line.toLowerCase(Locale.ROOT).contains(inDocumentLC))
+      {
+        found = true;
+        break;
+      }
+    }
+    Assert.assertTrue(found,
+            "Text '" + inDocument + "' not found in '" + finalUrl + "'");
+  }
+
+  @DataProvider(name = "urlTargetsAndDestinations")
+  public Object[][] urlTargetsAndDestinations()
+  {
+    /*
+    String targetUrl, // the URL you ask for
+    String finalUrl, // the URL you end up at
+    String foundInFirstLine, // some text found in the first line
+    String foundInDocument, // some text found in the document (and won't be in an error page)
+    */
+    return new Object[][] {
+        //
+        /*
+         */
+        { "http://jalview.org/", "https://www.jalview.org/", "<!doctype",
+            "Jalview is a" },
+        { "http://www.jalview.org/", "https://www.jalview.org/",
+            "<!doctype", "Jalview is a" },
+        { "https://jalview.org", "https://www.jalview.org/", "<!doctype",
+            "Jalview is a" },
+        /*
+         */
+        //
+    };
+  }
+
+}
index e46f524..7c5fd15 100755 (executable)
 #!/usr/bin/env bash
 
 # perform a dev build and install on local macOS machine
-INSTALLERVOL="Jalview Non-Release Installer"
-APP="Jalview Local.app"
-
+APP=""
+INSTALLERVOL=""
 APPLICATIONS=/Applications
-CHANNEL=NOCHANNEL
+CHANNEL="LOCAL"
 DMG=build/install4j/11/Jalview_Local-TEST-macos-java_11.dmg
+GRADLE=""
+APPBASEOVERRIDEARG=""
+MEDIA=macosArchive
+CLEAN="clean"
+JAVA=11
+x=$(grep jalview.version= RELEASE)
+VERSION=${x#*=}
+
+while getopts ":i:n:a:c:d:go:m:j:l" opt; do
+  case ${opt} in
+    i)
+      INSTALLERVOL="${OPTARG}"
+      ;;
+    n)
+      APP="${OPTARG}"
+      ;;
+    a)
+      APPLICATIONS="${OPTARG}"
+      ;;
+    c)
+      CHANNEL="${OPTARG}"
+      ;;
+    d)
+      DMG="${OPTARG}"
+      ;;
+    g)
+      GRADLE=1
+      ;;
+    o)
+      APPBASEOVERRIDEARG="-Pgetdown_appbase_override=${OPTARG}"
+      ;;
+    m)
+      MEDIA="${OPTARG}"
+      ;;
+    j)
+      JAVA="${OPTARG}"
+      ;;
+    l)
+      CLEAN=""
+      ;;
+    ?)
+      echo "Invalid option -${OPTARG}"
+      exit 1;
+      ;;
+  esac
+done
 
+if [ -z $APP ]; then
+  ARCH=x64
+  if [ $(uname -m) = "arm64" ]; then
+    ARCH=aarch64
+  fi
+  OS=macos
+  case $(uname -o) in
+    Darwin)
+      OS=macos
+      ;;
+    Windows)
+      OS=windows
+      ;;
+    Linux)
+      OS=linux
+      ;;
+    *)
+      OS=unix
+      ;;
+  esac
+  case ${CHANNEL} in
+    DEVELOP)
+      APP="Jalview Develop"
+      DMG="build/install4j/11/${APP// /_}-${VERSION//\./_}-d$(date +%Y%m%d)-${OS}-${ARCH}-java_${JAVA}.dmg"
+      ;;
+    TEST-RELEASE)
+      APP="Jalview Test"
+      DMG="build/install4j/11/${APP// /_}-${VERSION//\./_}-test-${OS}-${ARCH}-java_${JAVA}.dmg"
+      ;;
+    RELEASE)
+      APP="Jalview"
+      DMG="build/install4j/11/${APP// /_}-${VERSION//\./_}-${OS}-${ARCH}-java_${JAVA}.dmg"
+      ;;
+    *)
+      APP="Jalview Local"
+      DMG=build/install4j/11/${APP// /_}-TEST-macos-java_11.dmg
+      ;;
+  esac
+fi
+if [ -z $INSTALLERVOL ]; then
+  INSTALLERVOL="${APP} Installer"
+fi
 
-if [ x$1 != "xnogradle" ]; then
-  gradle installers -PCHANNEL=LOCAL -Pinstall4j_media_types=macosArchive
+if [ "${GRADLE}" = 1 ]; then
+  echo "Running: gradle ${CLEAN} installers -PCHANNEL="${CHANNEL}" -Pinstall4j_media_types="${MEDIA}" ${APPBASEOVERRIDEARG} -PJAVA_VERSION=${JAVA}"
+  gradle ${CLEAN} installers -PCHANNEL="${CHANNEL}" -Pinstall4j_media_types="${MEDIA}" ${APPBASEOVERRIDEARG} -PJAVA_VERSION=${JAVA}
 else
   echo "Not running gradle installers"
 fi
 
 if [ $? = 0 ]; then
-  umount "/Volumes/$INSTALLERVOL"
+  if [ -e "/Volumes/$INSTALLERVOL" ]; then
+    hdiutil detach "/Volumes/$INSTALLERVOL"
+  fi
   if [ -e "$DMG" ]; then
     open $DMG
   else
     echo "No DMG file '$DMG'" 1>&2
-    exit 1
+    exit 2
   fi
   echo "Mounting '$DMG' at /Volumes"
   N=0
-  while [ \! -e "/Volumes/$INSTALLERVOL/$APP" ]; do
-    if [ $(( N%1000 )) = 0 ]; then
-      echo -n "."
-    fi
+  MOUNTEDAPP="/Volumes/$INSTALLERVOL/$APP.app"
+  echo "Waiting for '$MOUNTEDAPP' to appear"
+  while [ \! -e "$MOUNTEDAPP" ]; do
+    echo -n "."
     N=$(( N+1 ))
+    if [ $N = 40 ]; then
+      echo ""
+      echo "Looks like something wrong with the DMG '$DMG'"
+      exit 4
+    fi
+    sleep 0.1
   done
   echo ""
+else
+  echo "Problem with gradle build: exit code $?"
+  exit 3
 fi
-if [ -e "/Volumes/$INSTALLERVOL/$APP" ]; then
-  echo "Removing '$APPLICATIONS/$APP'"
-  /bin/rm -r "$APPLICATIONS/$APP"
-  echo "Syncing '/Volumes/$INSTALLERVOL/$APP' to '$APPLICATIONS/'"
-  rsync -avh "/Volumes/$INSTALLERVOL/$APP" "$APPLICATIONS/"
+
+if [ -e "$MOUNTEDAPP" ]; then
+  echo "Removing '$APPLICATIONS/$APP.app'"
+  /bin/rm -r "$APPLICATIONS/$APP.app"
+  echo "Syncing '$MOUNTEDAPP' to '$APPLICATIONS/'"
+  rsync -avh "$MOUNTEDAPP" "$APPLICATIONS/"
   echo "Unmounting '/Volumes/$INSTALLERVOL'"
-  umount "/Volumes/$INSTALLERVOL"
+  hdiutil detach "/Volumes/$INSTALLERVOL"
 fi
index f7e17a1..96aee95 100755 (executable)
@@ -30,7 +30,9 @@ my $mimetypes = {
 };
 
 my @dontaddshortname = qw(features json);
-my @dontaddextension = qw(html xml json jar mfa fastq);
+# mfa and fastq not properly supported in Jalview (but enough to be in the application extensions)
+# ENA flatfile extension txt is too generic, as well as html xml json jar
+my @dontaddextension = qw(txt html xml json jar mfa fastq);
 my $add_associations = {
   biojson => {shortname=>"biojson",name=>"BioJSON",extensions=>["biojson"]},
   gff2 => {shortname=>"gff2",name=>"Generic Features Format v2",extensions=>["gff2"]},
@@ -49,7 +51,7 @@ my $add_extensions = {
 my @put_first = qw(jalview jvl);
 my @owner = @put_first;
 
-my @non_primary = qw(mmcif mmcif2 pdb);
+my @non_primary = qw(mmcif mmcif2 pdb txt);
 
 my $v = ($i4jversion >= 8)?$i4jversion:"";
 my $i4jtemplatefile = "file_associations_template-install4j${v}.xml";
diff --git a/utils/install4j/auto_file_associations-i4j8.pl b/utils/install4j/auto_file_associations-i4j8.pl
deleted file mode 100755 (executable)
index 31a4afa..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-#!/usr/bin/env perl
-
-use strict;
-
-my $i4jversion = 8;
-if ($ARGV[0] eq "-v") {
-  shift @ARGV;
-  $i4jversion = shift @ARGV;
-  die("-v i4jversion must be an integer [probably 7 or 8]") unless $i4jversion =~ m/^\d+$/;
-}
-
-my $fileformats = $ARGV[0];
-$fileformats = "../../src/jalview/io/FileFormat.java" unless $fileformats;
-
-# default mimetype will be text/x-$shortname
-# TODO: find an actual extension for mat, see JAL-Xxxxx for outstanding issues too
-# TODO: look up standard mime type used for BLASTfmt matrices, etc
-my $mimetypes = {
-  rnaml => "application/rnaml+xml",
-  biojson => "application/x-jalview-biojson+json",
-  jnet => "application/x-jalview-jnet+text",
-  features => "application/x-jalview-features+text",
-  scorematrix => "application/x-jalview-scorematrix+text",
-  pdb => "chemical/x-pdb",
-  mmcif => "chemical/x-cif",
-  mmcif2 => "chemical/x-mmcif",
-  jalview => "application/x-jalview+xml+zip",
-  jvl => "application/x-jalview-jvl+text",
-  annotations => "application/x-jalview-annotations+text",
-};
-
-my @dontaddshortname = qw(features json);
-my @dontaddextension = qw(html xml json jar mfa fastq);
-my $add_associations = {
-  biojson => {shortname=>"biojson",name=>"BioJSON",extensions=>["biojson"]},
-  gff2 => {shortname=>"gff2",name=>"Generic Features Format v2",extensions=>["gff2"]},
-  gff3 => {shortname=>"gff3",name=>"Generic Features Format v3",extensions=>["gff3"]},
-  features => {shortname=>"features",name=>"Jalview Features",extensions=>["features","jvfeatures"]},
-  annotations => {shortname=>"annotations",name=>"Jalview Annotations",extensions=>["annotations","jvannotations"]},
-  mmcif => {shortname=>"mmcif",name=>"CIF",extensions=>["cif"]},
-  mmcif2 => {shortname=>"mmcif2",name=>"mmCIF",extensions=>["mcif","mmcif"]},
-  jvl => {shortname=>"jvl",name=>"Jalview Launch",extensions=>["jvl"],iconfile=>"jvl_file"},
-  jnet => {shortname=>"jnet",name=>"JnetFile",extensions=>["concise","jnet"]},
-  scorematrix => {shortname=>"scorematrix",name=>"Substitution Matrix",extensions=>["mat"]},
-};
-my $add_extensions = {
-  blc => ["blc"],
-};
-my @put_first = qw(jalview jvl);
-
-my @non_primary = qw(mmcif mmcif2 pdb);
-
-my $v = ($i4jversion >= 8)?$i4jversion:"";
-my $i4jtemplatefile = "file_associations_template-install4j${v}.xml";
-my $i4jtemplate;
-my $mactemplatefile = "file_associations_template-Info_plist.xml";
-my $mactemplate;
-
-open(MT,"<$mactemplatefile") or die("Could not open '$mactemplatefile' for reading");
-while(<MT>){
-  $mactemplate .= $_;
-}
-close(MT);
-open(IT,"<$i4jtemplatefile") or die("Could not open '$i4jtemplatefile' for reading");
-while(<IT>){
-  $i4jtemplate .= $_;
-}
-close(IT);
-my $macauto;
-my $i4jauto;
-
-my $macautofile = $mactemplatefile;
-$macautofile =~ s/template/auto$1/;
-
-my $i4jautofile = $i4jtemplatefile;
-$i4jautofile =~ s/template/auto$1/;
-
-for my $key (sort keys %$add_associations) {
-  my $a = $add_associations->{$key};
-  warn("Known file association for $a->{shortname} (".join(",",@{$a->{extensions}}).")\n");
-}
-
-open(MA,">$macautofile") or die ("Could not open '$macautofile' for writing");
-print MA "<key>CFBundleDocumentTypes</key>\n<array>\n\n";
-
-open(IA,">$i4jautofile") or die ("Could not open '$i4jautofile' for writing");
-
-open(IN, "<$fileformats") or die ("Could not open '$fileformats' for reading");
-my $id = 10000;
-my $file_associations = {};
-while(my $line = <IN>) {
-  $line =~ s/\s+/ /g;
-  $line =~ s/(^ | $)//g;
-  if ($line =~ m/^(\w+) ?\( ?"([^"]*)" ?, ?"([^"]*)" ?, ?(true|false) ?, ?(true|false) ?\)$/i) {
-    my $shortname = lc($1);
-    next if (grep($_ eq $shortname, @dontaddshortname));
-    my $name = $2;
-    my $extensions = $3;
-    $extensions =~ s/\s+//g;
-    my @possextensions = map(lc($_),split(m/,/,$extensions));
-    my @extensions;
-    my $addext = $add_extensions->{$shortname};
-    if (ref($addext) eq "ARRAY") {
-      push(@possextensions, @$addext);
-    }
-    for my $possext (@possextensions) {
-      next if grep($_ eq $possext, @extensions);
-      next if grep($_ eq $possext, @dontaddextension);
-      push(@extensions,$possext);
-    }
-    next unless scalar(@extensions);
-    $file_associations->{$shortname} = {
-      shortname => $shortname,
-      name => $name,
-      extensions => \@extensions
-    };
-    warn("Reading file association for $shortname (".join(",",@extensions).")\n");
-  }
-}
-close(IN);
-
-my %all_associations = (%$file_associations, %$add_associations);
-
-my @ordered = (@put_first, @non_primary);
-for my $key (sort keys %all_associations) {
-  next if grep($_ eq $key, @ordered);
-  push(@ordered, $key);
-}
-my $num = $#ordered + 1;
-
-warn("--\n");
-
-my $i4jcount = 0;
-for my $shortname (@ordered) {
-  my $a = $all_associations{$shortname};
-  next if (ref($a) ne "HASH");
-
-  my $name = $a->{name};
-  my $extensions = $a->{extensions};
-  my $mimetype = $mimetypes->{$shortname};
-  $mimetype = "application/x-$shortname+txt" unless $mimetype;
-
-  my $iconfile = $a->{iconfile};
-  $iconfile = "Jalview-File" unless $iconfile;
-
-  my $primary = (! grep($_ eq $shortname, @non_primary));
-  my $primarystring = $primary?"true":"false";
-  my $role = $primary?"Editor":"Viewer";
-
-  my @extensions = @$extensions;
-
-  my $xname = xml_escape($name);
-  my $xmimetype = xml_escape($mimetype);
-  my $xshortname = xml_escape($shortname);
-  my $xiconfile = xml_escape($iconfile);
-  my $xrole = xml_escape($role);
-  my $xROLE = xml_escape(uc($role));
-  my $xprimarystring = xml_escape($primarystring);
-
-  my $macentry = $mactemplate;
-  $macentry =~ s/\$\$NAME\$\$/$xname/g;
-  $macentry =~ s/\$\$SHORTNAME\$\$/$xshortname/g;
-  $macentry =~ s/\$\$MIMETYPE\$\$/$xmimetype/g;
-  $macentry =~ s/\$\$ICONFILE\$\$/$xiconfile/g;
-  $macentry =~ s/\$\$ROLE\$\$/$xrole/g;
-  $macentry =~ s/\$\$PRIMARY\$\$/$xprimarystring/g;
-  while ($macentry =~ m/\$\$([^\$]*)EXTENSIONS([^\$]*)\$\$/) {
-    my $pre = $1;
-    my $post = $2;
-    my $macextensions;
-    for my $ext (@extensions) {
-      my $xext = xml_escape($ext);
-      $macextensions .= $pre.$xext.$post;
-    }
-    $macentry =~ s/\$\$${pre}EXTENSIONS${post}\$\$/$macextensions/g;
-  }
-  print MA $macentry;
-
-  my $i4jentry = $i4jtemplate;
-  $i4jentry =~ s/\$\$NAME\$\$/$xname/g;
-  $i4jentry =~ s/\$\$SHORTNAME\$\$/$xshortname/g;
-  $i4jentry =~ s/\$\$MIMETYPE\$\$/$xmimetype/g;
-  $i4jentry =~ s/\$\$ICONFILE\$\$/$xiconfile/g;
-  $i4jentry =~ s/\$\$PRIMARY\$\$/$xprimarystring/g;
-  $i4jentry =~ s/\$\$MACASSOCIATIONROLE\$\$/$xROLE/g;
-
-  my $ext = join(",",sort(@extensions));
-  my $xdisplayext = xml_escape(join(", ", map(".$_",sort(@extensions))));
-  my $progresspercent = int(($i4jcount/$num)*100);
-  $progresspercent = 100 if $progresspercent > 100;
-  $i4jcount++;
-  my $xext = xml_escape($ext);
-  my $addunixextension = "true";
-
-  $i4jentry =~ s/\$\$ADDUNIXEXTENSION\$\$/$addunixextension/g;
-  $i4jentry =~ s/\$\$EXTENSION\$\$/$xext/g;
-  $i4jentry =~ s/\$\$DISPLAYEXTENSION\$\$/$xdisplayext/g;
-  $i4jentry =~ s/\$\$PROGRESSPERCENT\$\$/$progresspercent/g;
-  $i4jentry =~ s/\$\$ID\$\$/$id/g;
-  $id++;
-  $i4jentry =~ s/\$\$ID1\$\$/$id/g;
-  $id++;
-  $i4jentry =~ s/\$\$ID2\$\$/$id/g;
-  $id++;
-
-  print IA $i4jentry;
-
-  delete $all_associations{$shortname};
-  warn("Writing entry for $name (".join(",",@$extensions).": $mimetype)\n");
-}
-
-close(IA);
-print MA "</array>\n";
-close(MA);
-
-sub xml_escape {
-  my $x = shift;
-  # stolen from Pod::Simple::XMLOutStream in base distro
-  $x =~ s/([^-\n\t !\#\$\%\(\)\*\+,\.\~\/\:\;=\?\@\[\\\]\^_\`\{\|\}a-zA-Z0-9])/'&#'.(ord($1)).';'/eg;
-  return $x;
-}  
index 2e23321..1a75139 100644 (file)
 <dict>
 <key>CFBundleTypeExtensions</key>
 <array>
-<string>txt</string>
+<string>fa</string>
+<string>fasta</string>
 </array>
 <key>CFBundleTypeName</key>
-<string>ENA Flatfile File</string>
+<string>Fasta File</string>
 <key>CFBundleTypeIconFile</key>
 <string>Jalview-File.icns</string>
 <key>CFBundleTypeRole</key>
 <string>Default</string>
 <key>CFBundleTypeMIMETypes</key>
 <array>
-<string>application/x-embl+txt</string>
+<string>application/x-fasta+txt</string>
 </array>
 <key>LSIsAppleDefaultForType</key>
 <true/>
 <dict>
 <key>CFBundleTypeExtensions</key>
 <array>
-<string>fa</string>
-<string>fasta</string>
+<string>features</string>
+<string>jvfeatures</string>
 </array>
 <key>CFBundleTypeName</key>
-<string>Fasta File</string>
+<string>Jalview Features File</string>
 <key>CFBundleTypeIconFile</key>
 <string>Jalview-File.icns</string>
 <key>CFBundleTypeRole</key>
 <string>Default</string>
 <key>CFBundleTypeMIMETypes</key>
 <array>
-<string>application/x-fasta+txt</string>
+<string>application/x-jalview-features+text</string>
 </array>
 <key>LSIsAppleDefaultForType</key>
 <true/>
 <dict>
 <key>CFBundleTypeExtensions</key>
 <array>
-<string>features</string>
-<string>jvfeatures</string>
+<string>fc</string>
 </array>
 <key>CFBundleTypeName</key>
-<string>Jalview Features File</string>
+<string>Jalview Feature Settings File File</string>
 <key>CFBundleTypeIconFile</key>
 <string>Jalview-File.icns</string>
 <key>CFBundleTypeRole</key>
 <string>Default</string>
 <key>CFBundleTypeMIMETypes</key>
 <array>
-<string>application/x-jalview-features+text</string>
+<string>application/x-featuresettings+txt</string>
 </array>
 <key>LSIsAppleDefaultForType</key>
 <true/>
index ee70251..4a87364 100644 (file)
@@ -53,9 +53,9 @@
                     </serializedBean>
                   </action>
 
-                  <action name="Jalview Launch (.jvl) progress bar 4" id="10004" customizedId="Jalview Launch-jvl-10004-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Jalview Launch (.jvl) progress bar 3" id="10004" customizedId="Jalview Launch-jvl-10004-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="4" />
+                      <property name="percentValue" type="int" value="3" />
                     </serializedBean>
                   </action>
 
@@ -98,9 +98,9 @@
                     </serializedBean>
                   </action>
 
-                  <action name="CIF (.cif) progress bar 8" id="10007" customizedId="CIF-cif-10007-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="CIF (.cif) progress bar 7" id="10007" customizedId="CIF-cif-10007-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="8" />
+                      <property name="percentValue" type="int" value="7" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="mmCIF (.mcif, .mmcif) progress bar 12" id="10010" customizedId="mmCIF-mcif,mmcif-10010-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="mmCIF (.mcif, .mmcif) progress bar 11" id="10010" customizedId="mmCIF-mcif,mmcif-10010-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="12" />
+                      <property name="percentValue" type="int" value="11" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="PDB (.ent, .pdb) progress bar 16" id="10013" customizedId="PDB-ent,pdb-10013-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PDB (.ent, .pdb) progress bar 15" id="10013" customizedId="PDB-ent,pdb-10013-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="16" />
+                      <property name="percentValue" type="int" value="15" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="AMSA (.amsa) progress bar 20" id="10016" customizedId="AMSA-amsa-10016-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="AMSA (.amsa) progress bar 19" id="10016" customizedId="AMSA-amsa-10016-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="20" />
+                      <property name="percentValue" type="int" value="19" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="Jalview Annotations (.annotations, .jvannotations) progress bar 24" id="10019" customizedId="Jalview Annotations-annotations,jvannotations-10019-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Jalview Annotations (.annotations, .jvannotations) progress bar 23" id="10019" customizedId="Jalview Annotations-annotations,jvannotations-10019-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="24" />
+                      <property name="percentValue" type="int" value="23" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="BioJSON (.biojson) progress bar 28" id="10022" customizedId="BioJSON-biojson-10022-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="BioJSON (.biojson) progress bar 26" id="10022" customizedId="BioJSON-biojson-10022-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="28" />
+                      <property name="percentValue" type="int" value="26" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="BLC (.blc) progress bar 32" id="10025" customizedId="BLC-blc-10025-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="BLC (.blc) progress bar 30" id="10025" customizedId="BLC-blc-10025-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="32" />
+                      <property name="percentValue" type="int" value="30" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="Clustal (.aln) progress bar 36" id="10028" customizedId="Clustal-aln-10028-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Clustal (.aln) progress bar 34" id="10028" customizedId="Clustal-aln-10028-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="36" />
+                      <property name="percentValue" type="int" value="34" />
                     </serializedBean>
                   </action>
 
                   </action>
 <!-- END -->
 
-<!-- ENA Flatfile (.txt) BEGIN -->
-                  <action name="ENA Flatfile (.txt) message" id="10030" customizedId="ENA Flatfile-txt-10030-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+<!-- Fasta (.fa, .fasta) BEGIN -->
+                  <action name="Fasta (.fa, .fasta) message" id="10030" customizedId="Fasta-fa,fasta-10030-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="detailMessage" type="string">ENA Flatfile (.txt)</property>
+                      <property name="detailMessage" type="string">Fasta (.fa, .fasta)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                       <property name="useDetail" type="boolean" value="true" />
                       <property name="useStatus" type="boolean" value="true" />
                     </serializedBean>
                   </action>
 
-                  <action name="ENA Flatfile (.txt) progress bar 40" id="10031" customizedId="ENA Flatfile-txt-10031-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Fasta (.fa, .fasta) progress bar 38" id="10031" customizedId="Fasta-fa,fasta-10031-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="40" />
+                      <property name="percentValue" type="int" value="38" />
                     </serializedBean>
                   </action>
 
-                  <action name="ENA Flatfile (.txt) file association" id="10032" customizedId="ENA Flatfile-txt-10032-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .txt file association">
+                  <action name="Fasta (.fa, .fasta) file association" id="10032" customizedId="Fasta-fa,fasta-10032-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .fa,fasta file association">
                     <serializedBean>
-                      <property name="description" type="string">ENA Flatfile File</property>
-                      <property name="extension" type="string">txt</property>
+                      <property name="description" type="string">Fasta File</property>
+                      <property name="extension" type="string">fa,fasta</property>
                       <property name="launcherId" type="string">JALVIEW</property>
                       <!--<property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.png</string>
                         </object>
                       </property>
-                      <property name="unixMimeType" type="string">application/x-embl+txt</property>
+                      <property name="unixMimeType" type="string">application/x-fasta+txt</property>
                       <property name="windowsIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.ico</string>
                   </action>
 <!-- END -->
 
-<!-- Fasta (.fa, .fasta) BEGIN -->
-                  <action name="Fasta (.fa, .fasta) message" id="10033" customizedId="Fasta-fa,fasta-10033-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+<!-- Jalview Features (.features, .jvfeatures) BEGIN -->
+                  <action name="Jalview Features (.features, .jvfeatures) message" id="10033" customizedId="Jalview Features-features,jvfeatures-10033-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="detailMessage" type="string">Fasta (.fa, .fasta)</property>
+                      <property name="detailMessage" type="string">Jalview Features (.features, .jvfeatures)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                       <property name="useDetail" type="boolean" value="true" />
                       <property name="useStatus" type="boolean" value="true" />
                     </serializedBean>
                   </action>
 
-                  <action name="Fasta (.fa, .fasta) progress bar 44" id="10034" customizedId="Fasta-fa,fasta-10034-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Jalview Features (.features, .jvfeatures) progress bar 42" id="10034" customizedId="Jalview Features-features,jvfeatures-10034-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="44" />
+                      <property name="percentValue" type="int" value="42" />
                     </serializedBean>
                   </action>
 
-                  <action name="Fasta (.fa, .fasta) file association" id="10035" customizedId="Fasta-fa,fasta-10035-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .fa,fasta file association">
+                  <action name="Jalview Features (.features, .jvfeatures) file association" id="10035" customizedId="Jalview Features-features,jvfeatures-10035-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .features,jvfeatures file association">
                     <serializedBean>
-                      <property name="description" type="string">Fasta File</property>
-                      <property name="extension" type="string">fa,fasta</property>
+                      <property name="description" type="string">Jalview Features File</property>
+                      <property name="extension" type="string">features,jvfeatures</property>
                       <property name="launcherId" type="string">JALVIEW</property>
                       <!--<property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.png</string>
                         </object>
                       </property>
-                      <property name="unixMimeType" type="string">application/x-fasta+txt</property>
+                      <property name="unixMimeType" type="string">application/x-jalview-features+text</property>
                       <property name="windowsIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.ico</string>
                   </action>
 <!-- END -->
 
-<!-- Jalview Features (.features, .jvfeatures) BEGIN -->
-                  <action name="Jalview Features (.features, .jvfeatures) message" id="10036" customizedId="Jalview Features-features,jvfeatures-10036-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
+<!-- Jalview Feature Settings File (.fc) BEGIN -->
+                  <action name="Jalview Feature Settings File (.fc) message" id="10036" customizedId="Jalview Feature Settings File-fc-10036-message" beanClass="com.install4j.runtime.beans.actions.control.SetMessageAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="detailMessage" type="string">Jalview Features (.features, .jvfeatures)</property>
+                      <property name="detailMessage" type="string">Jalview Feature Settings File (.fc)</property>
                       <property name="statusMessage" type="string">Creating file associations...</property>
                       <property name="useDetail" type="boolean" value="true" />
                       <property name="useStatus" type="boolean" value="true" />
                     </serializedBean>
                   </action>
 
-                  <action name="Jalview Features (.features, .jvfeatures) progress bar 48" id="10037" customizedId="Jalview Features-features,jvfeatures-10037-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Jalview Feature Settings File (.fc) progress bar 46" id="10037" customizedId="Jalview Feature Settings File-fc-10037-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="48" />
+                      <property name="percentValue" type="int" value="46" />
                     </serializedBean>
                   </action>
 
-                  <action name="Jalview Features (.features, .jvfeatures) file association" id="10038" customizedId="Jalview Features-features,jvfeatures-10038-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .features,jvfeatures file association">
+                  <action name="Jalview Feature Settings File (.fc) file association" id="10038" customizedId="Jalview Feature Settings File-fc-10038-fileassociation" beanClass="com.install4j.runtime.beans.actions.desktop.CreateFileAssociationAction" actionElevationType="elevated" rollbackBarrierExitCode="0" errorMessage="Could not make .fc file association">
                     <serializedBean>
-                      <property name="description" type="string">Jalview Features File</property>
-                      <property name="extension" type="string">features,jvfeatures</property>
+                      <property name="description" type="string">Jalview Feature Settings File File</property>
+                      <property name="extension" type="string">fc</property>
                       <property name="launcherId" type="string">JALVIEW</property>
                       <!--<property name="macIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.png</string>
                         </object>
                       </property>
-                      <property name="unixMimeType" type="string">application/x-jalview-features+text</property>
+                      <property name="unixMimeType" type="string">application/x-featuresettings+txt</property>
                       <property name="windowsIconFile">
                         <object class="com.install4j.api.beans.ExternalFile">
                           <string>Jalview-File.ico</string>
                     </serializedBean>
                   </action>
 
-                  <action name="GenBank Flatfile (.gb, .gbk) progress bar 52" id="10040" customizedId="GenBank Flatfile-gb,gbk-10040-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="GenBank Flatfile (.gb, .gbk) progress bar 50" id="10040" customizedId="GenBank Flatfile-gb,gbk-10040-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="52" />
+                      <property name="percentValue" type="int" value="50" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="Generic Features Format v2 (.gff2) progress bar 56" id="10043" customizedId="Generic Features Format v2-gff2-10043-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Generic Features Format v2 (.gff2) progress bar 53" id="10043" customizedId="Generic Features Format v2-gff2-10043-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="56" />
+                      <property name="percentValue" type="int" value="53" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="Generic Features Format v3 (.gff3) progress bar 60" id="10046" customizedId="Generic Features Format v3-gff3-10046-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Generic Features Format v3 (.gff3) progress bar 57" id="10046" customizedId="Generic Features Format v3-gff3-10046-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="60" />
+                      <property name="percentValue" type="int" value="57" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="JnetFile (.concise, .jnet) progress bar 64" id="10049" customizedId="JnetFile-concise,jnet-10049-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="JnetFile (.concise, .jnet) progress bar 61" id="10049" customizedId="JnetFile-concise,jnet-10049-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="64" />
+                      <property name="percentValue" type="int" value="61" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="MSF (.msf) progress bar 68" id="10052" customizedId="MSF-msf-10052-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="MSF (.msf) progress bar 65" id="10052" customizedId="MSF-msf-10052-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="68" />
+                      <property name="percentValue" type="int" value="65" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="PFAM (.pfam) progress bar 72" id="10055" customizedId="PFAM-pfam-10055-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PFAM (.pfam) progress bar 69" id="10055" customizedId="PFAM-pfam-10055-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="72" />
+                      <property name="percentValue" type="int" value="69" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="PHYLIP (.phy) progress bar 76" id="10058" customizedId="PHYLIP-phy-10058-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PHYLIP (.phy) progress bar 73" id="10058" customizedId="PHYLIP-phy-10058-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="76" />
+                      <property name="percentValue" type="int" value="73" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="PileUp (.pileup) progress bar 80" id="10061" customizedId="PileUp-pileup-10061-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PileUp (.pileup) progress bar 76" id="10061" customizedId="PileUp-pileup-10061-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="80" />
+                      <property name="percentValue" type="int" value="76" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="PIR (.pir) progress bar 84" id="10064" customizedId="PIR-pir-10064-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="PIR (.pir) progress bar 80" id="10064" customizedId="PIR-pir-10064-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="84" />
+                      <property name="percentValue" type="int" value="80" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="RNAML (.rnaml) progress bar 88" id="10067" customizedId="RNAML-rnaml-10067-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="RNAML (.rnaml) progress bar 84" id="10067" customizedId="RNAML-rnaml-10067-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="88" />
+                      <property name="percentValue" type="int" value="84" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="Substitution Matrix (.mat) progress bar 92" id="10070" customizedId="Substitution Matrix-mat-10070-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Substitution Matrix (.mat) progress bar 88" id="10070" customizedId="Substitution Matrix-mat-10070-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="92" />
+                      <property name="percentValue" type="int" value="88" />
                     </serializedBean>
                   </action>
 
                     </serializedBean>
                   </action>
 
-                  <action name="Stockholm (.stk, .sto) progress bar 96" id="10073" customizedId="Stockholm-stk,sto-10073-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
+                  <action name="Stockholm (.stk, .sto) progress bar 92" id="10073" customizedId="Stockholm-stk,sto-10073-progressbar" beanClass="com.install4j.runtime.beans.actions.control.SetProgressAction" actionElevationType="none" rollbackBarrierExitCode="0">
                     <serializedBean>
-                      <property name="percentValue" type="int" value="96" />
+                      <property name="percentValue" type="int" value="92" />
                     </serializedBean>
                   </action>
 
index b0887e3..53b5b27 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<install4j version="10.0.6" transformSequenceNumber="10">
+<install4j version="10.0.7" transformSequenceNumber="10">
   <directoryPresets config="bin/Jalview" />
   <application name="${compiler:JALVIEW_APPLICATION_NAME}" applicationId="${compiler:WINDOWS_APPLICATION_ID}" mediaDir="${compiler:BUILD_DIR}" lzmaCompression="true" shortName="${compiler:INTERNAL_ID}" publisher="University of Dundee" publisherWeb="https://www.jalview.org/" version="${compiler:JALVIEW_VERSION}" allPathsRelative="true" macVolumeId="5aac4968c304f65" javaMinVersion="${compiler:JAVA_MIN_VERSION}" javaMaxVersion="${compiler:JAVA_MAX_VERSION}" allowBetaVM="true" jdkMode="jdk" jdkName="JDK 11.0">
     <searchSequence>
@@ -62,6 +62,8 @@
       <variable name="BACKGROUND" value="utils/channels/release/images/jalview_logo_background_fade-640x480.png" />
       <variable name="BATCH_WRAPPER_SCRIPT" value="jalview.bat" />
       <variable name="POWERSHELL_WRAPPER_SCRIPT" value="jalview.ps1" />
+      <variable name="WIZARD_WIDTH" value="640" description="Default/initial width of installer wizard window.  Linux media types adapt this.&#xA;NOT USED" />
+      <variable name="WIZARD_HEIGHT" value="480" description="Default/initial width of installer wizard window.  Linux media types adapt this.&#xA;NOT USED" />
     </variables>
     <codeSigning macEnabled="true" macPkcs12File="${compiler:OSX_KEYSTORE}" macNotarize="true" appleId="${compiler:OSX_APPLEID}">
       <macAdditionalBinaries>
       <macStaticAssociations>
         <urlHandler scheme="jalview" />
         <urlHandler scheme="jalviews" />
+        <urlHandler scheme="jalviewhttp" />
+        <urlHandler scheme="jalviewhttps" />
         <urlHandler scheme="${compiler:EXTRA_SCHEME}" />
       </macStaticAssociations>
     </launcher>
     <applications>
       <application id="installer" beanClass="com.install4j.runtime.beans.applications.InstallerApplication" styleId="35" customIcnsFile="${compiler:JALVIEW_DIR}/${compiler:MAC_ICONS_FILE}" customIcoFile="${compiler:JALVIEW_DIR}/${compiler:WINDOWS_ICONS_FILE}">
         <serializedBean>
+          <property name="frameHeight" type="int" value="480" />
+          <property name="frameWidth" type="int" value="640" />
           <property name="useCustomIcon" type="boolean" value="true" />
         </serializedBean>
         <styleOverrides>
@@ -568,16 +574,28 @@ return console.askOkCancel(message, true);
               </group>
               <action id="2350" beanClass="com.install4j.runtime.beans.actions.desktop.UrlHandlerAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
                 <serializedBean>
-                  <property name="launcherId" type="string">JALVIEW</property>
+                  <property name="launcherId" type="string">737</property>
                   <property name="scheme" type="string">jalview</property>
                 </serializedBean>
               </action>
-              <action id="2450" beanClass="com.install4j.runtime.beans.actions.desktop.UrlHandlerAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
+              <action id="2822" beanClass="com.install4j.runtime.beans.actions.desktop.UrlHandlerAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
                 <serializedBean>
-                  <property name="launcherId" type="string">JALVIEW</property>
+                  <property name="launcherId" type="string">737</property>
                   <property name="scheme" type="string">jalviews</property>
                 </serializedBean>
               </action>
+              <action id="2819" beanClass="com.install4j.runtime.beans.actions.desktop.UrlHandlerAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
+                <serializedBean>
+                  <property name="launcherId" type="string">737</property>
+                  <property name="scheme" type="string">jalviewhttp</property>
+                </serializedBean>
+              </action>
+              <action id="2820" beanClass="com.install4j.runtime.beans.actions.desktop.UrlHandlerAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
+                <serializedBean>
+                  <property name="launcherId" type="string">737</property>
+                  <property name="scheme" type="string">jalviewhttps</property>
+                </serializedBean>
+              </action>
               <action id="2641" beanClass="com.install4j.runtime.beans.actions.desktop.UrlHandlerAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
                 <serializedBean>
                   <property name="launcherId" type="string">JALVIEW</property>
@@ -1520,6 +1538,10 @@ ${compiler:JALVIEW_APPLICATION_NAME} will now launch.</property>
         <entry filesetId="2801" />
         <entry filesetId="2803" />
       </exclude>
+      <variables>
+        <variable name="variable" value="720" />
+        <variable name="WIZARD_HEIGHT" value="540" />
+      </variables>
       <jreBundle jreBundleSource="preCreated" includedJre="${compiler:LINUX_X64_JAVA_VM_TGZ}" manualJreEntry="true" />
     </unixInstaller>
     <unixInstaller name="Linux aarch64 Shell Installer" id="2782" customizedId="LINUX-AARCH64-SH" mediaFileName="${compiler:UNIX_APPLICATION_FOLDER}-${compiler:JALVIEW_VERSION}-linux-aarch64-java_${compiler:JAVA_INTEGER_VERSION}" installDir="${compiler:UNIX_APPLICATION_FOLDER}" customInstallBaseDir="~/opt/">
@@ -1531,6 +1553,10 @@ ${compiler:JALVIEW_APPLICATION_NAME} will now launch.</property>
         <entry filesetId="2801" />
         <entry filesetId="2803" />
       </exclude>
+      <variables>
+        <variable name="variable" value="720" />
+        <variable name="WIZARD_HEIGHT" value="540" />
+      </variables>
       <jreBundle jreBundleSource="preCreated" includedJre="${compiler:LINUX_AARCH64_JAVA_VM_TGZ}" manualJreEntry="true" />
     </unixInstaller>
     <unixArchive name="Unix .tar.gz Archive" id="1596" customizedId="UNIX--TGZ" mediaFileName="${compiler:UNIX_APPLICATION_FOLDER}-${compiler:JALVIEW_VERSION}-${compiler:sys.platform}-java_${compiler:JAVA_INTEGER_VERSION}" installDir="${compiler:UNIX_APPLICATION_FOLDER}">