JAL-3446 JavaScript interface
[jalview.git] / src / jalview / bin / Jalview.java
index ca2a584..4819d7a 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.io.BufferedReader;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -68,6 +47,33 @@ import com.threerings.getdown.util.LaunchUtil;
 
 import groovy.lang.Binding;
 import groovy.util.GroovyScriptEngine;
+import jalview.api.AlignCalcWorkerI;
+import jalview.api.JalviewJSApp;
+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.MessageManager;
+import jalview.util.Platform;
+import jalview.ws.jws2.Jws2Discoverer;
+//import netscape.javascript.JSObject;
 
 /**
  * Main class for Jalview Application <br>
@@ -84,35 +90,92 @@ import groovy.util.GroovyScriptEngine;
  * @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()
+  {
+  }
+
+  private boolean headless;
 
   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()) {
+        Platform.getURLCommandArguments();
+    } else /** @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()
+        {
+        }
+      });
+    }
   }
 
   /**
@@ -174,21 +237,21 @@ 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>
+   *          open <em>filename</em>
    */
   public static void main(String[] args)
   {
-    instance = new Jalview();
-    instance.doMain(args);
+    if (doPlatformLogging)
+    {
+      Platform.startJavaLogging();
+    }
+    getInstance().doMain(args);
   }
 
   /**
@@ -196,55 +259,100 @@ public class Jalview
    */
   void doMain(String[] args)
   {
-    System.setSecurityManager(null);
+
+    boolean isJS = Platform.isJS();
+    if (!isJS)
+    {
+      System.setSecurityManager(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"));
-    // report Jalview version
-    Cache.loadBuildProperties(true);
-
-    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);
     }
-    String usrPropsFile = aparser.getValue("props");
-    Cache.loadProperties(usrPropsFile); // must do this before
-    if (usrPropsFile != null)
+    val = System.getProperty("launcher_version");
+    if (val != null)
     {
-      System.out.println(
-              "CMD [-props " + usrPropsFile + "] executed successfully!");
+      System.out.println("Launcher version: " + val);
     }
 
-    // anything else!
+    // report Jalview version
+    Cache.getInstance().loadBuildProperties(true);
+
+    ArgsParser aparser = new ArgsParser(args);
+    headless = false;
+
+    String usrPropsFile = aparser.getValue("props");
+
+    Cache.loadProperties(usrPropsFile); // must do this before
 
-    final String jabawsUrl = aparser.getValue("jabaws");
-    if (jabawsUrl != null)
+    if (isJS)
     {
-      try
+      j2sAppletID = Platform.getAppID(null);
+      Preferences.setAppletDefaults();
+      Cache.loadProperties(usrPropsFile); // again, because we
+      // might be changing defaults here?
+      appletResourcePath = (String) aparser.getAppletValue("resourcepath",
+              null, true);
+    }
+    else
+    /**
+     * Java only
+     * 
+     * @j2sIgnore
+     */
+    {
+
+      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);
+      }
+      // ?>>
+      if (aparser.contains("nodisplay") || aparser.contains("nogui")
+              || aparser.contains("headless"))
+      {
+        System.setProperty("java.awt.headless", "true");
+        headless = true;
+      }
+      // <<?
+
+      // anything else!
+
+      final String jabawsUrl = aparser.getValue(ArgsParser.JABAWS);
+      if (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("setprop");
+    }
+    String defs = aparser.getValue(ArgsParser.SETPROP);
     while (defs != null)
     {
       int p = defs.indexOf('=');
@@ -255,9 +363,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");
     }
@@ -281,168 +390,200 @@ public class Jalview
 
     desktop = null;
 
-    try
-    {
-      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
-    } catch (Exception ex)
+    if (!isJS)
+    /** @j2sIgnore */
     {
-      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
       {
-        try
-        {
-          UIManager.setLookAndFeel(lookAndFeel);
-        } catch (Throwable e)
-        {
-          System.err.println(
-                  "Failed to set QuaQua look and feel: " + e.toString());
-        }
+        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+      } catch (Exception ex)
+      {
+        System.err.println("Unexpected Look and Feel Exception");
+        ex.printStackTrace();
       }
-      if (lookAndFeel == null
-              || !(lookAndFeel.getClass().isAssignableFrom(
-                      UIManager.getLookAndFeel().getClass()))
-              || !UIManager.getLookAndFeel().getClass().toString()
-                      .toLowerCase().contains("quaqua"))
+      if (Platform.isMac())
       {
-        try
+
+        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)
         {
-          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)
+          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"))
         {
-          System.err.println(
-                  "Failed to reset look and feel: " + e.toString());
+          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());
+          }
         }
       }
     }
-
     /*
-     * 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", true))
+    boolean soDefault = !isJS;
+    if (Cache.getDefault("USE_FULL_SO", soDefault))
     {
-      SequenceOntologyFactory.setInstance(new SequenceOntology());
+      SequenceOntologyFactory.setSequenceOntology(new SequenceOntology());
     }
 
     if (!headless)
     {
-      desktop = new Desktop();
+      desktop = Desktop.getInstance();
       desktop.setInBatchMode(true); // indicate we are starting up
-
       try
       {
         JalviewTaskbar.setTaskbar(this);
-      } catch (Exception e)
-      {
-        System.out.println("Cannot set Taskbar");
-        // e.printStackTrace();
       } catch (Throwable t)
       {
-        System.out.println("Cannot set Taskbar");
-        // t.printStackTrace();
+        System.out.println("Error setting Taskbar: " + t.getMessage());
       }
-
       desktop.setVisible(true);
-      desktop.startServiceDiscovery();
-      if (!aparser.contains("nousagestats"))
-      {
-        startUsageStats(desktop);
-      }
-      else
-      {
-        System.err.println("CMD [-nousagestats] executed successfully!");
-      }
 
-      if (!aparser.contains("noquestionnaire"))
+      if (!isJS)
+      /**
+       * Java only
+       * 
+       * @j2sIgnore
+       */
       {
-        String url = aparser.getValue("questionnaire");
-        if (url != null)
+        desktop.startServiceDiscovery();
+        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 = "http://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!");
-      }
+        else
+        {
+          System.err
+                  .println("CMD [-noquestionnaire] executed successfully!");
+        }
 
-      if (!aparser.contains("nonews"))
-      {
-        desktop.checkForNews();
-      }
+        if (!aparser.contains("nonews"))
+        {
+          desktop.checkForNews();
+        }
 
-      BioJsHTMLOutput.updateBioJS();
+        BioJsHTMLOutput.updateBioJS();
+      }
     }
+    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)
+  {
 
-    // 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)
+    String groovyscript = null; // script to execute after all loading is
+    boolean isJS = Platform.isJS();
+    if (!isJS)
+    /** @j2sIgnore */
     {
-      final File appdir = new File(appdirString);
-      new Thread()
+      // 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)
       {
-        @Override
-        public void run()
+        final File appdir = new File(appdirString);
+        new Thread()
         {
-          LaunchUtil.upgradeGetdown(
-                  new File(appdir, "getdown-launcher-old.jar"),
-                  new File(appdir, "getdown-launcher.jar"),
-                  new File(appdir, "getdown-launcher-new.jar"));
-        }
-      }.start();
-    }
+          @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();
+      }
 
-    String file = null, data = null;
-    FileFormatI format = null;
-    DataSourceType protocol = null;
-    FileLoader fileLoader = new FileLoader(!headless);
+      // completed one way or another
+      // extract groovy argument and execute if necessary
+      groovyscript = aparser.getValue("groovy", true);
 
-    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);
     }
+
+    // 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.
+    JalviewJSApp jsApp = null;
+    AlignFrame af = null;
+
     if (file != null)
     {
       if (!headless)
@@ -454,29 +595,69 @@ public class Jalview
       }
       System.out.println("CMD [-open " + file + "] executed successfully!");
 
-      if (!file.startsWith("http://"))
+      if (!Platform.isJS())
+      /**
+       * ignore in JavaScript -- can't just file existence - could load it?
+       * 
+       * @j2sIgnore
+       */
       {
-        if (!(new File(file)).exists())
+        if (!file.startsWith("http://") && !file.startsWith("https://"))
+        // BH 2019 added https check for Java
         {
-          System.out.println("Can't find " + file);
-          if (headless)
+          if (!(new File(file)).exists())
           {
-            System.exit(1);
+            System.out.println("Can't find " + file);
+            if (headless)
+            {
+              System.exit(1);
+            }
           }
         }
       }
-
+      String fileFormat = (isJS
+              ? (String) aparser.getAppletValue("format", null, true)
+              : null);
       protocol = AppletFormatAdapter.checkProtocol(file);
-
       try
       {
-        format = new IdentifyFile().identify(file, protocol);
+        format = (fileFormat != null
+                ? FileFormats.getInstance().forName(fileFormat)
+                : null);
+        if (format == null)
+        {
+          format = new IdentifyFile().identify(file, protocol);
+        }
       } catch (FileFormatException e1)
       {
         // TODO ?
       }
 
-      AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
+      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!");
+      }
+
+      af = new FileLoader(!headless).LoadFileWaitTillLoaded(file, protocol,
               format);
       if (af == null)
       {
@@ -484,8 +665,38 @@ public class Jalview
       }
       else
       {
+
+        // JalviewLite interface for JavaScript allows second file open
+        String file2 = aparser.getValue(ArgsParser.OPEN2, true);
+        if (file2 != null)
+        {
+          protocol = AppletFormatAdapter.checkProtocol(file2);
+          try
+          {
+            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
+          {
+            AlignViewport.openLinkedAlignmentAs(af,
+                    af.getViewport().getAlignment(),
+                    af2.getViewport().getAlignment(), "",
+                    AlignViewport.SPLIT_FRAME);
+            System.out.println(
+                    "CMD [-open2 " + file2 + "] executed successfully!");
+          }
+        }
         setCurrentAlignFrame(af);
-        data = aparser.getValue("colour", true);
+
+        String data = aparser.getValue(ArgsParser.COLOUR, true);
         if (data != null)
         {
           data.replaceAll("%20", " ");
@@ -502,7 +713,7 @@ public class Jalview
         }
 
         // Must maintain ability to use the groups flag
-        data = aparser.getValue("groups", true);
+        data = aparser.getValue(ArgsParser.GROUPS, true);
         if (data != null)
         {
           af.parseFeaturesFile(data,
@@ -511,7 +722,7 @@ public class Jalview
           System.out.println(
                   "CMD groups[-" + data + "]  executed successfully!");
         }
-        data = aparser.getValue("features", true);
+        data = aparser.getValue(ArgsParser.FEATURES, true);
         if (data != null)
         {
           af.parseFeaturesFile(data,
@@ -520,8 +731,7 @@ public class Jalview
           System.out.println(
                   "CMD [-features " + data + "]  executed successfully!");
         }
-
-        data = aparser.getValue("annotations", true);
+        data = aparser.getValue(ArgsParser.ANNOTATIONS, true);
         if (data != null)
         {
           af.loadJalviewDataFile(data, null, null, null);
@@ -529,8 +739,17 @@ public class Jalview
           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("sortbytree"))
+        if (aparser.contains(ArgsParser.SORTBYTREE))
         {
           af.getViewport().setSortByTree(true);
           if (af.getViewport().getSortByTree())
@@ -538,34 +757,59 @@ public class Jalview
             System.out.println("CMD [-sortbytree] executed successfully!");
           }
         }
-        if (aparser.contains("no-annotation"))
+
+        boolean doUpdateAnnotation = false;
+        /**
+         * we do this earlier in JalviewJS because of a complication with
+         * SHOWOVERVIEW
+         * 
+         * For now, just fixing this in JalviewJS.
+         *
+         * 
+         * @j2sIgnore
+         * 
+         */
         {
-          af.getViewport().setShowAnnotation(false);
-          if (!af.getViewport().isShowAnnotation())
+          if (aparser.contains(ArgsParser.NOANNOTATION)
+                  || aparser.contains(ArgsParser.NOANNOTATION2))
           {
-            System.out.println("CMD no-annotation executed successfully!");
+            af.getViewport().setShowAnnotation(false);
+            if (!af.getViewport().isShowAnnotation())
+            {
+              doUpdateAnnotation = true;
+              System.out
+                      .println("CMD no-annotation executed successfully!");
+            }
           }
         }
-        if (aparser.contains("nosortbytree"))
+
+        if (aparser.contains(ArgsParser.NOSORTBYTREE))
         {
           af.getViewport().setSortByTree(false);
           if (!af.getViewport().getSortByTree())
           {
+            doUpdateAnnotation = true;
             System.out
                     .println("CMD [-nosortbytree] executed successfully!");
           }
         }
-        data = aparser.getValue("tree", true);
+        if (doUpdateAnnotation)
+        { // BH 2019.07.24
+          af.setMenusForViewport();
+          af.alignPanel.updateLayout();
+        }
+
+        data = aparser.getValue(ArgsParser.TREE, true);
         if (data != null)
         {
           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());
+            System.out.println(
+                    "CMD [-tree " + data + "] executed successfully!");
           } catch (IOException ex)
           {
             System.err.println("Couldn't add tree " + data);
@@ -575,157 +819,95 @@ public class Jalview
         // TODO - load PDB structure(s) to alignment JAL-629
         // (associate with identical sequence in alignment, or a specified
         // sequence)
-        if (groovyscript != null)
+
+        if (isJS)
         {
-          // 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;
+          jsApp = new JalviewJSApp(this, aparser);
+          jsApp.load(af);
         }
-        String imageName = "unnamed.png";
-        while (aparser.getSize() > 1)
+        else
+        /**
+         * Java only
+         * 
+         * @j2sIgnore
+         */
         {
-          String outputFormat = aparser.nextValue();
-          file = aparser.nextValue();
-
-          if (outputFormat.equalsIgnoreCase("png"))
+          if (groovyscript != null)
           {
-            af.createPNG(new File(file));
-            imageName = (new File(file)).getName();
-            System.out.println("Creating PNG image: " + file);
-            continue;
+            // 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;
           }
-          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!!");
-          }
-
+          createOutputFiles(aparser, af, format);
         }
+      }
+    }
+    else
+    {
+      if (!isJS && !headless && Cache.getDefault("SHOW_STARTUP_FILE", true))
+      /**
+       * Java only
+       * 
+       * @j2sIgnore
+       */
+      {
+
+        // We'll only open the default file if the desktop is visible.
+        // And the user
+        // ////////////////////
 
-        while (aparser.getSize() > 0)
+        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"))
         {
-          System.out.println("Unknown arg: " + aparser.nextValue());
+          // hardwire upgrade of the startup file
+          file.replace("_2_3.jar", "_2_7.jar");
+          // and remove the stale setting
+          Cache.removeProperty("STARTUP_FILE");
         }
-      }
-    }
-    AlignFrame startUpAlframe = null;
-    // We'll only open the default file if the desktop is visible.
-    // And the user
-    // ////////////////////
-
-    if (!headless && file == null
-            && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true))
-    {
-      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"))
-      {
-        // 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");
-      }
 
-      protocol = DataSourceType.FILE;
+        protocol = DataSourceType.FILE;
 
-      if (file.indexOf("http:") > -1)
-      {
-        protocol = DataSourceType.URL;
-      }
+        if (file.indexOf("http:") > -1)
+        {
+          protocol = DataSourceType.URL;
+        }
 
-      if (file.endsWith(".jar"))
-      {
-        format = FileFormat.Jalview;
-      }
-      else
-      {
-        try
+        if (file.endsWith(".jar"))
         {
-          format = new IdentifyFile().identify(file, protocol);
-        } catch (FileFormatException e)
+          format = FileFormat.Jalview;
+        }
+        else
         {
-          // TODO what?
+          try
+          {
+            format = new IdentifyFile().identify(file, protocol);
+          } catch (FileFormatException e)
+          {
+            // TODO what?
+          }
         }
-      }
 
-      startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
-              format);
-      // extract groovy arguments before anything else.
-    }
+        af = fileLoader.LoadFileWaitTillLoaded(file, protocol, format);
 
+      }
+    }
+    // extract groovy arguments before anything else.
     // Once all other stuff is done, execute any groovy scripts (in order)
-    if (groovyscript != null)
+    if (!isJS && groovyscript != null)
     {
       if (Cache.groovyJarsPresent())
       {
         System.out.println("Executing script " + groovyscript);
-        executeGroovyScript(groovyscript, startUpAlframe);
+        executeGroovyScript(groovyscript, af);
       }
       else
       {
@@ -734,6 +916,7 @@ public class Jalview
                         + groovyscript);
       }
     }
+
     // and finally, turn off batch mode indicator - if the desktop still exists
     if (desktop != null)
     {
@@ -743,6 +926,111 @@ public class Jalview
       }
       desktop.setInBatchMode(false);
     }
+
+    if (isJS && isStartup)
+    {
+      jsApp.callInitCallback();
+    }
+  }
+  
+
+  /**
+   * 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 af
+   * @param format
+   */
+  private void createOutputFiles(ArgsParser aparser, AlignFrame af,
+          FileFormatI format)
+  {
+    while (aparser.getSize() >= 2)
+    {
+      String outputFormat = aparser.nextValue();
+      File imageFile;
+      String fname;
+      switch (outputFormat.toLowerCase())
+      {
+      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
+        {
+          BioJsHTMLOutput.refreshVersionInfo(
+                  BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
+        } catch (URISyntaxException e)
+        {
+          e.printStackTrace();
+        }
+        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;
+      }
+      if (!Platform.isJS()) /** @j2sIgnore */
+      {
+        // skipping outputFormat?
+        System.out.println("Unknown arg: " + outputFormat);      
+        fname = new File(aparser.nextValue()).getAbsolutePath();
+        af.saveAlignment(fname, format);
+        if (af.isSaveAlignmentSuccessful())
+        {
+          System.out.println(
+                  "Written alignment in " + format + " format to " + fname);
+        }
+        else
+        {
+          System.out.println("Error writing file " + fname + " in " + format
+                  + " format!!");
+        }
+      }
+      break;
+    }
+    while (aparser.getSize() > 0)
+    {
+      System.out.println("Unknown arg: " + aparser.nextValue());
+    }
   }
 
   private static void showUsage()
@@ -791,7 +1079,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 ?"
@@ -821,10 +1109,10 @@ public class Jalview
    * Locate the given string as a file and pass it to the groovy interpreter.
    * 
    * @param groovyscript
-   *                         the script to execute
+   *          the script to execute
    * @param jalviewContext
-   *                         the Jalview Desktop object passed in to the groovy
-   *                         binding as the 'Jalview' object.
+   *          the Jalview Desktop object passed in to the groovy binding as the
+   *          'Jalview' object.
    */
   private void executeGroovyScript(String groovyscript, AlignFrame af)
   {
@@ -953,8 +1241,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()
   {
@@ -970,11 +1258,19 @@ 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);
   }
+  
 }