Clover icon

Coverage Report

  1. Project Clover database Thu Jan 15 2026 16:11:02 GMT
  2. Package jalview.bin

File Jalview.java

 

Coverage histogram

../../img/srcFileCovDistChart6.png
39% of files have more coverage

Code metrics

380
803
58
3
2,462
1,825
349
0.43
13.84
19.33
6.02

Classes

Class Line # Actions
Jalview 123 790 345
0.536764753.7%
Jalview.FeatureFetcher 251 13 4
0.00%
Jalview.ExitCode 2210 0 0
-1.0 -
 

Contributing tests

This file is covered by 312 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21   
22    package jalview.bin;
23   
24    import java.awt.Color;
25    import java.awt.GraphicsEnvironment;
26    import java.io.BufferedReader;
27    import java.io.File;
28    import java.io.FileNotFoundException;
29    import java.io.FileOutputStream;
30    import java.io.IOException;
31    import java.io.InputStreamReader;
32    import java.io.OutputStream;
33    import java.io.OutputStreamWriter;
34    import java.io.PrintStream;
35    import java.io.PrintWriter;
36    import java.net.MalformedURLException;
37    import java.net.URI;
38    import java.net.URISyntaxException;
39    import java.net.URL;
40    import java.util.ArrayList;
41    import java.util.HashMap;
42    import java.util.List;
43    import java.util.Locale;
44    import java.util.Map;
45    import java.util.Properties;
46    import java.util.Vector;
47    import java.util.stream.Collectors;
48   
49    import javax.swing.JDialog;
50    import javax.swing.JFrame;
51    import javax.swing.JInternalFrame;
52    import javax.swing.JOptionPane;
53    import javax.swing.SwingUtilities;
54    import javax.swing.UIManager;
55    import javax.swing.UIManager.LookAndFeelInfo;
56    import javax.swing.UnsupportedLookAndFeelException;
57   
58    import com.formdev.flatlaf.FlatLightLaf;
59    import com.formdev.flatlaf.themes.FlatMacLightLaf;
60    import com.formdev.flatlaf.util.SystemInfo;
61    import com.threerings.getdown.util.LaunchUtil;
62   
63    //import edu.stanford.ejalbert.launching.IBrowserLaunching;
64    import groovy.lang.Binding;
65    import groovy.util.GroovyScriptEngine;
66    import jalview.api.AlignCalcWorkerI;
67    import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI;
68    import jalview.bin.argparser.Arg;
69    import jalview.bin.argparser.Arg.Opt;
70    import jalview.bin.argparser.Arg.Type;
71    import jalview.bin.argparser.ArgParser;
72    import jalview.bin.argparser.BootstrapArgs;
73    import jalview.bin.groovy.JalviewObject;
74    import jalview.bin.groovy.JalviewObjectI;
75    import jalview.ext.so.SequenceOntology;
76    import jalview.gui.AlignFrame;
77    import jalview.gui.AlignViewport;
78    import jalview.gui.Desktop;
79    import jalview.gui.JvOptionPane;
80    import jalview.gui.Preferences;
81    import jalview.gui.PromptUserConfig;
82    import jalview.gui.QuitHandler;
83    import jalview.gui.QuitHandler.QResponse;
84    import jalview.gui.StructureViewerBase;
85    import jalview.io.AppletFormatAdapter;
86    import jalview.io.BioJsHTMLOutput;
87    import jalview.io.DataSourceType;
88    import jalview.io.FileFormat;
89    import jalview.io.FileFormatException;
90    import jalview.io.FileFormatI;
91    import jalview.io.FileFormats;
92    import jalview.io.FileLoader;
93    import jalview.io.HtmlSvgOutput;
94    import jalview.io.IdentifyFile;
95    import jalview.io.NewickFile;
96    import jalview.io.exceptions.ImageOutputException;
97    import jalview.io.gff.SequenceOntologyFactory;
98    import jalview.schemes.ColourSchemeI;
99    import jalview.schemes.ColourSchemeProperty;
100    import jalview.util.ChannelProperties;
101    import jalview.util.HttpUtils;
102    import jalview.util.LaunchUtils;
103    import jalview.util.MessageManager;
104    import jalview.util.Platform;
105    import jalview.util.UserAgent;
106    import jalview.ws.jws2.Jws2Discoverer;
107   
108    /**
109    * Main class for Jalview Application <br>
110    * <br>
111    * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
112    * jalview.bin.Jalview
113    *
114    * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
115    * jalview.bin.Jalview jalview.bin.Jalview
116    *
117    * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
118    * embellish '*' to e.g. '*.jar')
119    *
120    * @author $author$
121    * @version $Revision$
122    */
 
123    public class Jalview implements JalviewObjectI, ApplicationSingletonI
124    {
125    // TODO JAL-4107 - does Jalview need to do both objects explicitly
126    // for testing those nasty messages you cannot ever find.
127    // static
128    // {
129    // System.setOut(new PrintStream(new ByteArrayOutputStream())
130    // {
131    // @Override
132    // public void println(Object o)
133    // {
134    // if (o != null)
135    // {
136    // System.err.println(o);
137    // }
138    // }
139    //
140    // });
141    // }
 
142  40444 toggle public static Jalview getInstance()
143    {
144  40444 return ApplicationSingletonProvider.getInstance(Jalview.class);
145    }
146   
 
147  1209 toggle public static boolean instanceExists()
148    {
149  1209 return ApplicationSingletonProvider.instanceExists(Jalview.class);
150    }
151   
 
152  55 toggle private Jalview()
153    {
154  55 Platform.getURLCommandArguments();
155  55 Platform.addJ2SDirectDatabaseCall("https://www.jalview.org");
156  55 Platform.addJ2SDirectDatabaseCall("http://www.jalview.org");
157  55 Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk");
158  55 Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk");
159    }
160   
161    private boolean headless;
162   
163    private Desktop desktop;
164   
165    protected Commands cmds;
166   
167    public AlignFrame currentAlignFrame = null;
168   
169    private ArgParser argparser = null;
170   
171    private BootstrapArgs bootstrapArgs = null;
172   
173    private boolean QUIET = false;
174   
 
175  387 toggle public static boolean quiet()
176    {
177  387 return Jalview.instanceExists() && Jalview.getInstance().QUIET;
178    }
179   
180    public String appletResourcePath;
181   
182    public String j2sAppletID;
183   
184    private boolean noCalculation, noMenuBar, noStatus;
185   
186    private boolean noAnnotation;
187   
 
188  492 toggle public boolean getStartCalculations()
189    {
190  492 return !noCalculation;
191    }
192   
 
193  439 toggle public boolean getAllowMenuBar()
194    {
195  439 return !noMenuBar;
196    }
197   
 
198  439 toggle public boolean getShowStatus()
199    {
200  439 return !noStatus;
201    }
202   
 
203  0 toggle public boolean getShowAnnotation()
204    {
205  0 return !noAnnotation;
206    }
207   
208    /* bs 2026-01-14
209    * SecurityManager and related classes (e.g. Policy) are deprecated in Java 17.
210    * See https://issues.jalview.org/browse/JAL-3907?focusedCommentId=27285&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-27285
211    *
212    static
213    {
214    if (Platform.isJS())
215    {
216    Platform.getURLCommandArguments();
217    }
218    else
219    /**
220    * Java only
221    *
222    * @j2sIgnore
223    * /
224    {
225    // grab all the rights we can for the JVM
226    Policy.setPolicy(new Policy()
227    {
228    @Override
229    public PermissionCollection getPermissions(CodeSource codesource)
230    {
231    Permissions perms = new Permissions();
232    perms.add(new AllPermission());
233    return (perms);
234    }
235   
236    @Override
237    public void refresh()
238    {
239    }
240    });
241    }
242    }
243    */
244   
245    /**
246    * keep track of feature fetching tasks.
247    *
248    * @author JimP
249    *
250    */
 
251    class FeatureFetcher
252    {
253    /*
254    * TODO: generalise to track all jalview events to orchestrate batch processing
255    * events.
256    */
257   
258    private int queued = 0;
259   
260    private int running = 0;
261   
 
262  0 toggle public FeatureFetcher()
263    {
264   
265    }
266   
 
267  0 toggle public void addFetcher(final AlignFrame af,
268    final Vector<String> dasSources)
269    {
270  0 final long id = System.currentTimeMillis();
271  0 queued++;
272  0 final FeatureFetcher us = this;
273  0 new Thread(new Runnable()
274    {
275   
 
276  0 toggle @Override
277    public void run()
278    {
279  0 synchronized (us)
280    {
281  0 queued--;
282  0 running++;
283    }
284   
285  0 af.setProgressBar(MessageManager
286    .getString("status.das_features_being_retrived"), id);
287  0 af.featureSettings_actionPerformed(null);
288  0 af.setProgressBar(null, id);
289  0 synchronized (us)
290    {
291  0 running--;
292    }
293    }
294    }).start();
295    }
296   
 
297  0 toggle public synchronized boolean allFinished()
298    {
299  0 return queued == 0 && running == 0;
300    }
301   
302    }
303   
304    private final static boolean doPlatformLogging = false;
305   
306    /**
307    * main class for Jalview application
308    *
309    * @param args
310    * open <em>filename</em>
311    */
 
312  87 toggle public static void main(String[] args)
313    {
314  87 if (doPlatformLogging)
315    {
316  0 Platform.startJavaLogging();
317    }
318   
319  87 getInstance().doMain(args);
320   
321    }
322   
323    /**
324    * @param args
325    */
 
326  138 toggle void doMain(String[] args)
327    {
328  138 boolean isJS = Platform.isJS();
329    /* bs 2026-01-14
330    * SecurityManager and related classes (e.g. Policy) are deprecated in Java 17.
331    * See https://issues.jalview.org/browse/JAL-3907?focusedCommentId=27285&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-27285
332    *
333    if (!isJS)
334    {
335    System.setSecurityManager(null);
336    }
337    */
338   
339    /*
340    * @j2sNative J2S.db._DirectDatabaseCalls["compbio.dundee.ac.uk"]=null;
341    * @j2sNative J2S.db._DirectDatabaseCalls["jalview.org"]=null;
342    *
343    */
344   
345  138 if (args == null || args.length == 0 || (args.length == 1
346    && (args[0] == null || args[0].length() == 0)))
347    {
348  9 args = new String[] {};
349    }
350   
351    // get args needed before proper ArgParser
352  138 bootstrapArgs = BootstrapArgs.getBootstrapArgs(args);
353   
354  138 boolean usingLogfile = false;
355  138 if (!Platform.isJS())
356    {
357    // required to ensure log4j doesn't think it's running in a servlet
358  138 System.setProperty("log4j2.isWebapp", "false");
359   
360    // are we using a logfile?
361  138 String logfilename = System.getProperty("installer.logfile");
362  138 boolean append = Boolean
363    .parseBoolean(System.getProperty("installer.logfile_append"));
364   
365  138 usingLogfile = Console.setLogFile(logfilename, append);
366   
367    // are we being --quiet ? (doesn't matter if using a logfile)
368  138 if (!usingLogfile && bootstrapArgs.contains(Arg.QUIET))
369    {
370  0 QUIET = true;
371  0 OutputStream devNull = new OutputStream()
372    {
 
373  0 toggle @Override
374    public void write(int b)
375    {
376    // DO NOTHING
377    }
378    };
379  0 System.setOut(new PrintStream(devNull));
380    // redirecting stderr not working
381  0 if (bootstrapArgs.getList(Arg.QUIET).size() > 1)
382    {
383  0 System.setErr(new PrintStream(devNull));
384    }
385    }
386   
387  138 if (bootstrapArgs.contains(Arg.HELP)
388    || bootstrapArgs.contains(Arg.VERSION))
389    {
390  0 QUIET = true;
391    }
392    }
393   
394    // set individual session preferences
395  138 if (bootstrapArgs.contains(Arg.P))
396    {
397  0 for (String kev : bootstrapArgs.getValueList(Arg.P))
398    {
399  0 if (kev == null)
400    {
401  0 continue;
402    }
403  0 int equalsIndex = kev.indexOf(ArgParser.EQUALS);
404  0 if (equalsIndex > -1)
405    {
406  0 String key = kev.substring(0, equalsIndex);
407  0 String val = kev.substring(equalsIndex + 1);
408  0 Cache.setSessionProperty(key, val);
409    }
410    }
411    }
412   
413    // Move any new getdown-launcher-new.jar into place over old
414    // getdown-launcher.jar
415  138 final String appdirString = System
416    .getProperty("launcher.appdir") != null
417    ? System.getProperty("launcher.appdir")
418    :
419    // maybe an old install4j launch
420    System.getProperty("getdownappdir");
421  138 if (appdirString != null && appdirString.length() > 0)
422    {
423  0 Console.errPrintln("launcher.appdir property: " + appdirString);
424  0 new Thread()
425    {
426   
 
427  0 toggle @Override
428    public void run()
429    {
430  0 GetdownLauncherUpdate.main(new String[] { appdirString });
431    }
432    }.start();
433    }
434    else
435    {
436  138 Console.errPrintln("launcher.appdir property not found");
437    }
438   
439  138 if ((usingLogfile || !quiet()) || !bootstrapArgs.outputToStdout()
440    || bootstrapArgs.contains(Arg.VERSION))
441    {
442  138 if (usingLogfile)
443    {
444  0 Console.outPrintln("-------");
445    }
446  138 Console.outPrint(Cache.getVersionDetailsForConsole());
447  138 if (usingLogfile)
448    {
449  0 Console.outPrintln("-------");
450    }
451    }
452   
453  138 if (Platform.isLinux() && LaunchUtils.getJavaVersion() < 11)
454    {
455  0 System.setProperty("flatlaf.uiScale", "1");
456    }
457   
458    // get bootstrap properties (mainly for the logger level)
459  138 Properties bootstrapProperties = Cache
460    .bootstrapProperties(bootstrapArgs.getValue(Arg.PROPS));
461   
462    // report Jalview version
463  138 Cache.getInstance().loadBuildProperties(
464    !quiet() || bootstrapArgs.contains(Arg.VERSION));
465   
466    // stop now if only after --version
467  138 if (bootstrapArgs.contains(Arg.VERSION))
468    {
469  0 Jalview.exit(null, ExitCode.OK);
470    }
471   
472    // old ArgsParser
473  138 ArgsParser aparser = new ArgsParser(args);
474   
475    // old
476  138 boolean headless = false;
477    // new
478  138 boolean headlessArg = false;
479   
480  138 try
481    {
482  138 String logLevel = null;
483  138 if (bootstrapArgs.contains(Arg.TRACE))
484    {
485  0 logLevel = "TRACE";
486    }
487  138 else if (bootstrapArgs.contains(Arg.DEBUG))
488    {
489  23 logLevel = bootstrapArgs.getBoolean(Arg.DEBUG) ? "DEBUG" : "INFO";
490    }
491  138 if (logLevel == null && !(bootstrapProperties == null))
492    {
493  115 logLevel = bootstrapProperties.getProperty(Cache.JALVIEWLOGLEVEL);
494    }
495  138 Console.initLogger(logLevel);
496    } catch (NoClassDefFoundError error)
497    {
498  0 error.printStackTrace();
499  0 String message = "\nEssential logging libraries not found."
500    + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview";
501  0 Jalview.exit(message, ExitCode.OK);
502    }
503   
504  138 if (!Platform.isJS())
505    {
506    // register SIGTERM listener
507  138 Runtime.getRuntime().addShutdownHook(new Thread()
508    {
 
509  95 toggle @Override
510    public void run()
511    {
512  95 Console.debug("Running shutdown hook");
513  95 QuitHandler.startForceQuit();
514  93 boolean closeExternal = Cache
515    .getDefault("DEFAULT_CLOSE_EXTERNAL_VIEWERS", false)
516    || Cache.getDefault("ALWAYS_CLOSE_EXTERNAL_VIEWERS",
517    false);
518  93 StructureViewerBase.setQuitClose(closeExternal);
519  89 if (desktop != null)
520    {
521  38 for (JInternalFrame frame : Desktop.getInstance()
522    .getAllFrames())
523    {
524  34 if (frame instanceof StructureViewerBase)
525    {
526  1 ((StructureViewerBase) frame).closeViewer(closeExternal);
527    }
528    }
529    }
530   
531  88 if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT)
532    {
533    // Got to here by a SIGTERM signal.
534    // Note we will not actually cancel the quit from here -- it's too
535    // late -- but we can wait for saving files and close external
536    // viewers
537    // if configured.
538    // Close viewers/Leave viewers open
539  0 Console.debug("Checking for saving files");
540  0 QuitHandler.getQuitResponse(false);
541    }
542    else
543    {
544  88 Console.debug("Nothing more to do");
545    }
546  88 Console.debug("Exiting, bye!");
547    // shutdownHook cannot be cancelled, JVM will now halt
548    }
549    });
550    }
551   
552  138 String usrPropsFile = bootstrapArgs.contains(Arg.PROPS)
553    ? bootstrapArgs.getValue(Arg.PROPS)
554    : aparser.getValue("props");
555    // if usrPropsFile == null, loadProperties will use the Channel
556    // preferences.file
557  138 Cache.loadProperties(usrPropsFile);
558  138 if (usrPropsFile != null)
559    {
560  48 Console.outPrintln(
561    "CMD [-props " + usrPropsFile + "] executed successfully!");
562  48 testoutput(bootstrapArgs, Arg.PROPS,
563    "test/jalview/bin/testProps.jvprops", usrPropsFile);
564    }
565   
566    // --argfile=... -- OVERRIDES ALL NON-BOOTSTRAP ARGS
567  138 if (bootstrapArgs.contains(Arg.ARGFILE))
568    {
569  8 argparser = ArgParser.parseArgFiles(
570    bootstrapArgs.getValueList(Arg.ARGFILE),
571    bootstrapArgs.getBoolean(Arg.INITSUBSTITUTIONS),
572    bootstrapArgs);
573    }
574    else
575    {
576  130 argparser = new ArgParser(args,
577    bootstrapArgs.getBoolean(Arg.INITSUBSTITUTIONS),
578    bootstrapArgs);
579    }
580   
581  138 boolean allowServices = true;
582   
583  138 if (isJS)
584    {
585  0 j2sAppletID = Platform.getAppID(null);
586  0 Preferences.setAppletDefaults();
587  0 Cache.loadProperties(usrPropsFile); // again, because we
588    // might be changing defaults here?
589  0 appletResourcePath = (String) aparser.getAppletValue("resourcepath",
590    null, true);
591    }
592    else
593    /**
594    * Java only
595    *
596    * @j2sIgnore
597    */
598    {
599  138 if (bootstrapArgs.contains(Arg.HELP))
600    {
601  0 List<Map.Entry<Type, String>> helpArgs = bootstrapArgs
602    .getList(Arg.HELP);
603  0 Console.outPrintln(Arg.usage(helpArgs.stream().map(e -> e.getKey())
604    .collect(Collectors.toList())));
605  0 Jalview.exit(null, ExitCode.OK);
606    }
607  138 if (aparser.contains("help") || aparser.contains("h"))
608    {
609    /*
610    * Now using new usage statement.
611    showUsage();
612    */
613  0 Console.outPrintln(Arg.usage());
614  0 Jalview.exit(null, ExitCode.OK);
615    }
616   
617    // new CLI
618  138 headlessArg = bootstrapArgs.isHeadless();
619  138 if (headlessArg)
620    {
621  27 System.setProperty("java.awt.headless", "true");
622    }
623    // old CLI
624    // BH note: Only -nodisplay is official; others are deprecated?
625  138 if (aparser.contains("nodisplay") || aparser.contains("nogui")
626    || aparser.contains("headless")
627    || GraphicsEnvironment.isHeadless())
628    {
629  39 if (!isJS)
630    {
631    // BH Definitely not a good idea in JavaScript;
632    // probably should not be here for Java, either.
633  39 System.setProperty("java.awt.headless", "true");
634    }
635  39 headless = true;
636    }
637    // anything else!
638   
639    // allow https handshakes to download intermediate certs if necessary
640  138 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
641  138 String jabawsUrl = bootstrapArgs.getValue(Arg.JABAWS);
642  138 if (jabawsUrl == null)
643  137 jabawsUrl = aparser.getValue(ArgsParser.JABAWS);
644  138 allowServices = !("none".equals(jabawsUrl));
645  138 if (allowServices && jabawsUrl != null)
646    {
647  2 try
648    {
649  2 Jws2Discoverer.getInstance().setPreferredUrl(jabawsUrl);
650  2 Console.outPrintln(
651    "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
652  2 testoutput(bootstrapArgs, Arg.JABAWS,
653    "http://www.compbio.dundee.ac.uk/jabaws", jabawsUrl);
654    } catch (MalformedURLException e)
655    {
656  0 jalview.bin.Console.errPrintln(
657    "Invalid jabaws parameter: " + jabawsUrl + " ignored");
658    }
659    }
660    }
661   
662  138 List<String> setprops = new ArrayList<>();
663  138 if (bootstrapArgs.contains(Arg.SETPROP))
664    {
665  0 setprops = bootstrapArgs.getValueList(Arg.SETPROP);
666    }
667    else
668    {
669  138 String sp = aparser.getValue("setprop");
670  138 while (sp != null)
671    {
672  0 setprops.add(sp);
673  0 sp = aparser.getValue("setprop");
674    }
675    }
676  138 for (String setprop : setprops)
677    {
678  0 int p = setprop.indexOf('=');
679  0 if (p == -1)
680    {
681  0 jalview.bin.Console.errPrintln(
682    "Ignoring invalid setprop argument : " + setprop);
683    }
684    else
685    {
686  0 jalview.bin.Console
687    .errPrintln("Executing setprop argument: " + setprop);
688  0 if (isJS)
689    {
690  0 Cache.setProperty(setprop.substring(0, p),
691    setprop.substring(p + 1));
692    }
693    }
694    }
695  138 if (System.getProperty("java.awt.headless") != null
696    && System.getProperty("java.awt.headless").equals("true"))
697    {
698  44 headless = true;
699    }
700  138 System.setProperty("http.agent", UserAgent.getUserAgent());
701   
702    // Initialise the logger
703  138 try
704    {
705  138 Console.initLogger();
706    } catch (NoClassDefFoundError error)
707    {
708  0 error.printStackTrace();
709  0 String message = "\nEssential logging libraries not found."
710    + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview";
711  0 Jalview.exit(message, ExitCode.NO_LOGGING);
712    }
713  138 desktop = null;
714   
715  138 if (!(headless || headlessArg))
716    {
717  94 setLookAndFeel();
718    }
719   
720    /*
721    * configure 'full' SO model if preferences say to, else use the default (full SO)
722    * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
723    */
724  137 boolean soDefault = !isJS;
725  137 if (Cache.getDefault("USE_FULL_SO", soDefault))
726    {
727  137 SequenceOntologyFactory.setSequenceOntology(new SequenceOntology());
728    }
729   
730  137 if (!(headless || headlessArg))
731    {
732  93 Desktop.nosplash = "false".equals(bootstrapArgs.getValue(Arg.SPLASH))
733    || aparser.contains("nosplash")
734    || Cache.getDefault("SPLASH", "true").equals("false");
735  93 desktop = Desktop.getInstance();
736  93 desktop.setInBatchMode(true); // indicate we are starting up
737   
738  93 mixedCliWarning();
739   
740  93 try
741    {
742  93 JalviewTaskbar.setTaskbar(this);
743    } catch (Exception e)
744    {
745  0 Console.info("Cannot set Taskbar");
746  0 Console.error(e.getMessage());
747    // e.printStackTrace();
748    } catch (Throwable t)
749    {
750  0 Console.info("Cannot set Taskbar");
751  0 Console.error(t.getMessage());
752    // t.printStackTrace();
753    }
754   
755    // set Proxy settings before all the internet calls
756  93 Cache.setProxyPropertiesFromPreferences();
757   
758  93 desktop.setVisible(true);
759   
760  93 if (isJS)
761    {
762  0 Cache.setProperty("SHOW_JWS2_SERVICES", "false");
763    }
764  93 if (allowServices && !aparser.contains("nowebservicediscovery"))
765    {
766  93 desktop.startServiceDiscovery();
767    }
768   
769  93 if (!isJS)
770    /**
771    * Java only
772    *
773    * @j2sIgnore
774    */
775    {
776   
777  93 String appName = ChannelProperties.getProperty("app_name");
778   
779    /**
780    * Check to see that the JVM version being run is suitable for the Java
781    * version this Jalview was compiled for. Popup a warning if not.
782    */
783  93 if (!LaunchUtils.checkJavaVersion())
784    {
785  0 Console.warn("The Java version being used (Java "
786    + LaunchUtils.getJavaVersion()
787    + ") may lead to problems. This installation of "
788    + appName + " should be used with Java "
789    + LaunchUtils.getJavaCompileVersion() + ".");
790   
791  0 if (!LaunchUtils
792    .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
793    {
794  0 Object[] options = {
795    MessageManager.getString("label.continue") };
796  0 JOptionPane.showOptionDialog(null,
797    MessageManager.formatMessage(
798    "warning.wrong_jvm_version_message",
799    LaunchUtils.getJavaVersion(),
800    LaunchUtils.getJavaCompileVersion()),
801    MessageManager
802    .getString("warning.wrong_jvm_version_title"),
803    JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
804    null, options, options[0]);
805    }
806    }
807   
808    /**
809    * Check to see if we've been launched from the installer volume
810    * (macOS).
811    */
812  93 String installerappdirString = System
813    .getProperty("installer.appdir");
814  93 if (Platform.isMac() && installerappdirString != null
815    && installerappdirString.startsWith("/Volumes/"))
816    {
817  0 Console.warn("You appear to be running " + appName
818    + " from the Installer volume. Please drag and drop the "
819    + appName + " icon into the Applications folder.");
820   
821  0 Object[] options = { MessageManager.getString("action.quit") };
822  0 JOptionPane.showOptionDialog(null, MessageManager.formatMessage(
823    "warning.running_from_installer_volume_message", appName),
824    MessageManager.getString(
825    "warning.running_from_installer_volume_title"),
826    JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
827    null, options, options[0]);
828  0 quit();
829    }
830   
831  93 boolean webservicediscovery = bootstrapArgs
832    .getBoolean(Arg.WEBSERVICEDISCOVERY);
833  93 if (aparser.contains("nowebservicediscovery"))
834  0 webservicediscovery = false;
835  93 if (webservicediscovery)
836    {
837  73 desktop.startServiceDiscovery();
838    }
839    else
840    {
841  20 testoutput(argparser, Arg.WEBSERVICEDISCOVERY);
842    }
843   
844  93 boolean usagestats = !bootstrapArgs.getBoolean(Arg.NOUSAGESTATS);
845  93 if (aparser.contains("nousagestats"))
846  1 usagestats = false;
847  93 if (usagestats)
848    {
849  87 startUsageStats(desktop);
850  87 testoutput(argparser, Arg.NOUSAGESTATS);
851    }
852    else
853    {
854  6 Console.outPrintln("CMD [-nousagestats] executed successfully!");
855  6 testoutput(argparser, Arg.NOUSAGESTATS);
856    }
857   
858  93 boolean questionnaire = bootstrapArgs.getBoolean(Arg.QUESTIONNAIRE);
859  93 if (aparser.contains("noquestionnaire"))
860  1 questionnaire = false;
861  93 if (questionnaire)
862    {
863  85 String url = aparser.getValue("questionnaire");
864  85 if (url != null)
865    {
866    // Start the desktop questionnaire prompter with the specified
867    // questionnaire
868  0 Console.debug("Starting questionnaire url at " + url);
869  0 desktop.checkForQuestionnaire(url);
870  0 Console.outPrintln("CMD questionnaire[-" + url
871    + "] executed successfully!");
872    }
873    else
874    {
875  85 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
876    {
877    // Start the desktop questionnaire prompter with the specified
878    // questionnaire
879    // String defurl =
880    // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
881    // //
882  39 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
883  39 Console.debug(
884    "Starting questionnaire with default url: " + defurl);
885  39 desktop.checkForQuestionnaire(defurl);
886    }
887    }
888    }
889    else
890    {
891  8 Console.outPrintln(
892    "CMD [-noquestionnaire] executed successfully!");
893  8 testoutput(argparser, Arg.QUESTIONNAIRE);
894    }
895   
896  93 if ((!aparser.contains("nonews")
897    && Cache.getProperty("NONEWS") == null
898    && !"false".equals(bootstrapArgs.getValue(Arg.NEWS)))
899    || "true".equals(bootstrapArgs.getValue(Arg.NEWS)))
900    {
901  42 desktop.checkForNews();
902    }
903   
904  93 if (!aparser.contains("nohtmltemplates")
905    && Cache.getProperty("NOHTMLTEMPLATES") == null)
906    {
907  93 BioJsHTMLOutput.updateBioJS();
908    }
909    }
910    }
911    else
912    {
913   
914  44 if (getArgParser().isMixedStyle())
915    {
916  0 String warning = MessageManager.formatMessage(
917    "warning.using_mixed_command_line_arguments",
918    getArgParser().getMixedExamples());
919  0 Console.warn(warning);
920  0 Jalview.exit(
921    "Exiting due to mixed old and new command line arguments",
922    ExitCode.INVALID_ARGUMENT);
923    }
924  44 if (getArgParser().isOldStyle())
925    {
926  17 String warning = MessageManager
927    .getString("warning.using_old_command_line_arguments")
928    .replace("\n", " ")
929    + "https://www.jalview.org/help/html/features/commandline.html";
930  17 Console.warn(warning);
931    }
932   
933    }
934   
935    // Run Commands from cli
936  137 cmds = new Commands(desktop, argparser, headlessArg);
937  137 cmds.processArgs();
938  132 boolean commandsSuccess = cmds.argsWereParsed();
939   
940  132 if (commandsSuccess)
941    {
942  79 if (headlessArg)
943    {
944  27 if (argparser.getBoolean(Arg.NOQUIT))
945    {
946  1 Console.warn(
947    "Completed " + Arg.HEADLESS.getName() + " commands, but "
948    + Arg.NOQUIT + " is set so not quitting!");
949    }
950    else
951    {
952  26 Jalview.exit("Successfully completed commands in headless mode",
953    ExitCode.OK);
954    }
955    }
956  53 Console.info("Successfully completed commands");
957    }
958    else
959    {
960  53 if (headlessArg)
961    {
962  0 Jalview.exit("Error when running Commands in headless mode",
963    ExitCode.ERROR_RUNNING_COMMANDS);
964    }
965  53 Console.warn("Error when running commands");
966    }
967   
968    // Check if JVM and compile version might cause problems and log if it
969    // might.
970  106 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
971    {
972  0 Console.warn("The Java version being used (Java "
973    + LaunchUtils.getJavaVersion()
974    + ") may lead to problems. This installation of Jalview should be used with Java "
975    + LaunchUtils.getJavaCompileVersion() + ".");
976    }
977   
978    // TODO JAL-4107 - integrate old-style 2.12 and new style 2.11 args handling
979    // !
980  106 parseArguments(aparser, true, commandsSuccess);
981   
982  87 cliWarning();
983    }
984   
985    /**
986    * Parse all command-line String[] arguments as well as all JavaScript-derived
987    * parameters from Info.
988    *
989    * We allow for this method to be run from JavaScript. Basically allowing
990    * simple scripting.
991    *
992    * @param aparser
993    * @param isStartup
994    */
 
995  0 toggle public void parseArguments(ArgsParser aparser, boolean isStartup)
996    {
997    // TODO: JAL-4107 - @bsoares - need to reconcile JS calling and CLI calling
998    // of --args
999   
1000  0 parseArguments(aparser, isStartup, true); // allow call from JS which does
1001    // not result in fileloading ops
1002    }
1003   
 
1004  106 toggle public void parseArguments(ArgsParser aparser, boolean isStartup,
1005    boolean commandsSuccess)
1006    {
1007  106 String groovyscript = null; // script to execute after all loading is
1008  106 boolean isJS = Platform.isJS();
1009  106 if (!isJS)
1010    /** @j2sIgnore */
1011    {
1012    // Move any new getdown-launcher-new.jar into place over old
1013    // getdown-launcher.jar
1014  106 String appdirString = System.getProperty("getdownappdir");
1015  106 if (appdirString != null && appdirString.length() > 0)
1016    {
1017  0 final File appdir = new File(appdirString);
1018  0 new Thread()
1019    {
 
1020  0 toggle @Override
1021    public void run()
1022    {
1023  0 LaunchUtil.upgradeGetdown(
1024    new File(appdir, "getdown-launcher-old.jar"),
1025    new File(appdir, "getdown-launcher.jar"),
1026    new File(appdir, "getdown-launcher-new.jar"));
1027    }
1028    }.start();
1029    }
1030    }
1031   
1032  106 String file = null, data = null;
1033   
1034  106 FileFormatI format = null;
1035   
1036  106 DataSourceType protocol = null;
1037   
1038  106 FileLoader fileLoader = new FileLoader(!headless);
1039   
1040  106 groovyscript = aparser.getValue("groovy", true);
1041  106 file = aparser.getValue("open", true);
1042   
1043  106 if (!isJS && file == null && desktop == null && !commandsSuccess)
1044    {
1045  0 Jalview.exit("No files to open!", ExitCode.NO_FILES);
1046    }
1047  106 setDisplayParameters(aparser);
1048   
1049    // time to open a file.
1050  106 long progress = -1;
1051    // Finally, deal with the remaining input data.
1052  106 AlignFrame af = null;
1053   
1054  106 JalviewJSApp jsApp = (isJS ? new JalviewJSApp(this, aparser) : null);
1055   
1056  106 if (file == null)
1057    {
1058  88 if (isJS)
1059    {
1060    // JalviewJS allows sequence1 sequence2 ....
1061   
1062    }
1063    }
1064   
1065  106 if (file != null)
1066    {
1067   
1068  18 if (!(headless || isHeadlessMode()))
1069    {
1070  1 desktop.setProgressBar(
1071    MessageManager
1072    .getString("status.processing_commandline_args"),
1073    progress = System.currentTimeMillis());
1074    }
1075   
1076  18 Console.outPrintln("CMD [-open " + file + "] executed successfully!");
1077   
1078  18 if (!Platform.isJS())
1079    /**
1080    * ignore in JavaScript -- can't just file existence - could load it?
1081    *
1082    * @j2sIgnore
1083    */
1084    {
1085  18 if (!HttpUtils.startsWithHttpOrHttps(file))
1086    {
1087  18 if (!(new File(file)).exists())
1088    {
1089  0 if (headless)
1090    {
1091  0 Jalview.exit(
1092    "Can't find file '" + file + "' in headless mode",
1093    ExitCode.FILE_NOT_FOUND);
1094    }
1095  0 Console.warn("Can't find file'" + file + "'");
1096    }
1097    }
1098    }
1099   
1100    // JS Only argument to provide a format parameter to specify what format
1101    // to use
1102  18 String fileFormat = (isJS
1103    ? (String) aparser.getAppletValue("format", null, true)
1104    : null);
1105   
1106  18 protocol = AppletFormatAdapter.checkProtocol(file);
1107   
1108  18 try
1109    {
1110  18 format = (fileFormat != null
1111    ? FileFormats.getInstance().forName(fileFormat)
1112    : null);
1113  18 if (format == null)
1114    {
1115  18 format = new IdentifyFile().identify(file, protocol);
1116    }
1117    } catch (FileNotFoundException e)
1118    {
1119  0 Console.error("File at '" + file + "' not found", e);
1120    } catch (FileFormatException e)
1121    {
1122  0 Console.error("File '" + file + "' format not recognised", e);
1123    }
1124   
1125  18 af = new FileLoader(!headless).LoadFileWaitTillLoaded(file, protocol,
1126    format);
1127  18 if (af == null)
1128    {
1129  0 Console.outPrintln("jalview error - AlignFrame was not created");
1130    }
1131    else
1132    {
1133   
1134    // JalviewLite interface for JavaScript allows second file open
1135  18 String file2 = aparser.getValue(ArgsParser.OPEN2, true);
1136  18 if (file2 != null)
1137    {
1138  0 protocol = AppletFormatAdapter.checkProtocol(file2);
1139  0 try
1140    {
1141  0 format = new IdentifyFile().identify(file2, protocol);
1142    } catch (FileNotFoundException e)
1143    {
1144  0 Console.error("File at '" + file2 + "' not found", e);
1145    } catch (FileFormatException e)
1146    {
1147  0 Console.error("File '" + file2 + "' format not recognised", e);
1148    }
1149  0 AlignFrame af2 = new FileLoader(!headless)
1150    .LoadFileWaitTillLoaded(file2, protocol, format);
1151  0 if (af2 == null)
1152    {
1153  0 Console.outPrintln("error");
1154    }
1155    else
1156    {
1157  0 AlignViewport.openLinkedAlignmentAs(af,
1158    af.getViewport().getAlignment(),
1159    af2.getViewport().getAlignment(), "",
1160    AlignViewport.SPLIT_FRAME);
1161  0 Console.outPrintln(
1162    "CMD [-open2 " + file2 + "] executed successfully!");
1163    }
1164    }
1165    // af is loaded - so set it as current frame
1166  18 setCurrentAlignFrame(af);
1167   
1168  18 setFrameDependentProperties(aparser, af);
1169   
1170  18 if (isJS)
1171    {
1172  0 jsApp.initFromParams(af);
1173    }
1174    else
1175    /**
1176    * Java only
1177    *
1178    * @j2sIgnore
1179    */
1180    {
1181  18 if (groovyscript != null)
1182    {
1183    // Execute the groovy script after we've done all the rendering
1184    // stuff
1185    // and before any images or figures are generated.
1186  0 Console.outPrintln("Executing script " + groovyscript);
1187  0 executeGroovyScript(groovyscript, af);
1188  0 Console.outPrintln("CMD groovy[" + groovyscript
1189    + "] executed successfully!");
1190  0 groovyscript = null;
1191    }
1192    }
1193  18 if (!isJS || !isStartup)
1194    {
1195  18 createOutputFiles(aparser, format);
1196    }
1197    }
1198    }
1199    // extract groovy arguments before anything else.
1200    // Once all other stuff is done, execute any groovy scripts (in order)
1201  105 if (!isJS && (headless || isHeadlessMode()))
1202    {
1203    // TODO JAL-4107 - why doesn't Jalview.exit() do this ?
1204  18 if (af != null)
1205    {
1206  17 af.getViewport().getCalcManager().shutdown();
1207    }
1208  18 Jalview.exit("All done.", ExitCode.OK);
1209    }
1210   
1211  87 AlignFrame startUpAlframe = null;
1212    // We'll only open the default file if the desktop is visible.
1213    // And the user
1214    // ////////////////////
1215   
1216  87 if (!Platform.isJS() && !headless && file == null
1217    && Cache.getDefault("SHOW_STARTUP_FILE", true)
1218    && !cmds.commandArgsProvided()
1219    && !bootstrapArgs.getBoolean(Arg.NOSTARTUPFILE))
1220    // don't open the startup file if command line args have been processed
1221    // (&& !Commands.commandArgsProvided())
1222    /**
1223    * Java only
1224    *
1225    * @j2sIgnore
1226    */
1227    {
1228  0 file = Cache.getDefault("STARTUP_FILE",
1229    Cache.getDefault("www.jalview.org", "https://www.jalview.org")
1230    + "/examples/exampleFile_2_7.jvp");
1231  0 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
1232    || file.equals(
1233    "http://www.jalview.org/examples/exampleFile_2_7.jar"))
1234    {
1235  0 file.replace("http:", "https:");
1236    // hardwire upgrade of the startup file
1237  0 file.replace("_2_3", "_2_7");
1238  0 file.replace("2_7.jar", "2_7.jvp");
1239    // and remove the stale setting
1240  0 Cache.removeProperty("STARTUP_FILE");
1241    }
1242   
1243  0 protocol = AppletFormatAdapter.checkProtocol(file);
1244   
1245  0 if (file.endsWith(".jar"))
1246    {
1247  0 format = FileFormat.Jalview;
1248    }
1249    else
1250    {
1251  0 try
1252    {
1253  0 format = new IdentifyFile().identify(file, protocol);
1254    } catch (FileNotFoundException e)
1255    {
1256  0 Console.error("File at '" + file + "' not found", e);
1257    } catch (FileFormatException e)
1258    {
1259  0 Console.error("File '" + file + "' format not recognised", e);
1260    }
1261    }
1262   
1263  0 startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
1264    format);
1265    // don't ask to save when quitting if only the startup file has been
1266    // opened
1267  0 Console.debug("Resetting up-to-date flag for startup file");
1268  0 startUpAlframe.getViewport().setSavedUpToDate(true);
1269    // extract groovy arguments before anything else.
1270    }
1271  87 if (!isJS && groovyscript != null)
1272    {
1273  0 if (Cache.groovyJarsPresent())
1274    {
1275    // TODO: DECIDE IF THIS SECOND PASS AT GROOVY EXECUTION IS STILL
1276    // REQUIRED !!
1277  0 Console.outPrintln("Executing script " + groovyscript);
1278  0 executeGroovyScript(groovyscript, af);
1279  0 Console.outPrintln(
1280    "CMD groovy[" + groovyscript + "] executed successfully!");
1281   
1282    }
1283    else
1284    {
1285  0 Console.errPrintln(
1286    "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
1287    + groovyscript);
1288    }
1289    }
1290   
1291    // and finally, turn off batch mode indicator - if the desktop still
1292    // exists
1293  87 if (desktop != null)
1294    {
1295  87 if (progress != -1)
1296    {
1297  0 desktop.setProgressBar(null, progress);
1298    }
1299  87 desktop.setInBatchMode(false);
1300    }
1301   
1302  87 if (jsApp != null)
1303    {
1304  0 jsApp.callInitCallback();
1305    }
1306    }
1307   
1308    /**
1309    * Set general display parameters irrespective of file loading or
1310    * headlessness.
1311    *
1312    * @param aparser
1313    */
 
1314  106 toggle private void setDisplayParameters(ArgsParser aparser)
1315    {
1316  106 if (aparser.contains(ArgsParser.NOMENUBAR))
1317    {
1318  0 noMenuBar = true;
1319  0 Console.outPrintln("CMD [nomenu] executed successfully!");
1320    }
1321   
1322  106 if (aparser.contains(ArgsParser.NOSTATUS))
1323    {
1324  0 noStatus = true;
1325  0 Console.outPrintln("CMD [nostatus] executed successfully!");
1326    }
1327   
1328  106 if (aparser.contains(ArgsParser.NOANNOTATION)
1329    || aparser.contains(ArgsParser.NOANNOTATION2))
1330    {
1331  0 noAnnotation = true;
1332  0 Console.outPrintln("CMD no-annotation executed successfully!");
1333    }
1334  106 if (aparser.contains(ArgsParser.NOCALCULATION))
1335    {
1336  0 noCalculation = true;
1337  0 Console.outPrintln("CMD [nocalculation] executed successfully!");
1338    }
1339    }
1340   
 
1341  18 toggle private void setFrameDependentProperties(ArgsParser aparser,
1342    AlignFrame af)
1343    {
1344  18 String data = aparser.getValue(ArgsParser.COLOUR, true);
1345  18 if (data != null)
1346    {
1347  1 data.replaceAll("%20", " ");
1348   
1349  1 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
1350    af.getViewport(), af.getViewport().getAlignment(), data);
1351   
1352  1 if (cs != null)
1353    {
1354  1 Console.outPrintln(
1355    "CMD [-colour " + data + "] executed successfully!");
1356    }
1357  1 af.changeColour(cs);
1358    }
1359   
1360    // Must maintain ability to use the groups flag
1361  18 data = aparser.getValue(ArgsParser.GROUPS, true);
1362  18 if (data != null)
1363    {
1364  0 af.parseFeaturesFile(data, AppletFormatAdapter.checkProtocol(data));
1365    // System.out.println("Added " + data);
1366  0 Console.outPrintln(
1367    "CMD groups[-" + data + "] executed successfully!");
1368    }
1369  18 data = aparser.getValue(ArgsParser.FEATURES, true);
1370  18 if (data != null)
1371    {
1372  1 af.parseFeaturesFile(data, AppletFormatAdapter.checkProtocol(data));
1373    // System.out.println("Added " + data);
1374  1 Console.outPrintln(
1375    "CMD [-features " + data + "] executed successfully!");
1376    }
1377  18 data = aparser.getValue(ArgsParser.ANNOTATIONS, true);
1378  18 if (data != null)
1379    {
1380  1 af.loadJalviewDataFile(data, null, null, null);
1381    // System.out.println("Added " + data);
1382  1 Console.outPrintln(
1383    "CMD [-annotations " + data + "] executed successfully!");
1384    }
1385   
1386    // JavaScript feature
1387   
1388  18 if (aparser.contains(ArgsParser.SHOWOVERVIEW))
1389    {
1390  0 af.overviewMenuItem_actionPerformed(null);
1391  0 Console.outPrintln("CMD [showoverview] executed successfully!");
1392    }
1393   
1394    // set or clear the sortbytree flag.
1395  18 if (aparser.contains(ArgsParser.SORTBYTREE))
1396    {
1397  1 af.getViewport().setSortByTree(true);
1398  1 if (af.getViewport().getSortByTree())
1399    {
1400  1 Console.outPrintln("CMD [-sortbytree] executed successfully!");
1401    }
1402    }
1403   
1404  18 boolean doUpdateAnnotation = false;
1405    /**
1406    * we do this earlier in JalviewJS because of a complication with
1407    * SHOWOVERVIEW
1408    *
1409    * For now, just fixing this in JalviewJS.
1410    *
1411    *
1412    * @j2sIgnore
1413    *
1414    */
1415    {
1416  18 if (noAnnotation)
1417    {
1418  0 af.getViewport().setShowAnnotation(false);
1419  0 if (!af.getViewport().isShowAnnotation())
1420    {
1421  0 doUpdateAnnotation = true;
1422    }
1423    }
1424   
1425    }
1426   
1427  18 if (aparser.contains(ArgsParser.NOSORTBYTREE))
1428    {
1429  1 af.getViewport().setSortByTree(false);
1430  1 if (!af.getViewport().getSortByTree())
1431    {
1432  1 doUpdateAnnotation = true;
1433  1 Console.outPrintln("CMD [-nosortbytree] executed successfully!");
1434    }
1435    }
1436  18 if (doUpdateAnnotation)
1437    { // BH 2019.07.24
1438  1 af.setMenusForViewport();
1439  1 af.alignPanel.updateLayout();
1440    }
1441   
1442  18 data = aparser.getValue(ArgsParser.TREE, true);
1443  18 if (data != null)
1444    {
1445  1 try
1446    {
1447  1 NewickFile nf = new NewickFile(data,
1448    AppletFormatAdapter.checkProtocol(data));
1449  1 af.getViewport()
1450    .setCurrentTree(af.showNewickTree(nf, data).getTree());
1451  1 Console.outPrintln(
1452    "CMD [-tree " + data + "] executed successfully!");
1453    } catch (IOException ex)
1454    {
1455  0 Console.errPrintln("Couldn't add tree " + data);
1456  0 ex.printStackTrace(System.err);
1457    }
1458    }
1459    // JAL-4107 - DELETE THIS TODO ??? NO NEED TO LOAD PDB STRUCTURES ANYMORE
1460    // ??? ALL DONE IN NEW Commands ?
1461    // TODO - load PDB structure(s) to alignment JAL-629
1462    // (associate with identical sequence in alignment, or a specified
1463    // sequence)
1464    //
1465   
1466    }
1467   
1468    /**
1469    * Writes an output file for each format (if any) specified in the
1470    * command-line arguments. Supported formats are currently
1471    * <ul>
1472    * <li>png</li>
1473    * <li>svg</li>
1474    * <li>html</li>
1475    * <li>biojsmsa</li>
1476    * <li>imgMap</li>
1477    * <li>eps</li>
1478    * </ul>
1479    * A format parameter should be followed by a parameter specifying the output
1480    * file name. {@code imgMap} parameters should follow those for the
1481    * corresponding alignment image output.
1482    *
1483    * @param aparser
1484    * @param format
1485    */
 
1486  18 toggle private void createOutputFiles(ArgsParser aparser, FileFormatI format)
1487    {
1488    // logic essentially the same as 2.11.2/2.11.3 but uses a switch instead
1489  18 AlignFrame af = currentAlignFrame;
1490  18 String file = null;
1491  34 while (aparser.getSize() >= 2)
1492    {
1493  16 try
1494    {
1495  16 String outputFormat = aparser.nextValue();
1496  16 File imageFile;
1497  16 file = aparser.nextValue();
1498  16 String fname;
1499  16 switch (outputFormat.toLowerCase(Locale.ROOT))
1500    {
1501  1 case "png":
1502  1 imageFile = new File(file);
1503  1 af.createPNG(imageFile);
1504  1 Console.outPrintln(
1505    "Creating PNG image: " + imageFile.getAbsolutePath());
1506  1 continue;
1507  1 case "svg":
1508  1 imageFile = new File(file);
1509  1 af.createSVG(imageFile);
1510  1 Console.outPrintln(
1511    "Creating SVG image: " + imageFile.getAbsolutePath());
1512  1 continue;
1513  5 case "eps":
1514  5 imageFile = new File(file);
1515  5 Console.outPrintln(
1516    "Creating EPS file: " + imageFile.getAbsolutePath());
1517  5 af.createEPS(imageFile);
1518  5 continue;
1519  0 case "biojsmsa":
1520  0 fname = new File(file).getAbsolutePath();
1521  0 try
1522    {
1523  0 BioJsHTMLOutput.refreshVersionInfo(
1524    BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
1525    } catch (URISyntaxException e)
1526    {
1527  0 Console.errPrintln(Cache.getStackTraceString(e));
1528    }
1529  0 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
1530  0 bjs.exportHTML(fname);
1531  0 Console.outPrintln(
1532    "Creating BioJS MSA Viwer HTML file: " + fname);
1533  0 continue;
1534  1 case "html":
1535  1 fname = new File(file).getAbsolutePath();
1536  1 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
1537  1 htmlSVG.exportHTML(fname);
1538  1 Console.outPrintln("Creating HTML image: " + fname);
1539  1 continue;
1540  0 case "imgmap":
1541  0 imageFile = new File(file);
1542  0 af.alignPanel.makePNGImageMap(imageFile, "unnamed.png");
1543  0 Console.outPrintln(
1544    "Creating image map: " + imageFile.getAbsolutePath());
1545  0 continue;
1546  8 default:
1547    // fall through - try to parse as an alignment data export format
1548  8 FileFormatI outFormat = null;
1549  8 try
1550    {
1551  8 outFormat = FileFormats.getInstance().forName(outputFormat);
1552    } catch (Exception formatP)
1553    {
1554  0 Console.errPrintln(Cache.getStackTraceString(formatP));
1555    }
1556  8 if (outFormat == null)
1557    {
1558  0 Console.outPrintln("Couldn't parse " + outputFormat
1559    + " as a valid Jalview format string.");
1560  0 continue;
1561    }
1562  8 if (!outFormat.isWritable())
1563    {
1564  0 Console.outPrintln(
1565    "This version of Jalview does not support alignment export as "
1566    + outputFormat);
1567  0 continue;
1568    }
1569    // record file as it was passed to Jalview so it is recognisable to
1570    // the CLI
1571    // caller
1572   
1573  8 fname = new File(file).getAbsolutePath();
1574    // JBPNote - yuck - really wish we did have a bean returned from this
1575    // which gave
1576    // success/fail like before !
1577  8 af.saveAlignment(fname, outFormat);
1578  8 if (af.isSaveAlignmentSuccessful())
1579    {
1580  8 Console.outPrintln("Written alignment in " + outputFormat
1581    + " format to " + file);
1582    }
1583    else
1584    {
1585  0 Console.errPrintln("Error writing file " + file + " in "
1586    + outputFormat + " format!!");
1587    }
1588    }
1589    }
1590   
1591    catch (ImageOutputException ioexc)
1592    {
1593  0 Console.outPrintln(
1594    "Unexpected error whilst exporting image to " + file);
1595  0 ioexc.printStackTrace();
1596    }
1597    }
1598    // ??? Should report - 'ignoring' extra args here...
1599  18 while (aparser.getSize() > 0)
1600    {
1601  0 Console.outPrintln("Ignoring extra argument: " + aparser.nextValue());
1602    }
1603   
1604  18 cliWarning();
1605    }
1606   
 
1607  94 toggle private static void setLookAndFeel()
1608    {
1609  94 if (!Platform.isJS())
1610    /**
1611    * Java only
1612    *
1613    * @j2sIgnore
1614    */
1615    {
1616    // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
1617    // "mac" or "flat"
1618    // If not set (or chosen laf fails), use the normal SystemLaF and if on
1619    // Mac,
1620    // try Quaqua/Vaqua.
1621  94 String lafProp = System.getProperty("laf");
1622  94 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
1623  94 String laf = "none";
1624  94 if (lafProp != null)
1625    {
1626  0 laf = lafProp;
1627    }
1628  94 else if (lafSetting != null)
1629    {
1630  0 laf = lafSetting;
1631    }
1632  94 boolean lafSet = false;
1633  94 switch (laf)
1634    {
1635  0 case "crossplatform":
1636  0 lafSet = setCrossPlatformLookAndFeel();
1637  0 if (!lafSet)
1638    {
1639  0 Console.error("Could not set requested laf=" + laf);
1640    }
1641  0 break;
1642  0 case "system":
1643  0 lafSet = setSystemLookAndFeel();
1644  0 if (!lafSet)
1645    {
1646  0 Console.error("Could not set requested laf=" + laf);
1647    }
1648  0 break;
1649  0 case "gtk":
1650  0 lafSet = setGtkLookAndFeel();
1651  0 if (!lafSet)
1652    {
1653  0 Console.error("Could not set requested laf=" + laf);
1654    }
1655  0 break;
1656  0 case "metal":
1657  0 lafSet = setMetalLookAndFeel();
1658  0 if (!lafSet)
1659    {
1660  0 Console.error("Could not set requested laf=" + laf);
1661    }
1662  0 break;
1663  0 case "nimbus":
1664  0 lafSet = setNimbusLookAndFeel();
1665  0 if (!lafSet)
1666    {
1667  0 Console.error("Could not set requested laf=" + laf);
1668    }
1669  0 break;
1670  0 case "flat":
1671  0 lafSet = setFlatLookAndFeel();
1672  0 if (!lafSet)
1673    {
1674  0 Console.error("Could not set requested laf=" + laf);
1675    }
1676  0 break;
1677  0 case "mac":
1678  0 lafSet = setMacLookAndFeel();
1679  0 if (!lafSet)
1680    {
1681  0 Console.error("Could not set requested laf=" + laf);
1682    }
1683  0 break;
1684  94 case "none":
1685  94 break;
1686  0 default:
1687  0 Console.error("Requested laf=" + laf + " not implemented");
1688    }
1689  94 if (!lafSet)
1690    {
1691    // Flatlaf default for everyone!
1692  94 lafSet = setFlatLookAndFeel();
1693  93 if (!lafSet)
1694    {
1695  0 setSystemLookAndFeel();
1696    }
1697  93 if (Platform.isLinux())
1698    {
1699  93 setLinuxLookAndFeel();
1700    }
1701  93 if (Platform.isMac())
1702    {
1703  0 setMacLookAndFeel();
1704    }
1705    }
1706    }
1707    }
1708   
 
1709  0 toggle private static boolean setCrossPlatformLookAndFeel()
1710    {
1711  0 boolean set = false;
1712  0 try
1713    {
1714  0 UIManager.setLookAndFeel(
1715    UIManager.getCrossPlatformLookAndFeelClassName());
1716  0 set = true;
1717    } catch (Exception ex)
1718    {
1719  0 Console.error("Unexpected Look and Feel Exception");
1720  0 Console.error(ex.getMessage());
1721  0 Console.debug(Cache.getStackTraceString(ex));
1722    }
1723  0 return set;
1724    }
1725   
 
1726  0 toggle private static boolean setSystemLookAndFeel()
1727    {
1728  0 boolean set = false;
1729  0 try
1730    {
1731  0 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1732  0 set = true;
1733    } catch (Exception ex)
1734    {
1735  0 Console.error("Unexpected Look and Feel Exception");
1736  0 Console.error(ex.getMessage());
1737  0 Console.debug(Cache.getStackTraceString(ex));
1738    }
1739  0 return set;
1740    }
1741   
 
1742  0 toggle private static boolean setSpecificLookAndFeel(String name,
1743    String className, boolean nameStartsWith)
1744    {
1745  0 boolean set = false;
1746  0 try
1747    {
1748  0 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1749    {
1750  0 if (info.getName() != null && nameStartsWith
1751    ? info.getName().toLowerCase(Locale.ROOT)
1752    .startsWith(name.toLowerCase(Locale.ROOT))
1753    : info.getName().toLowerCase(Locale.ROOT)
1754    .equals(name.toLowerCase(Locale.ROOT)))
1755    {
1756  0 className = info.getClassName();
1757  0 break;
1758    }
1759    }
1760  0 UIManager.setLookAndFeel(className);
1761  0 set = true;
1762    } catch (Exception ex)
1763    {
1764  0 Console.error("Unexpected Look and Feel Exception");
1765  0 Console.error(ex.getMessage());
1766  0 Console.debug(Cache.getStackTraceString(ex));
1767    }
1768  0 return set;
1769    }
1770   
 
1771  0 toggle private static boolean setGtkLookAndFeel()
1772    {
1773  0 return setSpecificLookAndFeel("gtk",
1774    "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1775    }
1776   
 
1777  0 toggle private static boolean setMetalLookAndFeel()
1778    {
1779  0 return setSpecificLookAndFeel("metal",
1780    "javax.swing.plaf.metal.MetalLookAndFeel", false);
1781    }
1782   
 
1783  0 toggle private static boolean setNimbusLookAndFeel()
1784    {
1785  0 return setSpecificLookAndFeel("nimbus",
1786    "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1787    }
1788   
 
1789  187 toggle private static boolean setFlatLookAndFeel()
1790    {
1791  187 boolean set = false;
1792  186 if (SystemInfo.isMacOS)
1793    {
1794  0 try
1795    {
1796  0 UIManager.setLookAndFeel(
1797    "com.formdev.flatlaf.themes.FlatMacLightLaf");
1798  0 set = true;
1799  0 Console.debug("Using FlatMacLightLaf");
1800    } catch (ClassNotFoundException | InstantiationException
1801    | IllegalAccessException | UnsupportedLookAndFeelException e)
1802    {
1803  0 Console.debug("Exception loading FlatLightLaf", e);
1804    }
1805  0 System.setProperty("apple.laf.useScreenMenuBar", "true");
1806  0 System.setProperty("apple.awt.application.name",
1807    ChannelProperties.getProperty("app_name"));
1808  0 System.setProperty("apple.awt.application.appearance", "system");
1809  0 if (SystemInfo.isMacFullWindowContentSupported
1810    && Desktop.getInstance() != null)
1811    {
1812  0 Console.debug("Setting transparent title bar");
1813  0 Desktop.getInstance().getRootPane()
1814    .putClientProperty("apple.awt.fullWindowContent", true);
1815  0 Desktop.getInstance().getRootPane()
1816    .putClientProperty("apple.awt.transparentTitleBar", true);
1817  0 Desktop.getInstance().getRootPane()
1818    .putClientProperty("apple.awt.fullscreenable", true);
1819    }
1820  0 SwingUtilities.invokeLater(() -> {
1821  0 FlatMacLightLaf.setup();
1822    });
1823  0 Console.debug("Using FlatMacLightLaf");
1824  0 set = true;
1825    }
1826  186 if (!set)
1827    {
1828  186 try
1829    {
1830  186 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1831  186 set = true;
1832  186 Console.debug("Using FlatLightLaf");
1833    } catch (ClassNotFoundException | InstantiationException
1834    | IllegalAccessException | UnsupportedLookAndFeelException e)
1835    {
1836  0 Console.debug("Exception loading FlatLightLaf", e);
1837    }
1838    // Windows specific properties here
1839  186 SwingUtilities.invokeLater(() -> {
1840  186 FlatLightLaf.setup();
1841    });
1842  186 Console.debug("Using FlatLightLaf");
1843  186 set = true;
1844    }
1845  0 else if (SystemInfo.isLinux)
1846    {
1847  0 try
1848    {
1849  0 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1850  0 set = true;
1851  0 Console.debug("Using FlatLightLaf");
1852    } catch (ClassNotFoundException | InstantiationException
1853    | IllegalAccessException | UnsupportedLookAndFeelException e)
1854    {
1855  0 Console.debug("Exception loading FlatLightLaf", e);
1856    }
1857    // enable custom window decorations
1858  0 JFrame.setDefaultLookAndFeelDecorated(true);
1859  0 JDialog.setDefaultLookAndFeelDecorated(true);
1860  0 SwingUtilities.invokeLater(() -> {
1861  0 FlatLightLaf.setup();
1862    });
1863  0 Console.debug("Using FlatLightLaf");
1864  0 set = true;
1865    }
1866   
1867  186 if (!set)
1868    {
1869  0 try
1870    {
1871  0 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1872  0 set = true;
1873  0 Console.debug("Using FlatLightLaf");
1874    } catch (ClassNotFoundException | InstantiationException
1875    | IllegalAccessException | UnsupportedLookAndFeelException e)
1876    {
1877  0 Console.debug("Exception loading FlatLightLaf", e);
1878    }
1879    }
1880   
1881  186 if (set)
1882    {
1883  186 UIManager.put("TabbedPane.tabType", "card");
1884  186 UIManager.put("TabbedPane.showTabSeparators", true);
1885  186 UIManager.put("TabbedPane.showContentSeparator", true);
1886    // UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1887  186 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1888  186 UIManager.put("TabbedPane.hasFullBorder", true);
1889  186 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1890  186 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1891  186 UIManager.put("TabbedPane.smoothScrolling", true);
1892  186 UIManager.put("TabbedPane.tabWidthMode", "compact");
1893  186 UIManager.put("TabbedPane.selectedBackground", Color.white);
1894  186 UIManager.put("TabbedPane.background", new Color(236, 236, 236));
1895  186 UIManager.put("TabbedPane.hoverColor", Color.lightGray);
1896    }
1897   
1898  186 Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
1899  186 return set;
1900    }
1901   
 
1902  0 toggle private static boolean setMacLookAndFeel()
1903    {
1904  0 boolean set = false;
1905  0 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1906    ChannelProperties.getProperty("app_name"));
1907  0 System.setProperty("apple.laf.useScreenMenuBar", "true");
1908    /*
1909    * broken native LAFs on (ARM?) macbooks
1910    set = setQuaquaLookAndFeel();
1911    if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1912    .toLowerCase(Locale.ROOT).contains("quaqua"))
1913    {
1914    set = setVaquaLookAndFeel();
1915    }
1916    */
1917  0 set = setFlatLookAndFeel();
1918  0 return set;
1919    }
1920   
 
1921  93 toggle private static boolean setLinuxLookAndFeel()
1922    {
1923  93 boolean set = false;
1924  93 set = setFlatLookAndFeel();
1925  93 if (!set)
1926  0 set = setMetalLookAndFeel();
1927    // avoid GtkLookAndFeel -- not good results especially on HiDPI
1928  93 if (!set)
1929  0 set = setNimbusLookAndFeel();
1930  93 return set;
1931    }
1932   
1933    /*
1934    private static void showUsage()
1935    {
1936    jalview.bin.Console.outPrintln(
1937    "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1938    + "-nodisplay\tRun Jalview without User Interface.\n"
1939    + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1940    + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1941    + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1942    + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1943    + "-features FILE\tUse the given file to mark features on the alignment.\n"
1944    + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1945    + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1946    + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1947    + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1948    + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1949    + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1950    + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1951    + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1952    + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1953    + "-png FILE\tCreate PNG image FILE from alignment.\n"
1954    + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1955    + "-html FILE\tCreate HTML file from alignment.\n"
1956    + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1957    + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1958    + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1959    + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1960    + "-noquestionnaire\tTurn off questionnaire check.\n"
1961    + "-nonews\tTurn off check for Jalview news.\n"
1962    + "-nousagestats\tTurn off analytics tracking for this session.\n"
1963    + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1964    // +
1965    // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1966    // after all other properties files have been read\n\t
1967    // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1968    // passed in correctly)"
1969    + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1970    + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1971    + "-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"
1972    + "-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"
1973    + "-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"
1974    + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1975    }
1976    */
1977   
 
1978  87 toggle private static void startUsageStats(final Desktop desktop)
1979    {
1980    /**
1981    * start a User Config prompt asking if we can log usage statistics.
1982    */
1983  87 PromptUserConfig prompter = new PromptUserConfig(desktop, "USAGESTATS",
1984    MessageManager.getString("prompt.analytics_title"),
1985    MessageManager.getString("prompt.analytics"), new Runnable()
1986    {
 
1987  1 toggle @Override
1988    public void run()
1989    {
1990  1 Console.debug("Initialising analytics for usage stats.");
1991  1 Cache.initAnalytics();
1992  1 Console.debug("Tracking enabled.");
1993    }
1994    }, new Runnable()
1995    {
 
1996  0 toggle @Override
1997    public void run()
1998    {
1999  0 Console.debug("Not enabling analytics.");
2000    }
2001    }, null, true);
2002  87 desktop.addDialogThread(prompter);
2003    }
2004   
2005    /**
2006    * Locate the given string as a file and pass it to the groovy interpreter.
2007    *
2008    * @param groovyscript
2009    * the script to execute
2010    * @param jalviewContext
2011    * the Jalview Desktop object passed in to the groovy binding as the
2012    * 'Jalview' object.
2013    */
 
2014  0 toggle protected void executeGroovyScript(String groovyscript, AlignFrame af)
2015    {
2016    /**
2017    * for scripts contained in files
2018    */
2019  0 File tfile = null;
2020    /**
2021    * script's URI
2022    */
2023  0 URL sfile = null;
2024  0 if (groovyscript.trim().equals("STDIN"))
2025    {
2026    // read from stdin into a tempfile and execute it
2027  0 try
2028    {
2029  0 tfile = File.createTempFile("jalview", "groovy");
2030  0 PrintWriter outfile = new PrintWriter(
2031    new OutputStreamWriter(new FileOutputStream(tfile)));
2032  0 BufferedReader br = new BufferedReader(
2033    new InputStreamReader(System.in));
2034  0 String line = null;
2035  0 while ((line = br.readLine()) != null)
2036    {
2037  0 outfile.write(line + "\n");
2038    }
2039  0 br.close();
2040  0 outfile.flush();
2041  0 outfile.close();
2042   
2043    } catch (Exception ex)
2044    {
2045  0 jalview.bin.Console
2046    .errPrintln("Failed to read from STDIN into tempfile "
2047  0 + ((tfile == null) ? "(tempfile wasn't created)"
2048    : tfile.toString()));
2049  0 ex.printStackTrace();
2050  0 return;
2051    }
2052  0 try
2053    {
2054  0 sfile = tfile.toURI().toURL();
2055    } catch (Exception x)
2056    {
2057  0 jalview.bin.Console.errPrintln(
2058    "Unexpected Malformed URL Exception for temporary file created from STDIN: "
2059    + tfile.toURI());
2060  0 x.printStackTrace();
2061  0 return;
2062    }
2063    }
2064    else
2065    {
2066  0 try
2067    {
2068  0 sfile = new URI(groovyscript).toURL();
2069    } catch (Exception x)
2070    {
2071  0 tfile = new File(groovyscript);
2072  0 if (!tfile.exists())
2073    {
2074  0 jalview.bin.Console.errPrintln(
2075    "File '" + groovyscript + "' does not exist.");
2076  0 return;
2077    }
2078  0 if (!tfile.canRead())
2079    {
2080  0 jalview.bin.Console.errPrintln(
2081    "File '" + groovyscript + "' cannot be read.");
2082  0 return;
2083    }
2084  0 if (tfile.length() < 1)
2085    {
2086  0 jalview.bin.Console
2087    .errPrintln("File '" + groovyscript + "' is empty.");
2088  0 return;
2089    }
2090  0 try
2091    {
2092  0 sfile = tfile.getAbsoluteFile().toURI().toURL();
2093    } catch (Exception ex)
2094    {
2095  0 jalview.bin.Console.errPrintln("Failed to create a file URL for "
2096    + tfile.getAbsoluteFile());
2097  0 return;
2098    }
2099    }
2100    }
2101  0 try
2102    {
2103  0 JalviewObjectI j = new JalviewObject(this);
2104  0 Map<String, java.lang.Object> vbinding = new HashMap<>();
2105  0 vbinding.put(JalviewObjectI.jalviewObjectName, j);
2106  0 vbinding.put(JalviewObjectI.currentAlFrameName,
2107  0 af != null ? af : getCurrentAlignFrame());
2108  0 Binding gbinding = new Binding(vbinding);
2109  0 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
2110  0 gse.run(sfile.toString(), gbinding);
2111  0 if ("STDIN".equals(groovyscript))
2112    {
2113    // delete temp file that we made -
2114    // only if it was successfully executed
2115  0 tfile.delete();
2116    }
2117    } catch (Exception e)
2118    {
2119  0 jalview.bin.Console
2120    .errPrintln("Exception Whilst trying to execute file " + sfile
2121    + " as a groovy script.");
2122  0 e.printStackTrace(System.err);
2123    }
2124    }
2125   
 
2126  36810 toggle public static boolean isHeadlessMode()
2127    {
2128  36810 String isheadless = System.getProperty("java.awt.headless");
2129  36809 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
2130    {
2131  866 return true;
2132    }
2133  35943 return false;
2134    }
2135   
 
2136  0 toggle @Override
2137    public AlignFrame[] getAlignFrames()
2138    {
2139  0 return desktop == null
2140  0 ? getCurrentAlignFrame() != null ? new AlignFrame[]
2141    { getCurrentAlignFrame() } : null
2142    : Desktop.getDesktopAlignFrames();
2143    }
2144   
2145    /**
2146    * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
2147    */
 
2148  0 toggle @Override
2149    public void quit()
2150    {
2151    // System.exit will run the shutdownHook first
2152  0 Jalview.exit("Quitting now. Bye!", ExitCode.OK);
2153    }
2154   
 
2155  0 toggle @Override
2156    public AlignFrame getCurrentAlignFrame()
2157    {
2158  0 return currentAlignFrame;
2159    }
2160   
 
2161  1153 toggle public void setCurrentAlignFrame(AlignFrame af)
2162    {
2163  1153 this.currentAlignFrame = af;
2164    }
2165   
 
2166  341 toggle public Commands getCommands()
2167    {
2168  341 return cmds;
2169    }
2170   
 
2171  45 toggle public static void exit(String message, ExitCode ec)
2172    {
2173  45 int exitcode = ec == ExitCode.OK ? 0 : ec.ordinal() + 1;
2174  45 if (Console.log == null)
2175    {
2176    // Don't start the logger just to exit!
2177  0 if (message != null)
2178    {
2179  0 if (exitcode == 0)
2180    {
2181  0 Console.outPrintln(message);
2182    }
2183    else
2184    {
2185  0 jalview.bin.Console.errPrintln(message);
2186    }
2187    }
2188    }
2189    else
2190    {
2191  45 Console.debug("Using Jalview.exit");
2192  45 if (message != null)
2193    {
2194  45 if (exitcode == 0)
2195    {
2196  45 Console.info(message);
2197    }
2198    else
2199    {
2200  0 Console.error(message);
2201    }
2202    }
2203    }
2204  45 if (exitcode > -1)
2205    {
2206  45 System.exit(exitcode);
2207    }
2208    }
2209   
 
2210    public enum ExitCode
2211    {
2212    // only add new ones to the end of the list (to preserve ordinal values)
2213    OK, FILE_NOT_FOUND, FILE_NOT_READABLE, NO_FILES, INVALID_FORMAT,
2214    INVALID_ARGUMENT, INVALID_VALUE, MIXED_CLI_ARGUMENTS,
2215    ERROR_RUNNING_COMMANDS, NO_LOGGING, GROOVY_ERROR;
2216    }
2217   
2218    /******************************
2219    *
2220    * TEST OUTPUT METHODS
2221    *
2222    * these operate only when Arg.TESTOUTPUT has been passed, and variously check
2223    * if an expected value / arg was set and report it to the test framework.
2224    *
2225    ******************************/
2226    /**
2227    * report string values parsed/processed during tests When the Bootstrap
2228    * argument Arg.TESTOUTPUT is present - reports on debug if given s1 is not
2229    * null and not equals s2, warns if given argument is not set, and calls
2230    * testoutput(true,a,s1,s2) to report processing progress.
2231    *
2232    * @param ap
2233    * - ArgParser handling parsing
2234    * @param a
2235    * - Arg currently being processed
2236    * @param s1
2237    * - expected
2238    * @param s2
2239    */
 
2240  153 toggle protected static void testoutput(ArgParser ap, Arg a, String s1,
2241    String s2)
2242    {
2243  153 BootstrapArgs bsa = ap.getBootstrapArgs();
2244  153 if (!bsa.getBoolean(Arg.TESTOUTPUT))
2245  131 return;
2246  22 if (!((s1 == null && s2 == null) || (s1 != null && s1.equals(s2))))
2247    {
2248  0 Console.debug("testoutput with unmatching values '" + s1 + "' and '"
2249    + s2 + "' for arg " + a.argString());
2250  0 return;
2251    }
2252  22 boolean isset = a.hasOption(Opt.BOOTSTRAP) ? bsa.contains(a)
2253    : ap.isSet(a);
2254  22 if (!isset)
2255    {
2256  0 Console.warn("Arg '" + a.getName() + "' not set at all");
2257  0 return;
2258    }
2259  22 testoutput(true, a, s1, s2);
2260    }
2261   
2262    /**
2263    * report values passed via bootstrap arguments
2264    *
2265    * TODO: significant code duplication with testouput(Argparser...) - move it
2266    */
2267   
 
2268  50 toggle protected static void testoutput(BootstrapArgs bsa, Arg a, String s1,
2269    String s2)
2270    {
2271  50 if (!bsa.getBoolean(Arg.TESTOUTPUT))
2272  48 return;
2273  2 if (!((s1 == null && s2 == null) || (s1 != null && s1.equals(s2))))
2274    {
2275  0 Console.debug("testoutput with unmatching values '" + s1 + "' and '"
2276    + s2 + "' for arg " + a.argString());
2277  0 return;
2278    }
2279  2 if (!a.hasOption(Opt.BOOTSTRAP))
2280    {
2281  0 Console.error("Non-bootstrap Arg '" + a.getName()
2282    + "' given to testoutput(BootstrapArgs bsa, Arg a, String s1, String s2) with only BootstrapArgs");
2283    }
2284  2 if (!bsa.contains(a))
2285    {
2286  0 Console.warn("Arg '" + a.getName() + "' not set at all");
2287  0 return;
2288    }
2289  2 testoutput(true, a, s1, s2);
2290    }
2291   
2292    /**
2293    * conditionally (on @param yes) report that expected value s1 was set during
2294    * CommandsTest tests
2295    */
 
2296  24 toggle private static void testoutput(boolean yes, Arg a, String s1, String s2)
2297    {
2298  24 if (yes && ((s1 == null && s2 == null)
2299    || (s1 != null && s1.equals(s2))))
2300    {
2301  24 Console.outPrintln("[TESTOUTPUT] arg " + a.argString() + "='" + s1
2302    + "' was set");
2303    }
2304    }
2305   
2306    /*
2307    * testoutput for boolean and unary values
2308    */
 
2309  122 toggle protected static void testoutput(ArgParser ap, Arg a)
2310    {
2311  122 if (ap == null)
2312  0 return;
2313  122 BootstrapArgs bsa = ap.getBootstrapArgs();
2314  122 if (bsa == null)
2315  2 return;
2316  120 if (!bsa.getBoolean(Arg.TESTOUTPUT))
2317  117 return;
2318  3 boolean val = a.hasOption(Opt.BOOTSTRAP) ? bsa.getBoolean(a)
2319    : ap.getBoolean(a);
2320  3 boolean isset = a.hasOption(Opt.BOOTSTRAP) ? bsa.contains(a)
2321    : ap.isSet(a);
2322  3 if (!isset)
2323    {
2324  0 Console.warn("Arg '" + a.getName() + "' not set at all");
2325  0 return;
2326    }
2327  3 testoutput(val, a);
2328    }
2329   
 
2330  0 toggle protected static void testoutput(BootstrapArgs bsa, Arg a)
2331    {
2332  0 if (!bsa.getBoolean(Arg.TESTOUTPUT))
2333  0 return;
2334  0 if (!a.hasOption(Opt.BOOTSTRAP))
2335    {
2336  0 Console.warn("Non-bootstrap Arg '" + a.getName()
2337    + "' given to testoutput(BootstrapArgs bsa, Arg a) with only BootstrapArgs");
2338   
2339    }
2340  0 if (!bsa.contains(a))
2341    {
2342  0 Console.warn("Arg '" + a.getName() + "' not set at all");
2343  0 return;
2344    }
2345  0 testoutput(bsa.getBoolean(a), a);
2346    }
2347   
 
2348  3 toggle private static void testoutput(boolean yes, Arg a)
2349    {
2350  3 String message = null;
2351  3 if (a.hasOption(Opt.BOOLEAN))
2352    {
2353  2 message = (yes ? a.argString() : a.negateArgString()) + " was set";
2354    }
2355  1 else if (a.hasOption(Opt.UNARY))
2356    {
2357  1 message = a.argString() + (yes ? " was set" : " was not set");
2358    }
2359  3 Console.outPrintln("[TESTOUTPUT] arg " + message);
2360    }
2361   
 
2362  495 toggle public ArgParser getArgParser()
2363    {
2364  495 return argparser;
2365    }
2366   
 
2367  1410 toggle public BootstrapArgs getBootstrapArgs()
2368    {
2369  1410 return bootstrapArgs;
2370    }
2371   
 
2372  56 toggle public static boolean isBatchMode()
2373    {
2374  56 return instanceExists() && (getInstance().desktop == null
2375    || getInstance().desktop.isInBatchMode());
2376    }
2377   
2378    /**
2379    * Warning about old or mixed command line arguments
2380    */
 
2381  93 toggle private void mixedCliWarning()
2382    {
2383  93 Jalview j = Jalview.getInstance();
2384  93 boolean mixedStyle = j.getArgParser() != null
2385    && j.getArgParser().isMixedStyle();
2386  93 String title = MessageManager.getString("label.command_line_arguments");
2387  93 if (mixedStyle)
2388    {
2389  0 String warning = MessageManager.formatMessage(
2390    "warning.using_mixed_command_line_arguments",
2391    j.getArgParser().getMixedExamples());
2392  0 String quit = MessageManager.getString("action.quit");
2393   
2394  0 Desktop.getInstance().nonBlockingDialog(title, warning, null, quit,
2395    JvOptionPane.WARNING_MESSAGE, false, false, true, 30000);
2396   
2397  0 Jalview.exit(
2398    "Exiting due to mixed old and new command line arguments.",
2399    ExitCode.MIXED_CLI_ARGUMENTS);
2400    }
2401    }
2402   
 
2403  105 toggle private void cliWarning()
2404    {
2405  105 Jalview j = Jalview.getInstance();
2406  105 Commands c = j.getCommands();
2407  105 boolean oldStyle = j.getArgParser() != null
2408    && j.getArgParser().isOldStyle();
2409  105 String title = MessageManager.getString("label.command_line_arguments");
2410  105 if (oldStyle)
2411    {
2412  18 String warning = MessageManager
2413    .getString("warning.using_old_command_line_arguments");
2414  18 String url = "<a href=\"https://www.jalview.org/help/html/features/commandline.html\">https://www.jalview.org/help/html/features/commandline.html</a>";
2415  18 if (Desktop.getInstance() != null)
2416    {
2417  1 String cont = MessageManager.getString("label.continue");
2418   
2419  1 Desktop.getInstance().nonBlockingDialog(title, warning, url, cont,
2420    JvOptionPane.WARNING_MESSAGE, false, true, true, 30000);
2421    }
2422    }
2423  104 if (j.getCommands() != null && j.getCommands().getErrors().size() > 0)
2424    {
2425  0 if (Desktop.getInstance() != null)
2426    {
2427  0 String message = MessageManager
2428    .getString("warning.the_following_errors");
2429  0 String ok = MessageManager.getString("action.ok");
2430  0 int shortest = 60;
2431  0 List<String> errors = j.getCommands().getErrors();
2432  0 for (int i = 0; i < errors.size(); i++)
2433    {
2434  0 shortest = Math.min(shortest, errors.get(i).length());
2435    }
2436  0 Desktop.getInstance().nonBlockingDialog(
2437    Math.max(message.length(), Math.min(60, shortest)),
2438    Math.min(errors.size(), 20), title, message,
2439    j.getCommands().errorsToString(), ok,
2440    JvOptionPane.WARNING_MESSAGE, true, false, true, -1);
2441    }
2442    }
2443    }
2444   
 
2445  0 toggle public void notifyWorker(AlignCalcWorkerI worker, String status)
2446    {
2447    // System.out.println("Jalview worker " + worker.getClass().getSimpleName()
2448    // + " " + status);
2449    }
2450   
2451    private static boolean isInteractive = true;
2452   
 
2453  11 toggle public static boolean isInteractive()
2454    {
2455  11 return isInteractive;
2456    }
2457   
 
2458  0 toggle public static void setInteractive(boolean tf)
2459    {
2460  0 isInteractive = tf;
2461    }
2462    }