Merge branch 'improvement/JAL-3783_upgrade_to_groovy-4' into jims/bug/JAL-4298_java_c...
[jalview.git] / src / jalview / bin / Jalview.java
index af638c8..e343b0f 100755 (executable)
@@ -73,9 +73,12 @@ import jalview.bin.argparser.Arg.Opt;
 import jalview.bin.argparser.Arg.Type;
 import jalview.bin.argparser.ArgParser;
 import jalview.bin.argparser.BootstrapArgs;
+import jalview.bin.groovy.JalviewObject;
+import jalview.bin.groovy.JalviewObjectI;
 import jalview.ext.so.SequenceOntology;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
 import jalview.gui.PromptUserConfig;
 import jalview.gui.QuitHandler;
 import jalview.gui.QuitHandler.QResponse;
@@ -117,7 +120,7 @@ import jalview.ws.jws2.Jws2Discoverer;
  * @author $author$
  * @version $Revision$
  */
-public class Jalview
+public class Jalview implements JalviewObjectI
 {
   static
   {
@@ -137,7 +140,7 @@ public class Jalview
 
   protected Commands cmds;
 
-  public static AlignFrame currentAlignFrame;
+  public AlignFrame currentAlignFrame = null;
 
   private ArgParser argparser = null;
 
@@ -426,7 +429,7 @@ public class Jalview
     // stop now if only after --version
     if (bootstrapArgs.contains(Arg.VERSION))
     {
-      Jalview.exit(null, 0);
+      Jalview.exit(null, ExitCode.OK);
     }
 
     // old ArgsParser
@@ -446,7 +449,7 @@ public class Jalview
       }
       else if (bootstrapArgs.contains(Arg.DEBUG))
       {
-        logLevel = "DEBUG";
+        logLevel = bootstrapArgs.getBoolean(Arg.DEBUG) ? "DEBUG" : "INFO";
       }
       if (logLevel == null && !(bootstrapProperties == null))
       {
@@ -458,7 +461,7 @@ public class Jalview
       error.printStackTrace();
       String message = "\nEssential logging libraries not found."
               + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview";
-      Jalview.exit(message, 0);
+      Jalview.exit(message, ExitCode.OK);
     }
 
     // register SIGTERM listener
@@ -545,7 +548,7 @@ public class Jalview
                 .getList(Arg.HELP);
         Console.outPrintln(Arg.usage(helpArgs.stream().map(e -> e.getKey())
                 .collect(Collectors.toList())));
-        Jalview.exit(null, 0);
+        Jalview.exit(null, ExitCode.OK);
       }
       if (aparser.contains("help") || aparser.contains("h"))
       {
@@ -554,7 +557,7 @@ public class Jalview
         showUsage();
         */
         Console.outPrintln(Arg.usage());
-        Jalview.exit(null, 0);
+        Jalview.exit(null, ExitCode.OK);
       }
 
       // new CLI
@@ -641,14 +644,12 @@ public class Jalview
     try
     {
       Console.initLogger();
-    } catch (
-
-    NoClassDefFoundError error)
+    } catch (NoClassDefFoundError error)
     {
       error.printStackTrace();
       String message = "\nEssential logging libraries not found."
               + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview";
-      Jalview.exit(message, 0);
+      Jalview.exit(message, ExitCode.NO_LOGGING);
     }
     desktop = null;
 
@@ -673,6 +674,8 @@ public class Jalview
       desktop = new Desktop();
       desktop.setInBatchMode(true); // indicate we are starting up
 
+      mixedCliWarning();
+
       try
       {
         JalviewTaskbar.setTaskbar(this);
@@ -809,6 +812,30 @@ public class Jalview
         }
       }
     }
+    else
+    {
+
+      if (getArgParser().isMixedStyle())
+      {
+        String warning = MessageManager.formatMessage(
+                "warning.using_mixed_command_line_arguments",
+                getArgParser().getMixedExamples());
+        Console.warn(warning);
+        Jalview.exit(
+                "Exiting due to mixed old and new command line arguments",
+                ExitCode.INVALID_ARGUMENT);
+      }
+      if (getArgParser().isOldStyle())
+      {
+        String warning = MessageManager
+                .getString("warning.using_old_command_line_arguments")
+                .replace("\n", " ")
+                + "https://www.jalview.org/help/html/features/commandline.html";
+        Console.warn(warning);
+      }
+
+    }
+
     // Run Commands from cli
     cmds = new Commands(argparser, headlessArg);
     cmds.processArgs();
@@ -827,7 +854,7 @@ public class Jalview
         else
         {
           Jalview.exit("Successfully completed commands in headless mode",
-                  0);
+                  ExitCode.OK);
         }
       }
       Console.info("Successfully completed commands");
@@ -836,7 +863,8 @@ public class Jalview
     {
       if (headlessArg)
       {
-        Jalview.exit("Error when running Commands in headless mode", 1);
+        Jalview.exit("Error when running Commands in headless mode",
+                ExitCode.ERROR_RUNNING_COMMANDS);
       }
       Console.warn("Error when running commands");
     }
@@ -867,7 +895,7 @@ public class Jalview
 
     if (file == null && desktop == null && !commandsSuccess)
     {
-      Jalview.exit("No files to open!", 1);
+      Jalview.exit("No files to open!", ExitCode.NO_FILES);
     }
 
     long progress = -1;
@@ -897,7 +925,8 @@ public class Jalview
             if (headless)
             {
               Jalview.exit(
-                      "Can't find file '" + file + "' in headless mode", 1);
+                      "Can't find file '" + file + "' in headless mode",
+                      ExitCode.FILE_NOT_FOUND);
             }
             Console.warn("Can't find file'" + file + "'");
           }
@@ -1221,6 +1250,8 @@ public class Jalview
       }
       desktop.setInBatchMode(false);
     }
+
+    cliWarning();
   }
 
   private static void setLookAndFeel()
@@ -1502,7 +1533,7 @@ public class Jalview
       UIManager.put("TabbedPane.tabType", "card");
       UIManager.put("TabbedPane.showTabSeparators", true);
       UIManager.put("TabbedPane.showContentSeparator", true);
-      UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
+      // UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
       UIManager.put("TabbedPane.tabsOverlapBorder", true);
       UIManager.put("TabbedPane.hasFullBorder", true);
       UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
@@ -1601,9 +1632,8 @@ public class Jalview
      */
     PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
             "USAGESTATS",
-            MessageManager.getString("prompt.plausible_analytics_title"),
-            MessageManager.getString("prompt.plausible_analytics"),
-            new Runnable()
+            MessageManager.getString("prompt.analytics_title"),
+            MessageManager.getString("prompt.analytics"), new Runnable()
             {
               @Override
               public void run()
@@ -1721,12 +1751,11 @@ public class Jalview
     }
     try
     {
+      JalviewObjectI j = new JalviewObject(this);
       Map<String, java.lang.Object> vbinding = new HashMap<>();
-      vbinding.put("Jalview", this);
-      if (af != null)
-      {
-        vbinding.put("currentAlFrame", af);
-      }
+      vbinding.put(JalviewObjectI.jalviewObjectName, j);
+      vbinding.put(JalviewObjectI.currentAlFrameName,
+              af != null ? af : getCurrentAlignFrame());
       Binding gbinding = new Binding(vbinding);
       GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
       gse.run(sfile.toString(), gbinding);
@@ -1742,7 +1771,6 @@ public class Jalview
               .errPrintln("Exception Whilst trying to execute file " + sfile
                       + " as a groovy script.");
       e.printStackTrace(System.err);
-
     }
   }
 
@@ -1756,30 +1784,32 @@ public class Jalview
     return false;
   }
 
+  @Override
   public AlignFrame[] getAlignFrames()
   {
     return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
-            : Desktop.getAlignFrames();
-
+            : Desktop.getDesktopAlignFrames();
   }
 
   /**
    * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
    */
+  @Override
   public void quit()
   {
     // System.exit will run the shutdownHook first
-    Jalview.exit("Quitting now. Bye!", 0);
+    Jalview.exit("Quitting now. Bye!", ExitCode.OK);
   }
 
-  public static AlignFrame getCurrentAlignFrame()
+  @Override
+  public AlignFrame getCurrentAlignFrame()
   {
-    return Jalview.currentAlignFrame;
+    return currentAlignFrame;
   }
 
-  public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
+  public void setCurrentAlignFrame(AlignFrame af)
   {
-    Jalview.currentAlignFrame = currentAlignFrame;
+    this.currentAlignFrame = af;
   }
 
   public Commands getCommands()
@@ -1787,8 +1817,9 @@ public class Jalview
     return cmds;
   }
 
-  public static void exit(String message, int exitcode)
+  public static void exit(String message, ExitCode ec)
   {
+    int exitcode = ec == ExitCode.OK ? 0 : ec.ordinal() + 1;
     if (Console.log == null)
     {
       // Don't start the logger just to exit!
@@ -1825,14 +1856,35 @@ public class Jalview
     }
   }
 
+  public enum ExitCode
+  {
+    // only add new ones to the end of the list (to preserve ordinal values)
+    OK, FILE_NOT_FOUND, FILE_NOT_READABLE, NO_FILES, INVALID_FORMAT,
+    INVALID_ARGUMENT, INVALID_VALUE, MIXED_CLI_ARGUMENTS,
+    ERROR_RUNNING_COMMANDS, NO_LOGGING, GROOVY_ERROR;
+  }
+
   /******************************
    * 
    * TEST OUTPUT METHODS
    * 
+   * these operate only when Arg.TESTOUTPUT has been passed, and variously check
+   * if an expected value / arg was set and report it to the test framework.
+   * 
    ******************************/
   /**
-   * method for reporting string values parsed/processed during tests
+   * report string values parsed/processed during tests When the Bootstrap
+   * argument Arg.TESTOUTPUT is present - reports on debug if given s1 is not
+   * null and not equals s2, warns if given argument is not set, and calls
+   * testoutput(true,a,s1,s2) to report processing progress.
    * 
+   * @param ap
+   *          - ArgParser handling parsing
+   * @param a
+   *          - Arg currently being processed
+   * @param s1
+   *          - expected
+   * @param s2
    */
   protected static void testoutput(ArgParser ap, Arg a, String s1,
           String s2)
@@ -1857,7 +1909,9 @@ public class Jalview
   }
 
   /**
-   * method for reporting string values parsed/processed during tests
+   * report values passed via bootstrap arguments
+   * 
+   * TODO: significant code duplication with testouput(Argparser...) - move it
    */
 
   protected static void testoutput(BootstrapArgs bsa, Arg a, String s1,
@@ -1885,7 +1939,8 @@ public class Jalview
   }
 
   /**
-   * report value set for string values parsed/processed during tests
+   * conditionally (on @param yes) report that expected value s1 was set during
+   * CommandsTest tests
    */
   private static void testoutput(boolean yes, Arg a, String s1, String s2)
   {
@@ -1963,4 +2018,77 @@ public class Jalview
     return bootstrapArgs;
   }
 
+  public static boolean isBatchMode()
+  {
+    return getInstance() != null && (getInstance().desktop == null
+            || getInstance().desktop.isInBatchMode());
+  }
+
+  /**
+   * Warning about old or mixed command line arguments
+   */
+  private void mixedCliWarning()
+  {
+    Jalview j = Jalview.getInstance();
+    boolean mixedStyle = j.getArgParser() != null
+            && j.getArgParser().isMixedStyle();
+    String title = MessageManager.getString("label.command_line_arguments");
+    if (mixedStyle)
+    {
+      String warning = MessageManager.formatMessage(
+              "warning.using_mixed_command_line_arguments",
+              j.getArgParser().getMixedExamples());
+      String quit = MessageManager.getString("action.quit");
+
+      Desktop.instance.nonBlockingDialog(title, warning, null, quit,
+              JvOptionPane.WARNING_MESSAGE, false, false, true, 30000);
+
+      Jalview.exit(
+              "Exiting due to mixed old and new command line arguments.",
+              ExitCode.MIXED_CLI_ARGUMENTS);
+    }
+  }
+
+  private void cliWarning()
+  {
+    Jalview j = Jalview.getInstance();
+    Commands c = j.getCommands();
+    boolean oldStyle = j.getArgParser() != null
+            && j.getArgParser().isOldStyle();
+    String title = MessageManager.getString("label.command_line_arguments");
+    if (oldStyle)
+    {
+      String warning = MessageManager
+              .getString("warning.using_old_command_line_arguments");
+      String url = "<a href=\"https://www.jalview.org/help/html/features/commandline.html\">https://www.jalview.org/help/html/features/commandline.html</a>";
+      if (Desktop.instance != null)
+      {
+        String cont = MessageManager.getString("label.continue");
+
+        Desktop.instance.nonBlockingDialog(title, warning, url, cont,
+                JvOptionPane.WARNING_MESSAGE, false, true, true, 30000);
+      }
+    }
+    if (j.getCommands() != null && j.getCommands().getErrors().size() > 0)
+    {
+      if (Desktop.instance != null)
+      {
+        String message = MessageManager
+                .getString("warning.the_following_errors");
+        String ok = MessageManager.getString("action.ok");
+        int shortest = 60;
+        List<String> errors = j.getCommands().getErrors();
+        for (int i = 0; i < errors.size(); i++)
+        {
+          shortest = Math.min(shortest, errors.get(i).length());
+        }
+        Desktop.instance.nonBlockingDialog(
+                Math.max(message.length(), Math.min(60, shortest)),
+                Math.min(errors.size(), 20), title, message,
+                j.getCommands().errorsToString(), ok,
+                JvOptionPane.WARNING_MESSAGE, true, false, true, -1);
+      }
+    }
+  }
+
 }