Merge branch 'merge/develop_and_rebase_squashed_merge_JAL-3628+JAL-3608+JAL-3609...
[jalview.git] / src / jalview / bin / Jalview.java
index afe4055..642efdb 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;
@@ -64,13 +43,35 @@ 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.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.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.HttpUtils;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.ws.jws2.Jws2Discoverer;
 
 /**
  * Main class for Jalview Application <br>
@@ -94,8 +95,9 @@ public class Jalview
     Platform.getURLCommandArguments();
   }
 
-  // singleton instance of this class
-
+  /*
+   * singleton instance of this class
+   */
   private static Jalview instance;
 
   private Desktop desktop;
@@ -112,21 +114,21 @@ public class Jalview
      */
     {
       // grab all the rights we can for the JVM
-           Policy.setPolicy(new Policy()
-           {
-             @Override
-             public PermissionCollection getPermissions(CodeSource codesource)
-             {
-               Permissions perms = new Permissions();
-               perms.add(new AllPermission());
-               return (perms);
-             }
-       
-             @Override
-             public void refresh()
-             {
-             }
-           });
+      Policy.setPolicy(new Policy()
+      {
+        @Override
+        public PermissionCollection getPermissions(CodeSource codesource)
+        {
+          Permissions perms = new Permissions();
+          perms.add(new AllPermission());
+          return (perms);
+        }
+
+        @Override
+        public void refresh()
+        {
+        }
+      });
     }
   }
 
@@ -198,27 +200,27 @@ public class Jalview
    * main class for Jalview application
    * 
    * @param args
-   *               open <em>filename</em>
+   *          open <em>filename</em>
    */
   public static void main(String[] args)
   {
-//     setLogging(); // BH - for event debugging in JavaScript
+    // setLogging(); // BH - for event debugging in JavaScript
     instance = new Jalview();
     instance.doMain(args);
-}
+  }
 
-  private static void logClass(String name) 
-  {    
-         // BH - for event debugging in JavaScript
-      ConsoleHandler consoleHandler = new ConsoleHandler();
-      consoleHandler.setLevel(Level.ALL);
-      Logger logger = Logger.getLogger(name);
-      logger.setLevel(Level.ALL);
-      logger.addHandler(consoleHandler);
+  private static void logClass(String name)
+  {
+    // BH - for event debugging in JavaScript
+    ConsoleHandler consoleHandler = new ConsoleHandler();
+    consoleHandler.setLevel(Level.ALL);
+    Logger logger = Logger.getLogger(name);
+    logger.setLevel(Level.ALL);
+    logger.addHandler(consoleHandler);
   }
 
   @SuppressWarnings("unused")
-  private static void setLogging() 
+  private static void setLogging()
   {
 
     /**
@@ -229,26 +231,23 @@ public class Jalview
       System.out.println("not in js");
     }
 
-         // BH - for event debugging in JavaScript (Java mode only)
+    // BH - for event debugging in JavaScript (Java mode only)
     if (!Platform.isJS())
     /**
      * Java only
      * 
      * @j2sIgnore
      */
-       {
-               Logger.getLogger("").setLevel(Level.ALL);
-        logClass("java.awt.EventDispatchThread");
-        logClass("java.awt.EventQueue");
-        logClass("java.awt.Component");
-        logClass("java.awt.focus.Component");
-        logClass("java.awt.focus.DefaultKeyboardFocusManager"); 
-       }       
+    {
+      Logger.getLogger("").setLevel(Level.ALL);
+      logClass("java.awt.EventDispatchThread");
+      logClass("java.awt.EventQueue");
+      logClass("java.awt.Component");
+      logClass("java.awt.focus.Component");
+      logClass("java.awt.focus.DefaultKeyboardFocusManager");
+    }
 
   }
-  
-
-  
 
   /**
    * @param args
@@ -262,22 +261,24 @@ public class Jalview
     }
 
     System.out
-            .println("Java version: "
-                    + System.getProperty("java.version"));
+            .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"));
     String val = System.getProperty("sys.install4jVersion");
-    if (val != null) {
-    System.out.println("Install4j version: " + val);
+    if (val != null)
+    {
+      System.out.println("Install4j version: " + val);
     }
     val = System.getProperty("installer_template_version");
-    if (val != null) {
+    if (val != null)
+    {
       System.out.println("Install4j template version: " + val);
     }
     val = System.getProperty("launcher_version");
-    if (val != null) {
+    if (val != null)
+    {
       System.out.println("Launcher version: " + val);
     }
 
@@ -329,8 +330,8 @@ public class Jalview
                   "Invalid jabaws parameter: " + jabawsUrl + " ignored");
         }
       }
-
     }
+
     String defs = aparser.getValue("setprop");
     while (defs != null)
     {
@@ -344,8 +345,11 @@ public class Jalview
         System.out.println("Executing setprop argument: " + defs);
         if (Platform.isJS())
         {
-          Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
+          Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
         }
+        // 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));
       }
       defs = aparser.getValue("setprop");
     }
@@ -369,45 +373,7 @@ public class Jalview
 
     desktop = null;
 
-    // property laf = "crossplatform", "system" or "mac"
-    // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac, try Quaqua/Vaqua.
-    String laf = System.getProperty("laf","none");
-    boolean lafSet = false;
-    switch(laf) {
-    case "crossplatform":
-      lafSet = setCrossPlatformLookAndFeel();
-      if (!lafSet)
-      {
-        System.err.println("Could not set requested laf="+laf);
-      }
-      break;
-    case "system":
-      lafSet = setSystemLookAndFeel();
-      if (!lafSet)
-      {
-        System.err.println("Could not set requested laf="+laf);
-      }
-      break;
-    case "mac":
-      lafSet = setMacLookAndFeel();
-      if (!lafSet)
-      {
-        System.err.println("Could not set requested laf="+laf);
-      }
-      break;
-    case "none":
-      break;
-    default:
-      System.err.println("Requested laf="+laf+" not implemented");
-    }
-    if (! lafSet)
-    {
-      setSystemLookAndFeel();
-      if (Platform.isAMacAndNotJS())
-      {
-        setMacLookAndFeel();
-      }
-    }
+    setLookAndFeel();
 
     /*
      * configure 'full' SO model if preferences say to, else use the default (full SO)
@@ -421,17 +387,28 @@ public class Jalview
 
     if (!headless)
     {
+      Desktop.nosplash = aparser.contains("nosplash");
       desktop = new Desktop();
       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)
       {
-        System.out.println("Error setting Taskbar: " + t.getMessage());
+        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);
 
       if (!Platform.isJS())
@@ -441,7 +418,10 @@ public class Jalview
        * @j2sIgnore
        */
       {
-        desktop.startServiceDiscovery();
+        if (!aparser.contains("nowebservicediscovery"))
+        {
+          desktop.startServiceDiscovery();
+        }
         if (!aparser.contains("nousagestats"))
         {
           startUsageStats(desktop);
@@ -543,14 +523,13 @@ public class Jalview
       System.out.println("CMD [-open " + file + "] executed successfully!");
 
       if (!Platform.isJS())
-        /**
-         * ignore in JavaScript -- can't just file existence - could load it?
-         * 
-         * @j2sIgnore
-         */
+      /**
+       * ignore in JavaScript -- can't just file existence - could load it?
+       * 
+       * @j2sIgnore
+       */
       {
-        if (!file.startsWith("http://") && !file.startsWith("https://"))
-        // BH 2019 added https check for Java
+        if (!HttpUtils.startsWithHttpOrHttps(file))
         {
           if (!(new File(file)).exists())
           {
@@ -563,7 +542,7 @@ public class Jalview
         }
       }
 
-        protocol = AppletFormatAdapter.checkProtocol(file);
+      protocol = AppletFormatAdapter.checkProtocol(file);
 
       try
       {
@@ -748,17 +727,37 @@ public class Jalview
             af.createEPS(outputFile);
             continue;
           }
-
-          af.saveAlignment(file, format);
-          if (af.isSaveAlignmentSuccessful())
+          FileFormatI outFormat = null;
+          try
           {
-            System.out.println("Written alignment in " + format
-                    + " format to " + file);
+            outFormat = FileFormats.getInstance().forName(outputFormat);
+          } catch (Exception formatP)
+          {
+            System.out.println("Couldn't parse " + outFormat
+                    + " as a valid Jalview format string.");
           }
-          else
+          if (outFormat != null)
           {
-            System.out.println("Error writing file " + file + " in "
-                    + format + " format!!");
+            if (!outFormat.isWritable())
+            {
+              System.out.println(
+                      "This version of Jalview does not support alignment export as "
+                              + outputFormat);
+            }
+            else
+            {
+              af.saveAlignment(file, outFormat);
+              if (af.isSaveAlignmentSuccessful())
+              {
+                System.out.println("Written alignment in "
+                        + outFormat.getName() + " format to " + file);
+              }
+              else
+              {
+                System.out.println("Error writing file " + file + " in "
+                        + outFormat.getName() + " format!!");
+              }
+            }
           }
 
         }
@@ -783,8 +782,7 @@ public class Jalview
      */
     {
       file = Cache.getDefault("STARTUP_FILE",
-              Cache.getDefault("www.jalview.org",
-                      "http://www.jalview.org")
+              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"))
@@ -795,12 +793,7 @@ public class Jalview
         Cache.removeProperty("STARTUP_FILE");
       }
 
-      protocol = DataSourceType.FILE;
-
-      if (file.indexOf("http:") > -1)
-      {
-        protocol = DataSourceType.URL;
-      }
+      protocol = AppletFormatAdapter.checkProtocol(file);
 
       if (file.endsWith(".jar"))
       {
@@ -848,74 +841,209 @@ public class Jalview
     }
   }
 
-  private static boolean setCrossPlatformLookAndFeel() {
-         boolean set = false;
-         try
-         {
-                 UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
-                 set = true;
-         } catch (Exception ex)
-         {
-                 System.err.println("Unexpected Look and Feel Exception");
-                 ex.printStackTrace();
-         }
-         return set;
+  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)
+    {
+      laf = lafProp;
+    }
+    else if (lafSetting != null)
+    {
+      laf = lafSetting;
+    }
+    boolean lafSet = false;
+    switch (laf)
+    {
+    case "crossplatform":
+      lafSet = setCrossPlatformLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "system":
+      lafSet = setSystemLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "gtk":
+      lafSet = setGtkLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "metal":
+      lafSet = setMetalLookAndFeel();
+      if (!lafSet)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      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)
+      {
+        Cache.log.error("Could not set requested laf=" + laf);
+      }
+      break;
+    case "none":
+      break;
+    default:
+      Cache.log.error("Requested laf=" + laf + " not implemented");
+    }
+    if (!lafSet)
+    {
+      setSystemLookAndFeel();
+      if (Platform.isLinux())
+      {
+        setMetalLookAndFeel();
+      }
+      if (Platform.isMac())
+      {
+        setMacLookAndFeel();
+      }
+    }
   }
 
-  private static boolean setSystemLookAndFeel() {
-         boolean set = false;
-         try
-         {
-                 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
-                 set = true;
-         } catch (Exception ex)
-         {
-                 System.err.println("Unexpected Look and Feel Exception");
-                 ex.printStackTrace();
-         }
-         return set;
+  private static boolean setCrossPlatformLookAndFeel()
+  {
+    boolean set = false;
+    try
+    {
+      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 setMacLookAndFeel() {
-         boolean set = false;
-         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);
-                         set = true;
-                 } 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");
-                         set = true;
-                 } catch (Throwable e)
-                 {
-                         System.err.println(
-                                         "Failed to reset look and feel: " + e.toString());
-                 }
-         }
-         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())
+      {
+        if (info.getName() != null && nameStartsWith
+                ? info.getName().toLowerCase()
+                        .startsWith(name.toLowerCase())
+                : info.getName().toLowerCase().equals(name.toLowerCase()))
+        {
+          className = info.getClassName();
+          break;
+        }
+      }
+      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",
+            "Jalview");
+    System.setProperty("apple.laf.useScreenMenuBar", "true");
+    set = setQuaquaLookAndFeel();
+    if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
+            .toLowerCase().contains("quaqua"))
+    {
+      set = setVaquaLookAndFeel();
+    }
+    return set;
+  }
+
   private static void showUsage()
   {
     System.out.println(
@@ -992,10 +1120,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)
   {
@@ -1124,8 +1252,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()
   {