Merge branch 'alpha/origin_2022_JAL-3066_Jalview_212_slivka-integration' into spike...
[jalview.git] / src / jalview / bin / Jalview.java
index a992ace..eca8147 100755 (executable)
  */
 package jalview.bin;
 
-import jalview.ext.so.SequenceOntology;
-import jalview.gui.AlignFrame;
-import jalview.gui.Desktop;
-import jalview.gui.PromptUserConfig;
-import jalview.io.AppletFormatAdapter;
-import jalview.io.BioJsHTMLOutput;
-import jalview.io.DataSourceType;
-import jalview.io.FileFormat;
-import jalview.io.FileFormatException;
-import jalview.io.FileFormatI;
-import jalview.io.FileLoader;
-import jalview.io.HtmlSvgOutput;
-import jalview.io.IdentifyFile;
-import jalview.io.NewickFile;
-import jalview.io.gff.SequenceOntologyFactory;
-import jalview.schemes.ColourSchemeI;
-import jalview.schemes.ColourSchemeProperty;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-import jalview.ws.jws2.Jws2Discoverer;
+import java.awt.GraphicsEnvironment;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -58,52 +39,151 @@ import java.security.PermissionCollection;
 import java.security.Permissions;
 import java.security.Policy;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Vector;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
-import javax.swing.LookAndFeel;
 import javax.swing.UIManager;
+import javax.swing.UIManager.LookAndFeelInfo;
+
+import com.threerings.getdown.util.LaunchUtil;
 
 import groovy.lang.Binding;
 import groovy.util.GroovyScriptEngine;
+import jalview.api.AlignCalcWorkerI;
+import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI;
+import jalview.ext.so.SequenceOntology;
+import jalview.gui.AlignFrame;
+import jalview.gui.AlignViewport;
+import jalview.gui.Desktop;
+import jalview.gui.Preferences;
+import jalview.gui.PromptUserConfig;
+import jalview.io.AppletFormatAdapter;
+import jalview.io.BioJsHTMLOutput;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FileFormatException;
+import jalview.io.FileFormatI;
+import jalview.io.FileFormats;
+import jalview.io.FileLoader;
+import jalview.io.HtmlSvgOutput;
+import jalview.io.IdentifyFile;
+import jalview.io.NewickFile;
+import jalview.io.gff.SequenceOntologyFactory;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeProperty;
+import jalview.util.ChannelProperties;
+import jalview.util.HttpUtils;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.ws.jws2.Jws2Discoverer;
 
 /**
  * Main class for Jalview Application <br>
  * <br>
- * start with java -Djava.ext.dirs=$PATH_TO_LIB$ jalview.bin.Jalview
+ * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
+ * jalview.bin.Jalview
+ * 
+ * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
+ * jalview.bin.Jalview jalview.bin.Jalview
+ * 
+ * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
+ * embellish '*' to e.g. '*.jar')
  * 
  * @author $author$
  * @version $Revision$
  */
-public class Jalview
+public class Jalview implements ApplicationSingletonI
 {
-  /*
-   * singleton instance of this class
-   */
-  private static Jalview instance;
+  // for testing those nasty messages you cannot ever find.
+  // static
+  // {
+  // System.setOut(new PrintStream(new ByteArrayOutputStream())
+  // {
+  // @Override
+  // public void println(Object o)
+  // {
+  // if (o != null)
+  // {
+  // System.err.println(o);
+  // }
+  // }
+  //
+  // });
+  // }
+  public static Jalview getInstance()
+  {
+    return (Jalview) ApplicationSingletonProvider
+            .getInstance(Jalview.class);
+  }
+
+  private Jalview()
+  {
+    Platform.getURLCommandArguments();
+  }
+
 
   private Desktop desktop;
 
-  public static AlignFrame currentAlignFrame;
+  public AlignFrame currentAlignFrame;
+
+  public String appletResourcePath;
+
+  public String j2sAppletID;
+
+  private boolean noCalculation, noMenuBar, noStatus;
+
+  private boolean noAnnotation;
+
+  public boolean getStartCalculations()
+  {
+    return !noCalculation;
+  }
+
+  public boolean getAllowMenuBar()
+  {
+    return !noMenuBar;
+  }
+
+  public boolean getShowStatus()
+  {
+    return !noStatus;
+  }
+
+  public boolean getShowAnnotation()
+  {
+    return !noAnnotation;
+  }
 
   static
   {
-    // grab all the rights we can the JVM
-    Policy.setPolicy(new Policy()
+    if (!Platform.isJS())
+    /**
+     * Java only
+     * 
+     * @j2sIgnore
+     */
     {
-      @Override
-      public PermissionCollection getPermissions(CodeSource codesource)
+      // grab all the rights we can for the JVM
+      Policy.setPolicy(new Policy()
       {
-        Permissions perms = new Permissions();
-        perms.add(new AllPermission());
-        return (perms);
-      }
+        @Override
+        public PermissionCollection getPermissions(CodeSource codesource)
+        {
+          Permissions perms = new Permissions();
+          perms.add(new AllPermission());
+          return (perms);
+        }
 
-      @Override
-      public void refresh()
-      {
-      }
-    });
+        @Override
+        public void refresh()
+        {
+        }
+      });
+    }
   }
 
   /**
@@ -115,8 +195,8 @@ public class Jalview
   class FeatureFetcher
   {
     /*
-     * TODO: generalise to track all jalview events to orchestrate batch
-     * processing events.
+     * TODO: generalise to track all jalview events to orchestrate batch processing
+     * events.
      */
 
     private int queued = 0;
@@ -165,79 +245,136 @@ public class Jalview
 
   }
 
-  public static Jalview getInstance()
-  {
-    return instance;
-  }
+  private final static boolean doPlatformLogging = false;
 
   /**
    * main class for Jalview application
    * 
    * @param args
    *          open <em>filename</em>
-   * @throws InterruptedException
-   * @throws IOException
    */
   public static void main(String[] args)
   {
-    instance = new Jalview();
-    instance.doMain(args);
+    if (doPlatformLogging)
+    {
+      Platform.startJavaLogging();
+    }
+
+    getInstance().doMain(args);
+
   }
+  
+
+  
 
   /**
    * @param args
-   * @throws InterruptedException
-   * @throws IOException
    */
   void doMain(String[] args)
   {
-    System.setSecurityManager(null);
+
+    boolean isJS = Platform.isJS();
+    if (!isJS)
+    {
+      System.setSecurityManager(null);
+    }
+
+    /*
+     * @j2sNative J2S.db._DirectDatabaseCalls["compbio.dundee.ac.uk"]=null;
+     * @j2sNative J2S.db._DirectDatabaseCalls["jalview.org"]=null;
+     * 
+     */
     System.out
             .println("Java version: " + System.getProperty("java.version"));
+    System.out.println("Java Home: " + System.getProperty("java.home"));
     System.out.println(System.getProperty("os.arch") + " "
             + System.getProperty("os.name") + " "
             + System.getProperty("os.version"));
-
-    ArgsParser aparser = new ArgsParser(args);
-    boolean headless = false;
-
-    if (aparser.contains("help") || aparser.contains("h"))
+    String val = System.getProperty("sys.install4jVersion");
+    if (val != null)
     {
-      showUsage();
-      System.exit(0);
+      System.out.println("Install4j version: " + val);
     }
-    if (aparser.contains("nodisplay") || aparser.contains("nogui")
-            || aparser.contains("headless"))
+    val = System.getProperty("installer_template_version");
+    if (val != null)
     {
-      System.setProperty("java.awt.headless", "true");
-      headless = true;
+      System.out.println("Install4j template version: " + val);
+    }
+    val = System.getProperty("launcher_version");
+    if (val != null)
+    {
+      System.out.println("Launcher version: " + val);
     }
+
+    // report Jalview version
+    Cache.getInstance().loadBuildProperties(true);
+
+    ArgsParser aparser = new ArgsParser(args);
+    boolean headless = false;
+
     String usrPropsFile = aparser.getValue("props");
     Cache.loadProperties(usrPropsFile); // must do this before
-    if (usrPropsFile != null)
+    boolean allowServices = true;
+    
+    if (isJS)
     {
-      System.out.println(
-              "CMD [-props " + usrPropsFile + "] executed successfully!");
+      j2sAppletID = Platform.getAppID(null);
+      Preferences.setAppletDefaults();
+      Cache.loadProperties(usrPropsFile); // again, because we
+      // might be changing defaults here?
+      appletResourcePath = (String) aparser.getAppletValue("resourcepath",
+              null, true);
     }
 
-    // anything else!
-
-    final String jabawsUrl = aparser.getValue("jabaws");
-    if (jabawsUrl != null)
+    else
+    /**
+     * Java only
+     * 
+     * @j2sIgnore
+     */
     {
-      try
+      if (usrPropsFile != null)
       {
-        Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
         System.out.println(
-                "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
-      } catch (MalformedURLException e)
+                "CMD [-props " + usrPropsFile + "] executed successfully!");
+      }
+      if (aparser.contains("help") || aparser.contains("h"))
       {
-        System.err.println(
-                "Invalid jabaws parameter: " + jabawsUrl + " ignored");
+        showUsage();
+        System.exit(0);
       }
-    }
+      // BH note: Only -nodisplay is official; others are deprecated?
+      if (aparser.contains("nodisplay") || aparser.contains("nogui")
+              || aparser.contains("headless")
+              || GraphicsEnvironment.isHeadless())
+      {
+        if (!isJS) {
+          // BH Definitely not a good idea in JavaScript; 
+          // probably should not be here for Java, either.  
+          System.setProperty("java.awt.headless", "true");
+        }
+        headless = true;
+      }
+      // anything else!
 
-    String defs = aparser.getValue("setprop");
+      final String jabawsUrl = aparser.getValue(ArgsParser.JABAWS);
+      allowServices = !("none".equals(jabawsUrl));
+      if (allowServices && jabawsUrl != null)
+      {
+        try
+        {
+          Jws2Discoverer.getInstance().setPreferredUrl(jabawsUrl);
+          System.out.println(
+                  "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
+        } catch (MalformedURLException e)
+        {
+          System.err.println(
+                  "Invalid jabaws parameter: " + jabawsUrl + " ignored");
+        }
+      }
+
+    }
+    String defs = aparser.getValue(ArgsParser.SETPROP);
     while (defs != null)
     {
       int p = defs.indexOf('=');
@@ -248,9 +385,10 @@ public class Jalview
       else
       {
         System.out.println("Executing setprop argument: " + defs);
-        // DISABLED FOR SECURITY REASONS
-        // TODO: add a property to allow properties to be overriden by cli args
-        // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
+        if (isJS)
+        {
+          Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
+        }
       }
       defs = aparser.getValue("setprop");
     }
@@ -268,562 +406,880 @@ public class Jalview
     {
       error.printStackTrace();
       System.out.println("\nEssential logging libraries not found."
-              + "\nUse: java -Djava.ext.dirs=$PATH_TO_LIB$ jalview.bin.Jalview");
+              + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
       System.exit(0);
     }
 
     desktop = null;
 
-    try
-    {
-      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
-    } catch (Exception ex)
-    {
-      System.err.println("Unexpected Look and Feel Exception");
-      ex.printStackTrace();
-    }
-    if (Platform.isAMac())
-    {
-
-      LookAndFeel lookAndFeel = ch.randelshofer.quaqua.QuaquaManager
-              .getLookAndFeel();
-      System.setProperty("com.apple.mrj.application.apple.menu.about.name",
-              "Jalview");
-      System.setProperty("apple.laf.useScreenMenuBar", "true");
-      if (lookAndFeel != null)
-      {
-        try
-        {
-          UIManager.setLookAndFeel(lookAndFeel);
-        } catch (Throwable e)
-        {
-          System.err.println(
-                  "Failed to set QuaQua look and feel: " + e.toString());
-        }
-      }
-      if (lookAndFeel == null || !(lookAndFeel.getClass()
-              .isAssignableFrom(UIManager.getLookAndFeel().getClass()))
-              || !UIManager.getLookAndFeel().getClass().toString()
-                      .toLowerCase().contains("quaqua"))
-      {
-        try
-        {
-          System.err.println(
-                  "Quaqua LaF not available on this plaform. Using VAqua(4).\nSee https://issues.jalview.org/browse/JAL-2976");
-          UIManager.setLookAndFeel("org.violetlib.aqua.AquaLookAndFeel");
-        } catch (Throwable e)
-        {
-          System.err.println(
-                  "Failed to reset look and feel: " + e.toString());
-        }
-      }
-    }
+    setLookAndFeel();
 
     /*
-     * configure 'full' SO model if preferences say to, 
-     * else use the default (SO Lite)
+     * configure 'full' SO model if preferences say to, else use the default (full SO)
+     * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
      */
-    if (Cache.getDefault("USE_FULL_SO", false))
+    boolean soDefault = !isJS;
+    if (Cache.getDefault("USE_FULL_SO", soDefault))
     {
       SequenceOntologyFactory.setInstance(new SequenceOntology());
     }
 
     if (!headless)
     {
-      desktop = new Desktop();
+      Desktop.nosplash = aparser.contains("nosplash");
+      desktop = Desktop.getInstance();
       desktop.setInBatchMode(true); // indicate we are starting up
+
+      try
+      {
+        JalviewTaskbar.setTaskbar(this);
+      } catch (Exception e)
+      {
+        Cache.log.info("Cannot set Taskbar");
+        Cache.log.error(e.getMessage());
+        // e.printStackTrace();
+      } catch (Throwable t)
+      {
+        Cache.log.info("Cannot set Taskbar");
+        Cache.log.error(t.getMessage());
+        // t.printStackTrace();
+      }
+      // set Proxy settings before all the internet calls
+      Cache.setProxyPropertiesFromPreferences();
+
       desktop.setVisible(true);
-      desktop.startServiceDiscovery();
-      if (!aparser.contains("nousagestats"))
+
+      if (isJS)
       {
-        startUsageStats(desktop);
+        Cache.setProperty("SHOW_JWS2_SERVICES", "false");
       }
-      else
+      if (allowServices && !aparser.contains("nowebservicediscovery"))
       {
-        System.err.println("CMD [-nousagestats] executed successfully!");
+        desktop.startServiceDiscovery();
       }
 
-      if (!aparser.contains("noquestionnaire"))
+      if (!isJS)
+      /**
+       * Java only
+       * 
+       * @j2sIgnore
+       */
       {
-        String url = aparser.getValue("questionnaire");
-        if (url != null)
+        if (!aparser.contains("nousagestats"))
         {
-          // Start the desktop questionnaire prompter with the specified
-          // questionnaire
-          Cache.log.debug("Starting questionnaire url at " + url);
-          desktop.checkForQuestionnaire(url);
-          System.out.println(
-                  "CMD questionnaire[-" + url + "] executed successfully!");
+          startUsageStats(desktop);
         }
         else
         {
-          if (Cache.getProperty("NOQUESTIONNAIRES") == null)
+          System.err.println("CMD [-nousagestats] executed successfully!");
+        }
+
+        if (!aparser.contains("noquestionnaire"))
+        {
+          String url = aparser.getValue("questionnaire");
+          if (url != null)
           {
             // Start the desktop questionnaire prompter with the specified
             // questionnaire
-            // String defurl =
-            // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
-            // //
-            String defurl = "http://www.jalview.org/cgi-bin/questionnaire.pl";
-            Cache.log.debug(
-                    "Starting questionnaire with default url: " + defurl);
-            desktop.checkForQuestionnaire(defurl);
+            Cache.log.debug("Starting questionnaire url at " + url);
+            desktop.checkForQuestionnaire(url);
+            System.out.println("CMD questionnaire[-" + url
+                    + "] executed successfully!");
+          }
+          else
+          {
+            if (Cache.getProperty("NOQUESTIONNAIRES") == null)
+            {
+              // Start the desktop questionnaire prompter with the specified
+              // questionnaire
+              // String defurl =
+              // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
+              // //
+              String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
+              Cache.log.debug(
+                      "Starting questionnaire with default url: " + defurl);
+              desktop.checkForQuestionnaire(defurl);
+            }
           }
         }
+        else
+        {
+          System.err
+                  .println("CMD [-noquestionnaire] executed successfully!");
+        }
+
+        if (!aparser.contains("nonews"))
+        {
+          desktop.checkForNews();
+        }
+
+        BioJsHTMLOutput.updateBioJS();
       }
-      else
-      {
-        System.err.println("CMD [-noquestionnaire] executed successfully!");
-      }
+    }
+    parseArguments(aparser, true);
+  }
+
+  /**
+   * Parse all command-line String[] arguments as well as all JavaScript-derived
+   * parameters from Info.
+   * 
+   * We allow for this method to be run from JavaScript. Basically allowing
+   * simple scripting.
+   * 
+   * @param aparser
+   * @param isStartup
+   */
+  public void parseArguments(ArgsParser aparser, boolean isStartup)
+  {
 
-      if (!aparser.contains("nonews"))
+    String groovyscript = null; // script to execute after all loading is
+    boolean isJS = Platform.isJS();
+    if (!isJS)
+    /** @j2sIgnore */
+    {
+      // Move any new getdown-launcher-new.jar into place over old
+      // getdown-launcher.jar
+      String appdirString = System.getProperty("getdownappdir");
+      if (appdirString != null && appdirString.length() > 0)
       {
-        desktop.checkForNews();
+        final File appdir = new File(appdirString);
+        new Thread()
+        {
+          @Override
+          public void run()
+          {
+            LaunchUtil.upgradeGetdown(
+                    new File(appdir, "getdown-launcher-old.jar"),
+                    new File(appdir, "getdown-launcher.jar"),
+                    new File(appdir, "getdown-launcher-new.jar"));
+          }
+        }.start();
       }
 
-      BioJsHTMLOutput.updateBioJS();
+      // completed one way or another
+      // extract groovy argument and execute if necessary
+      groovyscript = aparser.getValue("groovy", true);
     }
 
-    String file = null, data = null;
-    FileFormatI format = null;
-    DataSourceType protocol = null;
-    FileLoader fileLoader = new FileLoader(!headless);
-    Vector<String> getFeatures = null; // vector of das source nicknames to
-                                       // fetch
-    // features from
-    // loading is done.
-    String groovyscript = null; // script to execute after all loading is
-    // completed one way or another
-    // extract groovy argument and execute if necessary
-    groovyscript = aparser.getValue("groovy", true);
-    file = aparser.getValue("open", true);
+    String file = aparser.getValue("open", true);
 
-    if (file == null && desktop == null)
+    if (!isJS && file == null && desktop == null)
     {
       System.out.println("No files to open!");
       System.exit(1);
     }
-    String vamsasImport = aparser.getValue("vdoc");
-    String vamsasSession = aparser.getValue("vsess");
-    if (vamsasImport != null || vamsasSession != null)
+    setDisplayParameters(aparser);
+    
+    // time to open a file.
+    long progress = -1;
+    DataSourceType protocol = null;
+    FileLoader fileLoader = new FileLoader(!headless);
+    FileFormatI format = null;
+    // Finally, deal with the remaining input data.
+    AlignFrame af = null;
+
+    JalviewJSApp jsApp = (isJS ? new JalviewJSApp(this, aparser) : null);
+
+    if (file == null)
     {
-      if (desktop == null || headless)
+      if (isJS)
       {
-        System.out.println(
-                "Headless vamsas sessions not yet supported. Sorry.");
-        System.exit(1);
+        // JalviewJS allows sequence1 sequence2 ....
+        
       }
-      // if we have a file, start a new session and import it.
-      boolean inSession = false;
-      if (vamsasImport != null)
+      else if (!headless && Cache.getDefault("SHOW_STARTUP_FILE", true))
+      /**
+       * Java only
+       * 
+       * @j2sIgnore
+       */
       {
-        try
+
+        // We'll only open the default file if the desktop is visible.
+        // And the user
+        // ////////////////////
+
+        file = Cache.getDefault("STARTUP_FILE",
+                Cache.getDefault("www.jalview.org",
+                        "http://www.jalview.org")
+                        + "/examples/exampleFile_2_7.jar");
+        if (file.equals(
+                "http://www.jalview.org/examples/exampleFile_2_3.jar"))
         {
-          DataSourceType viprotocol = AppletFormatAdapter
-                  .checkProtocol(vamsasImport);
-          if (viprotocol == DataSourceType.FILE)
-          {
-            inSession = desktop.vamsasImport(new File(vamsasImport));
-          }
-          else if (viprotocol == DataSourceType.URL)
-          {
-            inSession = desktop.vamsasImport(new URL(vamsasImport));
-          }
+          // hardwire upgrade of the startup file
+          file.replace("_2_3.jar", "_2_7.jar");
+          // and remove the stale setting
+          Cache.removeProperty("STARTUP_FILE");
+        }
 
-        } catch (Exception e)
+        protocol = DataSourceType.FILE;
+
+        if (file.indexOf("http:") > -1)
         {
-          System.err.println("Exeption when importing " + vamsasImport
-                  + " as a vamsas document.");
-          e.printStackTrace();
+          protocol = DataSourceType.URL;
         }
-        if (!inSession)
+
+        if (file.endsWith(".jar"))
         {
-          System.err.println("Failed to import " + vamsasImport
-                  + " as a vamsas document.");
+          format = FileFormat.Jalview;
         }
         else
         {
-          System.out.println("Imported Successfully into new session "
-                  + desktop.getVamsasApplication().getCurrentSession());
+          try
+          {
+            format = new IdentifyFile().identify(file, protocol);
+          } catch (FileFormatException e)
+          {
+            // TODO what?
+          }
         }
+        af = fileLoader.LoadFileWaitTillLoaded(file, protocol, format);
+      }
+    }
+    else
+    {
+      if (!headless)
+      {
+        desktop.setProgressBar(
+                MessageManager
+                        .getString("status.processing_commandline_args"),
+                progress = System.currentTimeMillis());
       }
-      if (vamsasSession != null)
+      System.out.println("CMD [-open " + file + "] executed successfully!");
+
+      if (!Platform.isJS())
+      /**
+       * ignore in JavaScript -- can't just file existence - could load it?
+       * 
+       * @j2sIgnore
+       */
       {
-        if (vamsasImport != null)
+        if (!HttpUtils.startsWithHttpOrHttps(file))
         {
-          // close the newly imported session and import the Jalview specific
-          // remnants into the new session later on.
-          desktop.vamsasStop_actionPerformed(null);
+          if (!(new File(file)).exists())
+          {
+            System.out.println("Can't find " + file);
+            if (headless)
+            {
+              System.exit(1);
+            }
+          }
         }
-        // now join the new session
-        try
+      }
+
+      // JS Only argument to provide a format parameter to specify what format to use
+      String fileFormat = (isJS
+              ? (String) aparser.getAppletValue("format", null, true)
+              : null);
+      protocol = AppletFormatAdapter.checkProtocol(file);
+
+      try
+      {
+        format = (fileFormat != null
+                ? FileFormats.getInstance().forName(fileFormat)
+                : null);
+        if (format == null)
         {
-          if (desktop.joinVamsasSession(vamsasSession))
+          format = new IdentifyFile().identify(file, protocol);
+        }
+      } catch (FileFormatException e1)
+      {
+        // TODO ?
+      }
+
+      af = new FileLoader(!headless).LoadFileWaitTillLoaded(file, protocol,
+              format);
+      if (af == null)
+      {
+        System.out.println("jalview error - AlignFrame was not created");
+      }
+      else
+      {
+        
+        // JalviewLite interface for JavaScript allows second file open
+        String file2 = aparser.getValue(ArgsParser.OPEN2, true);
+        if (file2 != null)
+        {
+          protocol = AppletFormatAdapter.checkProtocol(file2);
+          try
           {
-            System.out.println(
-                    "Successfully joined vamsas session " + vamsasSession);
+            format = new IdentifyFile().identify(file2, protocol);
+          } catch (FileFormatException e1)
+          {
+            // TODO ?
+          }
+          AlignFrame af2 = new FileLoader(!headless)
+                  .LoadFileWaitTillLoaded(file2, protocol, format);
+          if (af2 == null)
+          {
+            System.out.println("error");
           }
           else
           {
-            System.err.println("WARNING: Failed to join vamsas session "
-                    + vamsasSession);
+            AlignViewport.openLinkedAlignmentAs(af,
+                    af.getViewport().getAlignment(),
+                    af2.getViewport().getAlignment(), "",
+                    AlignViewport.SPLIT_FRAME);
+            System.out.println(
+                    "CMD [-open2 " + file2 + "] executed successfully!");
           }
-        } catch (Exception e)
+        }
+        // af is loaded - so set it as current frame
+        setCurrentAlignFrame(af);
+
+        setFrameDependentProperties(aparser, af);
+        
+        if (isJS)
         {
-          System.err.println(
-                  "ERROR: Failed to join vamsas session " + vamsasSession);
-          e.printStackTrace();
+          jsApp.initFromParams(af);
         }
-        if (vamsasImport != null)
+        else
+        /**
+         * Java only
+         * 
+         * @j2sIgnore
+         */
         {
-          // the Jalview specific remnants can now be imported into the new
-          // session at the user's leisure.
-          Cache.log.info(
-                  "Skipping Push for import of data into existing vamsas session."); // TODO:
-          // enable
-          // this
-          // when
-          // debugged
-          // desktop.getVamsasApplication().push_update();
+          if (groovyscript != null)
+          {
+            // Execute the groovy script after we've done all the rendering
+            // stuff
+            // and before any images or figures are generated.
+            System.out.println("Executing script " + groovyscript);
+            executeGroovyScript(groovyscript, af);
+            System.out.println("CMD groovy[" + groovyscript
+                    + "] executed successfully!");
+            groovyscript = null;
+          }
+        }
+        if (!isJS || !isStartup) {
+          createOutputFiles(aparser, format);
         }
       }
+      if (headless)
+      {
+        af.getViewport().getCalcManager().shutdown();
+      }
+    }
+    // extract groovy arguments before anything else.
+    // Once all other stuff is done, execute any groovy scripts (in order)
+    if (!isJS && groovyscript != null)
+    {
+      if (Cache.groovyJarsPresent())
+      {
+        // TODO: DECIDE IF THIS SECOND PASS AT GROOVY EXECUTION IS STILL REQUIRED !!
+        System.out.println("Executing script " + groovyscript);
+        executeGroovyScript(groovyscript, af);
+        System.out.println("CMD groovy[" + groovyscript
+                    + "] executed successfully!");
+
+      }
+      else
+      {
+        System.err.println(
+                "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
+                        + groovyscript);
+      }
+    }
+
+    // and finally, turn off batch mode indicator - if the desktop still exists
+    if (desktop != null)
+    {
+      if (progress != -1)
+      {
+        desktop.setProgressBar(null, progress);
+      }
+      desktop.setInBatchMode(false);
+    }
+    
+    if (jsApp != null) {
+      jsApp.callInitCallback();
+    }
+  }
+  
+  /**
+   * Set general display parameters irrespective of file loading or headlessness.
+   * 
+   * @param aparser
+   */
+  private void setDisplayParameters(ArgsParser aparser)
+  {
+    if (aparser.contains(ArgsParser.NOMENUBAR))
+    {
+      noMenuBar = true;
+      System.out.println("CMD [nomenu] executed successfully!");
+    }
+
+    if (aparser.contains(ArgsParser.NOSTATUS))
+    {
+      noStatus = true;
+      System.out.println("CMD [nostatus] executed successfully!");
+    }
+
+    if (aparser.contains(ArgsParser.NOANNOTATION)
+            || aparser.contains(ArgsParser.NOANNOTATION2))
+    {
+      noAnnotation = true;
+      System.out.println("CMD no-annotation executed successfully!");
+    }
+    if (aparser.contains(ArgsParser.NOCALCULATION))
+    {
+      noCalculation = true;
+      System.out.println("CMD [nocalculation] executed successfully!");
+    }
+  }
+
+
+  private void setFrameDependentProperties(ArgsParser aparser,
+          AlignFrame af)
+  {
+    String data = aparser.getValue(ArgsParser.COLOUR, true);
+    if (data != null)
+    {
+      data.replaceAll("%20", " ");
+
+      ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
+              af.getViewport(), af.getViewport().getAlignment(), data);
+
+      if (cs != null)
+      {
+        System.out.println(
+                "CMD [-color " + data + "] executed successfully!");
+      }
+      af.changeColour(cs);
+    }
+
+    // Must maintain ability to use the groups flag
+    data = aparser.getValue(ArgsParser.GROUPS, true);
+    if (data != null)
+    {
+      af.parseFeaturesFile(data,
+              AppletFormatAdapter.checkProtocol(data));
+      // System.out.println("Added " + data);
+      System.out.println(
+              "CMD groups[-" + data + "]  executed successfully!");
+    }
+    data = aparser.getValue(ArgsParser.FEATURES, true);
+    if (data != null)
+    {
+      af.parseFeaturesFile(data,
+              AppletFormatAdapter.checkProtocol(data));
+      // System.out.println("Added " + data);
+      System.out.println(
+              "CMD [-features " + data + "]  executed successfully!");
     }
-    long progress = -1;
-    // Finally, deal with the remaining input data.
-    if (file != null)
+    data = aparser.getValue(ArgsParser.ANNOTATIONS, true);
+    if (data != null)
     {
-      if (!headless)
+      af.loadJalviewDataFile(data, null, null, null);
+      // System.out.println("Added " + data);
+      System.out.println(
+              "CMD [-annotations " + data + "] executed successfully!");
+    }
+
+    // JavaScript feature
+
+    if (aparser.contains(ArgsParser.SHOWOVERVIEW))
+    {
+      af.overviewMenuItem_actionPerformed(null);
+      System.out.println("CMD [showoverview] executed successfully!");
+    }
+
+    // set or clear the sortbytree flag.
+    if (aparser.contains(ArgsParser.SORTBYTREE))
+    {
+      af.getViewport().setSortByTree(true);
+      if (af.getViewport().getSortByTree())
       {
-        desktop.setProgressBar(
-                MessageManager
-                        .getString("status.processing_commandline_args"),
-                progress = System.currentTimeMillis());
+        System.out.println("CMD [-sortbytree] executed successfully!");
       }
-      System.out.println("CMD [-open " + file + "] executed successfully!");
+    }
 
-      if (!file.startsWith("http://"))
+    boolean doUpdateAnnotation = false;
+    /**
+     * we do this earlier in JalviewJS because of a complication with
+     * SHOWOVERVIEW
+     * 
+     * For now, just fixing this in JalviewJS.
+     *
+     * 
+     * @j2sIgnore
+     * 
+     */
+    {
+      if (noAnnotation)
       {
-        if (!(new File(file)).exists())
+        af.getViewport().setShowAnnotation(false);
+        if (!af.getViewport().isShowAnnotation())
         {
-          System.out.println("Can't find " + file);
-          if (headless)
-          {
-            System.exit(1);
-          }
+          doUpdateAnnotation = true;
         }
       }
+    }
 
-      protocol = AppletFormatAdapter.checkProtocol(file);
-
-      try
-      {
-        format = new IdentifyFile().identify(file, protocol);
-      } catch (FileFormatException e1)
+    if (aparser.contains(ArgsParser.NOSORTBYTREE))
+    {
+      af.getViewport().setSortByTree(false);
+      if (!af.getViewport().getSortByTree())
       {
-        // TODO ?
+        doUpdateAnnotation = true;
+        System.out
+                .println("CMD [-nosortbytree] executed successfully!");
       }
+    }
+    if (doUpdateAnnotation)
+    { // BH 2019.07.24
+      af.setMenusForViewport();
+      af.alignPanel.updateLayout();
+    }
 
-      AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
-              format);
-      if (af == null)
+    data = aparser.getValue(ArgsParser.TREE, true);
+    if (data != null)
+    {
+      try
       {
-        System.out.println("error");
-      }
-      else
+        NewickFile nf = new NewickFile(data,
+                AppletFormatAdapter.checkProtocol(data));
+        af.getViewport()
+                .setCurrentTree(af.showNewickTree(nf, data).getTree());
+        System.out.println(
+                "CMD [-tree " + data + "] executed successfully!");
+      } catch (IOException ex)
       {
-        setCurrentAlignFrame(af);
-        data = aparser.getValue("colour", true);
-        if (data != null)
-        {
-          data.replaceAll("%20", " ");
-
-          ColourSchemeI cs = ColourSchemeProperty
-                  .getColourScheme(af.getViewport().getAlignment(), data);
-
-          if (cs != null)
-          {
-            System.out.println(
-                    "CMD [-color " + data + "] executed successfully!");
-          }
-          af.changeColour(cs);
-        }
+        System.err.println("Couldn't add tree " + data);
+        ex.printStackTrace(System.err);
+      }
+    }
+    // TODO - load PDB structure(s) to alignment JAL-629
+    // (associate with identical sequence in alignment, or a specified
+    // sequence)
 
-        // Must maintain ability to use the groups flag
-        data = aparser.getValue("groups", true);
-        if (data != null)
-        {
-          af.parseFeaturesFile(data,
-                  AppletFormatAdapter.checkProtocol(data));
-          // System.out.println("Added " + data);
-          System.out.println(
-                  "CMD groups[-" + data + "]  executed successfully!");
-        }
-        data = aparser.getValue("features", true);
-        if (data != null)
-        {
-          af.parseFeaturesFile(data,
-                  AppletFormatAdapter.checkProtocol(data));
-          // System.out.println("Added " + data);
-          System.out.println(
-                  "CMD [-features " + data + "]  executed successfully!");
-        }
+  }
 
-        data = aparser.getValue("annotations", true);
-        if (data != null)
-        {
-          af.loadJalviewDataFile(data, null, null, null);
-          // System.out.println("Added " + data);
-          System.out.println(
-                  "CMD [-annotations " + data + "] executed successfully!");
-        }
-        // set or clear the sortbytree flag.
-        if (aparser.contains("sortbytree"))
+  /**
+   * Writes an output file for each format (if any) specified in the
+   * command-line arguments. Supported formats are currently
+   * <ul>
+   * <li>png</li>
+   * <li>svg</li>
+   * <li>html</li>
+   * <li>biojsmsa</li>
+   * <li>imgMap</li>
+   * <li>eps</li>
+   * </ul>
+   * A format parameter should be followed by a parameter specifying the output
+   * file name. {@code imgMap} parameters should follow those for the
+   * corresponding alignment image output.
+   * 
+   * @param aparser
+   * @param format
+   */
+  private void createOutputFiles(ArgsParser aparser, FileFormatI format)
+  {
+    // logic essentially the same as 2.11.2/2.11.3 but uses a switch instead
+    AlignFrame af = currentAlignFrame;
+    while (aparser.getSize() >= 2)
+    {
+      String outputFormat = aparser.nextValue();
+      File imageFile;
+      String fname;
+      switch (outputFormat.toLowerCase(Locale.ROOT))
+      {
+      case "png":
+        imageFile = new File(aparser.nextValue());
+        af.createPNG(imageFile);
+        System.out.println(
+                "Creating PNG image: " + imageFile.getAbsolutePath());
+        continue;
+      case "svg":
+        imageFile = new File(aparser.nextValue());
+        af.createSVG(imageFile);
+        System.out.println(
+                "Creating SVG image: " + imageFile.getAbsolutePath());
+        continue;
+      case "eps":
+        imageFile = new File(aparser.nextValue());
+        System.out.println(
+                "Creating EPS file: " + imageFile.getAbsolutePath());
+        af.createEPS(imageFile);
+        continue;
+      case "biojsmsa":
+        fname = new File(aparser.nextValue()).getAbsolutePath();
+        try
         {
-          af.getViewport().setSortByTree(true);
-          if (af.getViewport().getSortByTree())
-          {
-            System.out.println("CMD [-sortbytree] executed successfully!");
-          }
-        }
-        if (aparser.contains("no-annotation"))
+          BioJsHTMLOutput.refreshVersionInfo(
+                  BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
+        } catch (URISyntaxException e)
         {
-          af.getViewport().setShowAnnotation(false);
-          if (!af.getViewport().isShowAnnotation())
-          {
-            System.out.println("CMD no-annotation executed successfully!");
-          }
+          e.printStackTrace();
         }
-        if (aparser.contains("nosortbytree"))
+        BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
+        bjs.exportHTML(fname);
+        System.out.println("Creating BioJS MSA Viwer HTML file: " + fname);
+        continue;
+      case "html":
+        fname = new File(aparser.nextValue()).getAbsolutePath();
+        HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
+        htmlSVG.exportHTML(fname);
+        System.out.println("Creating HTML image: " + fname);
+        continue;
+      case "imgmap":
+        imageFile = new File(aparser.nextValue());
+        af.alignPanel.makePNGImageMap(imageFile, "unnamed.png");
+        System.out.println(
+                "Creating image map: " + imageFile.getAbsolutePath());
+        continue;
+      default:
+        // fall through - try to parse as an alignment data export format
+        FileFormatI outFormat = null;
+        try
         {
-          af.getViewport().setSortByTree(false);
-          if (!af.getViewport().getSortByTree())
-          {
-            System.out
-                    .println("CMD [-nosortbytree] executed successfully!");
-          }
-        }
-        data = aparser.getValue("tree", true);
-        if (data != null)
+          outFormat = FileFormats.getInstance().forName(outputFormat);
+        } catch (Exception formatP)
         {
-          try
-          {
-            System.out.println(
-                    "CMD [-tree " + data + "] executed successfully!");
-            NewickFile nf = new NewickFile(data,
-                    AppletFormatAdapter.checkProtocol(data));
-            af.getViewport()
-                    .setCurrentTree(af.showNewickTree(nf, data).getTree());
-          } catch (IOException ex)
-          {
-            System.err.println("Couldn't add tree " + data);
-            ex.printStackTrace(System.err);
-          }
         }
-        // TODO - load PDB structure(s) to alignment JAL-629
-        // (associate with identical sequence in alignment, or a specified
-        // sequence)
-
-        getFeatures = checkDasArguments(aparser);
-        if (af != null && getFeatures != null)
+        if (outFormat == null)
         {
-          FeatureFetcher ff = startFeatureFetching(getFeatures);
-          if (ff != null)
-          {
-            while (!ff.allFinished() || af.operationInProgress())
-            {
-              // wait around until fetching is finished.
-              try
-              {
-                Thread.sleep(100);
-              } catch (Exception e)
-              {
-
-              }
-            }
-          }
-          getFeatures = null; // have retrieved features - forget them now.
+          System.out.println("Couldn't parse " + outputFormat
+                  + " as a valid Jalview format string.");
+          continue;
         }
-        if (groovyscript != null)
+        if (!outFormat.isWritable())
         {
-          // Execute the groovy script after we've done all the rendering stuff
-          // and before any images or figures are generated.
-          System.out.println("Executing script " + groovyscript);
-          executeGroovyScript(groovyscript, af);
-          System.out.println("CMD groovy[" + groovyscript
-                  + "] executed successfully!");
-          groovyscript = null;
+          System.out.println(
+                  "This version of Jalview does not support alignment export as "
+                          + outputFormat);
+          continue;
         }
-        String imageName = "unnamed.png";
-        while (aparser.getSize() > 1)
+        // record file as it was passed to Jalview so it is recognisable to the CLI
+        // caller
+        String file;
+        fname = new File(file = aparser.nextValue()).getAbsolutePath();
+        // JBPNote - yuck - really wish we did have a bean returned from this which gave
+        // success/fail like before !
+        af.saveAlignment(fname, outFormat);
+        if (!af.isSaveAlignmentSuccessful())
         {
-          String outputFormat = aparser.nextValue();
-          file = aparser.nextValue();
-
-          if (outputFormat.equalsIgnoreCase("png"))
-          {
-            af.createPNG(new File(file));
-            imageName = (new File(file)).getName();
-            System.out.println("Creating PNG image: " + file);
-            continue;
-          }
-          else if (outputFormat.equalsIgnoreCase("svg"))
-          {
-            File imageFile = new File(file);
-            imageName = imageFile.getName();
-            af.createSVG(imageFile);
-            System.out.println("Creating SVG image: " + file);
-            continue;
-          }
-          else if (outputFormat.equalsIgnoreCase("html"))
-          {
-            File imageFile = new File(file);
-            imageName = imageFile.getName();
-            HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
-            htmlSVG.exportHTML(file);
-
-            System.out.println("Creating HTML image: " + file);
-            continue;
-          }
-          else if (outputFormat.equalsIgnoreCase("biojsmsa"))
-          {
-            if (file == null)
-            {
-              System.err.println("The output html file must not be null");
-              return;
-            }
-            try
-            {
-              BioJsHTMLOutput.refreshVersionInfo(
-                      BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
-            } catch (URISyntaxException e)
-            {
-              e.printStackTrace();
-            }
-            BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
-            bjs.exportHTML(file);
-            System.out
-                    .println("Creating BioJS MSA Viwer HTML file: " + file);
-            continue;
-          }
-          else if (outputFormat.equalsIgnoreCase("imgMap"))
-          {
-            af.createImageMap(new File(file), imageName);
-            System.out.println("Creating image map: " + file);
-            continue;
-          }
-          else if (outputFormat.equalsIgnoreCase("eps"))
-          {
-            File outputFile = new File(file);
-            System.out.println(
-                    "Creating EPS file: " + outputFile.getAbsolutePath());
-            af.createEPS(outputFile);
-            continue;
-          }
-
-          if (af.saveAlignment(file, format))
-          {
-            System.out.println("Written alignment in " + format
-                    + " format to " + file);
-          }
-          else
-          {
-            System.out.println("Error writing file " + file + " in "
-                    + format + " format!!");
-          }
-
+          System.out.println("Written alignment in " + outputFormat
+                  + " format to " + file);
+          continue;
         }
-
-        while (aparser.getSize() > 0)
+        else
         {
-          System.out.println("Unknown arg: " + aparser.nextValue());
+          System.out.println("Error writing file " + file + " in "
+                  + outputFormat + " format!!");
         }
       }
     }
-    AlignFrame startUpAlframe = null;
-    // We'll only open the default file if the desktop is visible.
-    // And the user
-    // ////////////////////
+    // ??? Should report - 'ignoring' extra args here...
+    while (aparser.getSize() > 0)
+    {
+      System.out.println("Ignoring extra argument: " + aparser.nextValue());
+    }
+  }
 
-    if (!headless && file == null && vamsasImport == null
-            && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true))
+  private static void setLookAndFeel()
+  {
+    // property laf = "crossplatform", "system", "gtk", "metal", "nimbus" or
+    // "mac"
+    // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
+    // try Quaqua/Vaqua.
+    String lafProp = System.getProperty("laf");
+    String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
+    String laf = "none";
+    if (lafProp != null)
     {
-      file = jalview.bin.Cache.getDefault("STARTUP_FILE",
-              jalview.bin.Cache.getDefault("www.jalview.org",
-                      "http://www.jalview.org")
-                      + "/examples/exampleFile_2_7.jar");
-      if (file.equals(
-              "http://www.jalview.org/examples/exampleFile_2_3.jar"))
+      laf = lafProp;
+    }
+    else if (lafSetting != null)
+    {
+      laf = lafSetting;
+    }
+    boolean lafSet = false;
+    switch (laf)
+    {
+    case "crossplatform":
+      lafSet = setCrossPlatformLookAndFeel();
+      if (!lafSet)
       {
-        // hardwire upgrade of the startup file
-        file.replace("_2_3.jar", "_2_7.jar");
-        // and remove the stale setting
-        jalview.bin.Cache.removeProperty("STARTUP_FILE");
+        Cache.log.error("Could not set requested laf=" + laf);
       }
-
-      protocol = DataSourceType.FILE;
-
-      if (file.indexOf("http:") > -1)
+      break;
+    case "system":
+      lafSet = setSystemLookAndFeel();
+      if (!lafSet)
       {
-        protocol = DataSourceType.URL;
+        Cache.log.error("Could not set requested laf=" + laf);
       }
-
-      if (file.endsWith(".jar"))
+      break;
+    case "gtk":
+      lafSet = setGtkLookAndFeel();
+      if (!lafSet)
       {
-        format = FileFormat.Jalview;
+        Cache.log.error("Could not set requested laf=" + laf);
       }
-      else
+      break;
+    case "metal":
+      lafSet = setMetalLookAndFeel();
+      if (!lafSet)
       {
-        try
-        {
-          format = new IdentifyFile().identify(file, protocol);
-        } catch (FileFormatException e)
-        {
-          // TODO what?
-        }
+        Cache.log.error("Could not set requested laf=" + laf);
       }
-
-      startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
-              format);
-      getFeatures = checkDasArguments(aparser);
-      // extract groovy arguments before anything else.
-    }
-    // If the user has specified features to be retrieved,
-    // or a groovy script to be executed, do them if they
-    // haven't been done already
-    // fetch features for the default alignment
-    if (getFeatures != null)
-    {
-      if (startUpAlframe != null)
+      break;
+    case "nimbus":
+      lafSet = setNimbusLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "quaqua":
+      lafSet = setQuaquaLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "vaqua":
+      lafSet = setVaquaLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "mac":
+      lafSet = setMacLookAndFeel();
+      if (!lafSet)
       {
-        startFeatureFetching(getFeatures);
+        Cache.log.error("Could not set requested laf=" + laf);
       }
+      break;
+    case "none":
+      break;
+    default:
+      Cache.log.error("Requested laf=" + laf + " not implemented");
     }
-    // Once all other stuff is done, execute any groovy scripts (in order)
-    if (groovyscript != null)
+    if (!lafSet)
     {
-      if (Cache.groovyJarsPresent())
+      setSystemLookAndFeel();
+      if (Platform.isLinux())
       {
-        System.out.println("Executing script " + groovyscript);
-        executeGroovyScript(groovyscript, startUpAlframe);
+        setMetalLookAndFeel();
       }
-      else
+      if (Platform.isMac())
       {
-        System.err.println(
-                "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
-                        + groovyscript);
+        setMacLookAndFeel();
       }
     }
-    // and finally, turn off batch mode indicator - if the desktop still exists
-    if (desktop != null)
+  }
+
+  private static boolean setCrossPlatformLookAndFeel()
+  {
+    boolean set = false;
+    try
     {
-      if (progress != -1)
+      UIManager.setLookAndFeel(
+              UIManager.getCrossPlatformLookAndFeelClassName());
+      set = true;
+    } catch (Exception ex)
+    {
+      Cache.log.error("Unexpected Look and Feel Exception");
+      Cache.log.error(ex.getMessage());
+      Cache.log.debug(Cache.getStackTraceString(ex));
+    }
+    return set;
+  }
+
+  private static boolean setSystemLookAndFeel()
+  {
+    boolean set = false;
+    try
+    {
+      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+      set = true;
+    } catch (Exception ex)
+    {
+      Cache.log.error("Unexpected Look and Feel Exception");
+      Cache.log.error(ex.getMessage());
+      Cache.log.debug(Cache.getStackTraceString(ex));
+    }
+    return set;
+  }
+
+  private static boolean setSpecificLookAndFeel(String name,
+          String className, boolean nameStartsWith)
+  {
+    boolean set = false;
+    try
+    {
+      for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
       {
-        desktop.setProgressBar(null, progress);
+        if (info.getName() != null && nameStartsWith
+                ? info.getName().toLowerCase(Locale.ROOT)
+                        .startsWith(name.toLowerCase(Locale.ROOT))
+                : info.getName().toLowerCase(Locale.ROOT).equals(name.toLowerCase(Locale.ROOT)))
+        {
+          className = info.getClassName();
+          break;
+        }
       }
-      desktop.setInBatchMode(false);
+      UIManager.setLookAndFeel(className);
+      set = true;
+    } catch (Exception ex)
+    {
+      Cache.log.error("Unexpected Look and Feel Exception");
+      Cache.log.error(ex.getMessage());
+      Cache.log.debug(Cache.getStackTraceString(ex));
     }
+    return set;
+  }
+
+  private static boolean setGtkLookAndFeel()
+  {
+    return setSpecificLookAndFeel("gtk",
+            "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
+  }
+
+  private static boolean setMetalLookAndFeel()
+  {
+    return setSpecificLookAndFeel("metal",
+            "javax.swing.plaf.metal.MetalLookAndFeel", false);
+  }
+
+  private static boolean setNimbusLookAndFeel()
+  {
+    return setSpecificLookAndFeel("nimbus",
+            "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
+  }
+
+  private static boolean setQuaquaLookAndFeel()
+  {
+    return setSpecificLookAndFeel("quaqua",
+            ch.randelshofer.quaqua.QuaquaManager.getLookAndFeel().getClass()
+                    .getName(),
+            false);
   }
 
+  private static boolean setVaquaLookAndFeel()
+  {
+    return setSpecificLookAndFeel("vaqua",
+            "org.violetlib.aqua.AquaLookAndFeel", false);
+  }
+
+  private static boolean setMacLookAndFeel()
+  {
+    boolean set = false;
+    System.setProperty("com.apple.mrj.application.apple.menu.about.name",
+            ChannelProperties.getProperty("app_name"));
+    System.setProperty("apple.laf.useScreenMenuBar", "true");
+    set = setQuaquaLookAndFeel();
+    if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
+            .toLowerCase(Locale.ROOT).contains("quaqua"))
+    {
+      set = setVaquaLookAndFeel();
+    }
+    return set;
+  }
   private static void showUsage()
   {
     System.out.println(
@@ -860,16 +1316,11 @@ public class Jalview
                     // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
                     // passed in correctly)"
                     + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
-                    + "-dasserver nickname=URL\tAdd and enable a das server with given nickname\n\t\t\t(alphanumeric or underscores only) for retrieval of features for all alignments.\n"
-                    + "\t\t\tSources that also support the sequence command may be specified by prepending the URL with sequence:\n"
-                    + "\t\t\t e.g. sequence:http://localdas.somewhere.org/das/source)\n"
                     + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
-                    // +
-                    // "-vdoc vamsas-document\tImport vamsas document into new
-                    // session or join existing session with same URN\n"
-                    // + "-vses vamsas-session\tJoin session with given URN\n"
                     + "-groovy FILE\tExecute groovy script in FILE, after all other arguments have been processed (if FILE is the text 'STDIN' then the file will be read from STDIN)\n"
-                    + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
+                    + "-jvmmempc=PERCENT\tOnly available with standalone executable jar or jalview.bin.Launcher. Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected. See https://www.jalview.org/help/html/memory.html for more details.\n"
+                    + "-jvmmemmax=MAXMEMORY\tOnly available with standalone executable jar or jalview.bin.Launcher. Limit maximum heap size (memory) to MAXMEMORY. MAXMEMORY can be specified in bytes, kilobytes(k), megabytes(m), gigabytes(g) or if you're lucky enough, terabytes(t). This defaults to 32g if total physical memory can be detected, or to 8g if total physical memory cannot be detected. See https://www.jalview.org/help/html/memory.html for more details.\n"
+                    + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
   }
 
   private static void startUsageStats(final Desktop desktop)
@@ -877,7 +1328,7 @@ public class Jalview
     /**
      * start a User Config prompt asking if we can log usage statistics.
      */
-    PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
+    PromptUserConfig prompter = new PromptUserConfig(Desktop.getDesktopPane(),
             "USAGESTATS", "Jalview Usage Statistics",
             "Do you want to help make Jalview better by enabling "
                     + "the collection of usage statistics with Google Analytics ?"
@@ -997,7 +1448,7 @@ public class Jalview
     }
     try
     {
-      Map<String, Object> vbinding = new HashMap<>();
+      Map<String, java.lang.Object> vbinding = new HashMap<>();
       vbinding.put("Jalview", this);
       if (af != null)
       {
@@ -1021,94 +1472,6 @@ public class Jalview
     }
   }
 
-  /**
-   * Check commandline for any das server definitions or any fetchfrom switches
-   * 
-   * @return vector of DAS source nicknames to retrieve from
-   */
-  private static Vector<String> checkDasArguments(ArgsParser aparser)
-  {
-    Vector<String> source = null;
-    String data;
-    String locsources = Cache.getProperty(Cache.DAS_LOCAL_SOURCE);
-    while ((data = aparser.getValue("dasserver", true)) != null)
-    {
-      String nickname = null;
-      String url = null;
-      int pos = data.indexOf('=');
-      // determine capabilities
-      if (pos > 0)
-      {
-        nickname = data.substring(0, pos);
-      }
-      url = data.substring(pos + 1);
-      if (url != null && (url.startsWith("http:")
-              || url.startsWith("sequence:http:")))
-      {
-        if (nickname == null)
-        {
-          nickname = url;
-        }
-        if (locsources == null)
-        {
-          locsources = "";
-        }
-        else
-        {
-          locsources += "\t";
-        }
-        locsources = locsources + nickname + "|" + url;
-        System.err.println(
-                "NOTE! dasserver parameter not yet really supported (got args of "
-                        + nickname + "|" + url);
-        if (source == null)
-        {
-          source = new Vector<>();
-        }
-        source.addElement(nickname);
-      }
-      System.out.println(
-              "CMD [-dasserver " + data + "] executed successfully!");
-    } // loop until no more server entries are found.
-    if (locsources != null && locsources.indexOf('|') > -1)
-    {
-      Cache.log.debug("Setting local source list in properties file to:\n"
-              + locsources);
-      Cache.setProperty(Cache.DAS_LOCAL_SOURCE, locsources);
-    }
-    while ((data = aparser.getValue("fetchfrom", true)) != null)
-    {
-      System.out.println("adding source '" + data + "'");
-      if (source == null)
-      {
-        source = new Vector<>();
-      }
-      source.addElement(data);
-    }
-    return source;
-  }
-
-  /**
-   * start a feature fetcher for every alignment frame
-   * 
-   * @param dasSources
-   */
-  private FeatureFetcher startFeatureFetching(
-          final Vector<String> dasSources)
-  {
-    FeatureFetcher ff = new FeatureFetcher();
-    AlignFrame afs[] = Desktop.getAlignFrames();
-    if (afs == null || afs.length == 0)
-    {
-      return null;
-    }
-    for (int i = 0; i < afs.length; i++)
-    {
-      ff.addFetcher(afs[i], dasSources);
-    }
-    return ff;
-  }
-
   public static boolean isHeadlessMode()
   {
     String isheadless = System.getProperty("java.awt.headless");
@@ -1127,8 +1490,8 @@ public class Jalview
   }
 
   /**
-   * Quit method delegates to Desktop.quit - unless running in headless mode
-   * when it just ends the JVM
+   * Quit method delegates to Desktop.quit - unless running in headless mode when
+   * it just ends the JVM
    */
   public void quit()
   {
@@ -1144,11 +1507,30 @@ public class Jalview
 
   public static AlignFrame getCurrentAlignFrame()
   {
-    return Jalview.currentAlignFrame;
+    return Jalview.getInstance().currentAlignFrame;
   }
 
   public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
   {
-    Jalview.currentAlignFrame = currentAlignFrame;
+    Jalview.getInstance().currentAlignFrame = currentAlignFrame;
+  }
+  
+  public void notifyWorker(AlignCalcWorkerI worker, String status)
+  {
+    // System.out.println("Jalview worker " + worker.getClass().getSimpleName()
+    // + " " + status);
+  }
+
+
+  private static boolean isInteractive = true;
+
+  public static boolean isInteractive()
+  {
+    return isInteractive;
+  }
+
+  public static void setInteractive(boolean tf)
+  {
+    isInteractive = tf;
   }
 }