2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
23 import java.awt.Color;
24 import java.io.BufferedReader;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.io.OutputStream;
30 import java.io.OutputStreamWriter;
31 import java.io.PrintStream;
32 import java.io.PrintWriter;
33 import java.net.MalformedURLException;
35 import java.net.URISyntaxException;
37 import java.security.AllPermission;
38 import java.security.CodeSource;
39 import java.security.PermissionCollection;
40 import java.security.Permissions;
41 import java.security.Policy;
42 import java.util.HashMap;
43 import java.util.Locale;
45 import java.util.Properties;
46 import java.util.Vector;
47 import java.util.logging.ConsoleHandler;
48 import java.util.logging.Level;
49 import java.util.logging.Logger;
51 import javax.swing.JDialog;
52 import javax.swing.JFrame;
53 import javax.swing.JOptionPane;
54 import javax.swing.SwingUtilities;
55 import javax.swing.UIManager;
56 import javax.swing.UIManager.LookAndFeelInfo;
57 import javax.swing.UnsupportedLookAndFeelException;
59 import com.formdev.flatlaf.FlatLightLaf;
60 import com.formdev.flatlaf.themes.FlatMacLightLaf;
61 import com.formdev.flatlaf.util.SystemInfo;
62 import com.threerings.getdown.util.LaunchUtil;
64 //import edu.stanford.ejalbert.launching.IBrowserLaunching;
65 import groovy.lang.Binding;
66 import groovy.util.GroovyScriptEngine;
67 import jalview.bin.ArgParser.Arg;
68 import jalview.bin.ArgParser.BootstrapArgs;
69 import jalview.ext.so.SequenceOntology;
70 import jalview.gui.AlignFrame;
71 import jalview.gui.Desktop;
72 import jalview.gui.PromptUserConfig;
73 import jalview.gui.QuitHandler;
74 import jalview.gui.QuitHandler.QResponse;
75 import jalview.io.AppletFormatAdapter;
76 import jalview.io.BioJsHTMLOutput;
77 import jalview.io.DataSourceType;
78 import jalview.io.FileFormat;
79 import jalview.io.FileFormatException;
80 import jalview.io.FileFormatI;
81 import jalview.io.FileFormats;
82 import jalview.io.FileLoader;
83 import jalview.io.HtmlSvgOutput;
84 import jalview.io.IdentifyFile;
85 import jalview.io.NewickFile;
86 import jalview.io.gff.SequenceOntologyFactory;
87 import jalview.schemes.ColourSchemeI;
88 import jalview.schemes.ColourSchemeProperty;
89 import jalview.util.ChannelProperties;
90 import jalview.util.HttpUtils;
91 import jalview.util.LaunchUtils;
92 import jalview.util.MessageManager;
93 import jalview.util.Platform;
94 import jalview.ws.jws2.Jws2Discoverer;
97 * Main class for Jalview Application <br>
99 * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
100 * jalview.bin.Jalview
102 * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
103 * jalview.bin.Jalview jalview.bin.Jalview
105 * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
106 * embellish '*' to e.g. '*.jar')
109 * @version $Revision$
115 Platform.getURLCommandArguments();
116 Platform.addJ2SDirectDatabaseCall("https://www.jalview.org");
117 Platform.addJ2SDirectDatabaseCall("http://www.jalview.org");
118 Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk");
119 Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk");
123 * singleton instance of this class
125 private static Jalview instance;
127 private Desktop desktop;
129 public static AlignFrame currentAlignFrame;
133 if (!Platform.isJS())
140 // grab all the rights we can for the JVM
141 Policy.setPolicy(new Policy()
144 public PermissionCollection getPermissions(CodeSource codesource)
146 Permissions perms = new Permissions();
147 perms.add(new AllPermission());
152 public void refresh()
160 * keep track of feature fetching tasks.
168 * TODO: generalise to track all jalview events to orchestrate batch processing
172 private int queued = 0;
174 private int running = 0;
176 public FeatureFetcher()
181 public void addFetcher(final AlignFrame af,
182 final Vector<String> dasSources)
184 final long id = System.currentTimeMillis();
186 final FeatureFetcher us = this;
187 new Thread(new Runnable()
199 af.setProgressBar(MessageManager
200 .getString("status.das_features_being_retrived"), id);
201 af.featureSettings_actionPerformed(null);
202 af.setProgressBar(null, id);
211 public synchronized boolean allFinished()
213 return queued == 0 && running == 0;
218 public static Jalview getInstance()
224 * main class for Jalview application
227 * open <em>filename</em>
229 public static void main(String[] args)
231 // setLogging(); // BH - for event debugging in JavaScript
232 instance = new Jalview();
233 instance.doMain(args);
236 private static void logClass(String name)
238 // BH - for event debugging in JavaScript
239 ConsoleHandler consoleHandler = new ConsoleHandler();
240 consoleHandler.setLevel(Level.ALL);
241 Logger logger = Logger.getLogger(name);
242 logger.setLevel(Level.ALL);
243 logger.addHandler(consoleHandler);
246 @SuppressWarnings("unused")
247 private static void setLogging()
255 System.out.println("not in js");
258 // BH - for event debugging in JavaScript (Java mode only)
259 if (!Platform.isJS())
266 Logger.getLogger("").setLevel(Level.ALL);
267 logClass("java.awt.EventDispatchThread");
268 logClass("java.awt.EventQueue");
269 logClass("java.awt.Component");
270 logClass("java.awt.focus.Component");
271 logClass("java.awt.focus.DefaultKeyboardFocusManager");
279 void doMain(String[] args)
282 if (!Platform.isJS())
284 System.setSecurityManager(null);
287 // get args needed before proper ArgParser
288 BootstrapArgs bootstrapArgs = BootstrapArgs.getBootstrapArgs(args);
290 if (!Platform.isJS())
292 // are we being --quiet ?
293 if (bootstrapArgs.contains(Arg.QUIET))
295 OutputStream devNull = new OutputStream()
298 public void write(int b)
303 System.setOut(new PrintStream(devNull));
304 // redirecting stderr not working
305 if (bootstrapArgs.getList(Arg.QUIET).size() > 1)
307 System.setErr(new PrintStream(devNull));
313 .println("Java version: " + System.getProperty("java.version"));
314 System.out.println("Java Home: " + System.getProperty("java.home"));
315 System.out.println(System.getProperty("os.arch") + " "
316 + System.getProperty("os.name") + " "
317 + System.getProperty("os.version"));
319 String val = System.getProperty("sys.install4jVersion");
322 System.out.println("Install4j version: " + val);
324 val = System.getProperty("installer_template_version");
327 System.out.println("Install4j template version: " + val);
329 val = System.getProperty("launcher_version");
332 System.out.println("Launcher version: " + val);
335 if (Platform.isLinux() && LaunchUtils.getJavaVersion() < 11)
337 System.setProperty("flatlaf.uiScale", "1");
340 // get bootstrap properties (mainly for the logger level)
341 Properties bootstrapProperties = Cache
342 .bootstrapProperties(bootstrapArgs.get(Arg.PROPS));
344 // report Jalview version
345 Cache.loadBuildProperties(true);
348 ArgsParser aparser = new ArgsParser(args);
351 boolean headless = false;
353 boolean headlessArg = false;
357 String logLevel = bootstrapArgs.contains(Arg.DEBUG) ? "DEBUG" : null;
358 if (logLevel == null && !(bootstrapProperties == null))
360 logLevel = bootstrapProperties.getProperty(Cache.JALVIEWLOGLEVEL);
362 Console.initLogger(logLevel);
363 } catch (NoClassDefFoundError error)
365 error.printStackTrace();
366 System.out.println("\nEssential logging libraries not found."
367 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
371 // register SIGTERM listener
372 Runtime.getRuntime().addShutdownHook(new Thread()
376 Console.debug("Running shutdown hook");
377 if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT)
379 // Got to here by a SIGTERM signal.
380 // Note we will not actually cancel the quit from here -- it's too
381 // late -- but we can wait for saving files.
382 Console.debug("Checking for saving files");
383 QuitHandler.getQuitResponse(false);
387 Console.debug("Nothing more to do");
389 Console.debug("Exiting, bye!");
390 // shutdownHook cannot be cancelled, JVM will now halt
394 String usrPropsFile = bootstrapArgs.contains(Arg.PROPS)
395 ? bootstrapArgs.get(Arg.PROPS)
396 : aparser.getValue("props");
397 Cache.loadProperties(usrPropsFile);
398 if (usrPropsFile != null)
401 "CMD [-props " + usrPropsFile + "] executed successfully!");
406 // --argfile=... -- OVERRIDES ALL NON-BOOTSTRAP ARGS
407 if (bootstrapArgs.contains(Arg.ARGFILE))
409 argparser = ArgParser
410 .parseArgFiles(bootstrapArgs.getList(Arg.ARGFILE));
414 argparser = new ArgParser(args);
417 if (!Platform.isJS())
424 if (aparser.contains("help") || aparser.contains("h")
425 || argparser.getBool(Arg.HELP))
431 if (bootstrapArgs.contains(Arg.HEADLESS))
433 System.setProperty("java.awt.headless", "true");
435 headlessArg = argparser.getBool(Arg.HEADLESS);
437 if (aparser.contains("nodisplay") || aparser.contains("nogui")
438 || aparser.contains("headless"))
440 System.setProperty("java.awt.headless", "true");
446 // allow https handshakes to download intermediate certs if necessary
447 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
449 final String jabawsUrl = aparser.getValue("jabaws");
450 if (jabawsUrl != null)
454 Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
456 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
457 } catch (MalformedURLException e)
460 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
465 String defs = aparser.getValue("setprop");
468 int p = defs.indexOf('=');
471 System.err.println("Ignoring invalid setprop argument : " + defs);
475 System.out.println("Executing setprop argument: " + defs);
478 Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
480 // DISABLED FOR SECURITY REASONS
481 // TODO: add a property to allow properties to be overriden by cli args
482 // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
484 defs = aparser.getValue("setprop");
486 if (System.getProperty("java.awt.headless") != null
487 && System.getProperty("java.awt.headless").equals("true"))
491 System.setProperty("http.agent",
492 "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
496 Console.initLogger();
499 NoClassDefFoundError error)
501 error.printStackTrace();
502 System.out.println("\nEssential logging libraries not found."
503 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
508 if (!(headless || headlessArg))
512 * configure 'full' SO model if preferences say to, else use the default (full SO)
513 * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
515 boolean soDefault = !Platform.isJS();
516 if (Cache.getDefault("USE_FULL_SO", soDefault))
518 SequenceOntologyFactory.setInstance(new SequenceOntology());
521 if (!(headless || headlessArg))
523 Desktop.nosplash = aparser.contains("nosplash");
524 desktop = new Desktop();
525 desktop.setInBatchMode(true); // indicate we are starting up
529 JalviewTaskbar.setTaskbar(this);
530 } catch (Exception e)
532 Console.info("Cannot set Taskbar");
533 Console.error(e.getMessage());
534 // e.printStackTrace();
535 } catch (Throwable t)
537 Console.info("Cannot set Taskbar");
538 Console.error(t.getMessage());
539 // t.printStackTrace();
542 // set Proxy settings before all the internet calls
543 Cache.setProxyPropertiesFromPreferences();
545 desktop.setVisible(true);
547 if (!Platform.isJS())
556 * Check to see that the JVM version being run is suitable for the Java
557 * version this Jalview was compiled for. Popup a warning if not.
559 if (!LaunchUtils.checkJavaVersion())
561 Console.warn("The Java version being used (Java "
562 + LaunchUtils.getJavaVersion()
563 + ") may lead to problems. This installation of Jalview should be used with Java "
564 + LaunchUtils.getJavaCompileVersion() + ".");
567 .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
570 MessageManager.getString("label.continue") };
571 JOptionPane.showOptionDialog(null,
572 MessageManager.formatMessage(
573 "warning.wrong_jvm_version_message",
574 LaunchUtils.getJavaVersion(),
575 LaunchUtils.getJavaCompileVersion()),
577 .getString("warning.wrong_jvm_version_title"),
578 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
579 null, options, options[0]);
583 if (!aparser.contains("nowebservicediscovery"))
585 desktop.startServiceDiscovery();
587 if (!aparser.contains("nousagestats"))
589 startUsageStats(desktop);
593 System.err.println("CMD [-nousagestats] executed successfully!");
596 if (!aparser.contains("noquestionnaire"))
598 String url = aparser.getValue("questionnaire");
601 // Start the desktop questionnaire prompter with the specified
603 Console.debug("Starting questionnaire url at " + url);
604 desktop.checkForQuestionnaire(url);
605 System.out.println("CMD questionnaire[-" + url
606 + "] executed successfully!");
610 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
612 // Start the desktop questionnaire prompter with the specified
615 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
617 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
619 "Starting questionnaire with default url: " + defurl);
620 desktop.checkForQuestionnaire(defurl);
627 .println("CMD [-noquestionnaire] executed successfully!");
630 if (!aparser.contains("nonews")
631 || Cache.getProperty("NONEWS") == null)
633 desktop.checkForNews();
636 if (!aparser.contains("nohtmltemplates")
637 || Cache.getProperty("NOHTMLTEMPLATES") == null)
639 BioJsHTMLOutput.updateBioJS();
643 // Run Commands from cli
644 boolean commandsSuccess = Commands.processArgs(argparser, headlessArg);
647 Console.info("Successfully completed commands");
653 Console.warn("Error when running commands");
658 // Check if JVM and compile version might cause problems and log if it
660 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
662 Console.warn("The Java version being used (Java "
663 + LaunchUtils.getJavaVersion()
664 + ") may lead to problems. This installation of Jalview should be used with Java "
665 + LaunchUtils.getJavaCompileVersion() + ".");
668 // Move any new getdown-launcher-new.jar into place over old
669 // getdown-launcher.jar
670 String appdirString = System.getProperty("getdownappdir");
671 if (appdirString != null && appdirString.length() > 0)
673 final File appdir = new File(appdirString);
679 LaunchUtil.upgradeGetdown(
680 new File(appdir, "getdown-launcher-old.jar"),
681 new File(appdir, "getdown-launcher.jar"),
682 new File(appdir, "getdown-launcher-new.jar"));
687 String file = null, data = null;
689 FileFormatI format = null;
691 DataSourceType protocol = null;
693 FileLoader fileLoader = new FileLoader(!headless);
695 String groovyscript = null; // script to execute after all loading is
696 // completed one way or another
697 // extract groovy argument and execute if necessary
698 groovyscript = aparser.getValue("groovy", true);
699 file = aparser.getValue("open", true);
701 if (file == null && desktop == null)
703 System.out.println("No files to open!");
708 // Finally, deal with the remaining input data.
713 desktop.setProgressBar(
715 .getString("status.processing_commandline_args"),
716 progress = System.currentTimeMillis());
718 System.out.println("CMD [-open " + file + "] executed successfully!");
720 if (!Platform.isJS())
722 * ignore in JavaScript -- can't just file existence - could load it?
727 if (!HttpUtils.startsWithHttpOrHttps(file))
729 if (!(new File(file)).exists())
731 System.out.println("Can't find " + file);
740 protocol = AppletFormatAdapter.checkProtocol(file);
744 format = new IdentifyFile().identify(file, protocol);
745 } catch (FileFormatException e1)
750 AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
754 System.out.println("error");
758 setCurrentAlignFrame(af);
759 data = aparser.getValue("colour", true);
762 data.replaceAll("%20", " ");
764 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
765 af.getViewport(), af.getViewport().getAlignment(), data);
770 "CMD [-colour " + data + "] executed successfully!");
775 // Must maintain ability to use the groups flag
776 data = aparser.getValue("groups", true);
779 af.parseFeaturesFile(data,
780 AppletFormatAdapter.checkProtocol(data));
781 // System.out.println("Added " + data);
783 "CMD groups[-" + data + "] executed successfully!");
785 data = aparser.getValue("features", true);
788 af.parseFeaturesFile(data,
789 AppletFormatAdapter.checkProtocol(data));
790 // System.out.println("Added " + data);
792 "CMD [-features " + data + "] executed successfully!");
795 data = aparser.getValue("annotations", true);
798 af.loadJalviewDataFile(data, null, null, null);
799 // System.out.println("Added " + data);
801 "CMD [-annotations " + data + "] executed successfully!");
803 // set or clear the sortbytree flag.
804 if (aparser.contains("sortbytree"))
806 af.getViewport().setSortByTree(true);
807 if (af.getViewport().getSortByTree())
809 System.out.println("CMD [-sortbytree] executed successfully!");
812 if (aparser.contains("no-annotation"))
814 af.getViewport().setShowAnnotation(false);
815 if (!af.getViewport().isShowAnnotation())
817 System.out.println("CMD no-annotation executed successfully!");
820 if (aparser.contains("nosortbytree"))
822 af.getViewport().setSortByTree(false);
823 if (!af.getViewport().getSortByTree())
826 .println("CMD [-nosortbytree] executed successfully!");
829 data = aparser.getValue("tree", true);
835 "CMD [-tree " + data + "] executed successfully!");
836 NewickFile nf = new NewickFile(data,
837 AppletFormatAdapter.checkProtocol(data));
839 .setCurrentTree(af.showNewickTree(nf, data).getTree());
840 } catch (IOException ex)
842 System.err.println("Couldn't add tree " + data);
843 ex.printStackTrace(System.err);
846 // TODO - load PDB structure(s) to alignment JAL-629
847 // (associate with identical sequence in alignment, or a specified
849 if (groovyscript != null)
851 // Execute the groovy script after we've done all the rendering stuff
852 // and before any images or figures are generated.
853 System.out.println("Executing script " + groovyscript);
854 executeGroovyScript(groovyscript, af);
855 System.out.println("CMD groovy[" + groovyscript
856 + "] executed successfully!");
859 String imageName = "unnamed.png";
860 while (aparser.getSize() > 1)
862 String outputFormat = aparser.nextValue();
863 file = aparser.nextValue();
865 if (outputFormat.equalsIgnoreCase("png"))
867 af.createPNG(new File(file));
868 imageName = (new File(file)).getName();
869 System.out.println("Creating PNG image: " + file);
872 else if (outputFormat.equalsIgnoreCase("svg"))
874 File imageFile = new File(file);
875 imageName = imageFile.getName();
876 af.createSVG(imageFile);
877 System.out.println("Creating SVG image: " + file);
880 else if (outputFormat.equalsIgnoreCase("html"))
882 File imageFile = new File(file);
883 imageName = imageFile.getName();
884 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
885 htmlSVG.exportHTML(file);
887 System.out.println("Creating HTML image: " + file);
890 else if (outputFormat.equalsIgnoreCase("biojsmsa"))
894 System.err.println("The output html file must not be null");
899 BioJsHTMLOutput.refreshVersionInfo(
900 BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
901 } catch (URISyntaxException e)
905 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
906 bjs.exportHTML(file);
908 .println("Creating BioJS MSA Viwer HTML file: " + file);
911 else if (outputFormat.equalsIgnoreCase("imgMap"))
913 af.createImageMap(new File(file), imageName);
914 System.out.println("Creating image map: " + file);
917 else if (outputFormat.equalsIgnoreCase("eps"))
919 File outputFile = new File(file);
921 "Creating EPS file: " + outputFile.getAbsolutePath());
922 af.createEPS(outputFile);
925 FileFormatI outFormat = null;
928 outFormat = FileFormats.getInstance().forName(outputFormat);
929 } catch (Exception formatP)
931 System.out.println("Couldn't parse " + outFormat
932 + " as a valid Jalview format string.");
934 if (outFormat != null)
936 if (!outFormat.isWritable())
939 "This version of Jalview does not support alignment export as "
944 af.saveAlignment(file, outFormat);
945 if (af.isSaveAlignmentSuccessful())
947 System.out.println("Written alignment in "
948 + outFormat.getName() + " format to " + file);
952 System.out.println("Error writing file " + file + " in "
953 + outFormat.getName() + " format!!");
960 while (aparser.getSize() > 0)
962 System.out.println("Unknown arg: " + aparser.nextValue());
967 AlignFrame startUpAlframe = null;
968 // We'll only open the default file if the desktop is visible.
970 // ////////////////////
972 if (!Platform.isJS() && !headless && file == null
973 && Cache.getDefault("SHOW_STARTUP_FILE", true)
974 && !Commands.commandArgsProvided())
975 // don't open the startup file if command line args have been processed
976 // (&& !Commands.commandArgsProvided())
983 file = Cache.getDefault("STARTUP_FILE",
984 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
985 + "/examples/exampleFile_2_7.jvp");
986 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
988 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
990 file.replace("http:", "https:");
991 // hardwire upgrade of the startup file
992 file.replace("_2_3", "_2_7");
993 file.replace("2_7.jar", "2_7.jvp");
994 // and remove the stale setting
995 Cache.removeProperty("STARTUP_FILE");
998 protocol = AppletFormatAdapter.checkProtocol(file);
1000 if (file.endsWith(".jar"))
1002 format = FileFormat.Jalview;
1008 format = new IdentifyFile().identify(file, protocol);
1009 } catch (FileFormatException e)
1015 startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
1017 // don't ask to save when quitting if only the startup file has been
1019 Console.debug("Resetting up-to-date flag for startup file");
1020 startUpAlframe.getViewport().setSavedUpToDate(true);
1021 // extract groovy arguments before anything else.
1024 // Once all other stuff is done, execute any groovy scripts (in order)
1025 if (groovyscript != null)
1027 if (Cache.groovyJarsPresent())
1029 System.out.println("Executing script " + groovyscript);
1030 executeGroovyScript(groovyscript, startUpAlframe);
1035 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
1039 // and finally, turn off batch mode indicator - if the desktop still exists
1040 if (desktop != null)
1044 desktop.setProgressBar(null, progress);
1046 desktop.setInBatchMode(false);
1050 private static void setLookAndFeel()
1052 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
1054 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
1055 // try Quaqua/Vaqua.
1056 String lafProp = System.getProperty("laf");
1057 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
1058 String laf = "none";
1059 if (lafProp != null)
1063 else if (lafSetting != null)
1067 boolean lafSet = false;
1070 case "crossplatform":
1071 lafSet = setCrossPlatformLookAndFeel();
1074 Console.error("Could not set requested laf=" + laf);
1078 lafSet = setSystemLookAndFeel();
1081 Console.error("Could not set requested laf=" + laf);
1085 lafSet = setGtkLookAndFeel();
1088 Console.error("Could not set requested laf=" + laf);
1092 lafSet = setMetalLookAndFeel();
1095 Console.error("Could not set requested laf=" + laf);
1099 lafSet = setNimbusLookAndFeel();
1102 Console.error("Could not set requested laf=" + laf);
1106 lafSet = setFlatLookAndFeel();
1109 Console.error("Could not set requested laf=" + laf);
1113 lafSet = setMacLookAndFeel();
1116 Console.error("Could not set requested laf=" + laf);
1122 Console.error("Requested laf=" + laf + " not implemented");
1126 setSystemLookAndFeel();
1127 if (Platform.isLinux())
1129 setLinuxLookAndFeel();
1131 if (Platform.isMac())
1133 setMacLookAndFeel();
1138 private static boolean setCrossPlatformLookAndFeel()
1140 boolean set = false;
1143 UIManager.setLookAndFeel(
1144 UIManager.getCrossPlatformLookAndFeelClassName());
1146 } catch (Exception ex)
1148 Console.error("Unexpected Look and Feel Exception");
1149 Console.error(ex.getMessage());
1150 Console.debug(Cache.getStackTraceString(ex));
1155 private static boolean setSystemLookAndFeel()
1157 boolean set = false;
1160 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1162 } catch (Exception ex)
1164 Console.error("Unexpected Look and Feel Exception");
1165 Console.error(ex.getMessage());
1166 Console.debug(Cache.getStackTraceString(ex));
1171 private static boolean setSpecificLookAndFeel(String name,
1172 String className, boolean nameStartsWith)
1174 boolean set = false;
1177 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1179 if (info.getName() != null && nameStartsWith
1180 ? info.getName().toLowerCase(Locale.ROOT)
1181 .startsWith(name.toLowerCase(Locale.ROOT))
1182 : info.getName().toLowerCase(Locale.ROOT)
1183 .equals(name.toLowerCase(Locale.ROOT)))
1185 className = info.getClassName();
1189 UIManager.setLookAndFeel(className);
1191 } catch (Exception ex)
1193 Console.error("Unexpected Look and Feel Exception");
1194 Console.error(ex.getMessage());
1195 Console.debug(Cache.getStackTraceString(ex));
1200 private static boolean setGtkLookAndFeel()
1202 return setSpecificLookAndFeel("gtk",
1203 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1206 private static boolean setMetalLookAndFeel()
1208 return setSpecificLookAndFeel("metal",
1209 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1212 private static boolean setNimbusLookAndFeel()
1214 return setSpecificLookAndFeel("nimbus",
1215 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1218 private static boolean setFlatLookAndFeel()
1220 boolean set = false;
1221 if (SystemInfo.isMacOS)
1225 UIManager.setLookAndFeel(
1226 "com.formdev.flatlaf.themes.FlatMacLightLaf");
1228 Console.debug("Using FlatMacLightLaf");
1229 } catch (ClassNotFoundException | InstantiationException
1230 | IllegalAccessException | UnsupportedLookAndFeelException e)
1232 Console.debug("Exception loading FlatLightLaf", e);
1234 System.setProperty("apple.laf.useScreenMenuBar", "true");
1235 System.setProperty("apple.awt.application.name",
1236 ChannelProperties.getProperty("app_name"));
1237 System.setProperty("apple.awt.application.appearance", "system");
1238 if (SystemInfo.isMacFullWindowContentSupported
1239 && Desktop.desktop != null)
1241 Console.debug("Setting transparent title bar");
1242 Desktop.desktop.getRootPane()
1243 .putClientProperty("apple.awt.fullWindowContent", true);
1244 Desktop.desktop.getRootPane()
1245 .putClientProperty("apple.awt.transparentTitleBar", true);
1246 Desktop.desktop.getRootPane()
1247 .putClientProperty("apple.awt.fullscreenable", true);
1249 SwingUtilities.invokeLater(() -> {
1250 FlatMacLightLaf.setup();
1252 Console.debug("Using FlatMacLightLaf");
1259 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1261 Console.debug("Using FlatLightLaf");
1262 } catch (ClassNotFoundException | InstantiationException
1263 | IllegalAccessException | UnsupportedLookAndFeelException e)
1265 Console.debug("Exception loading FlatLightLaf", e);
1267 // Windows specific properties here
1268 SwingUtilities.invokeLater(() -> {
1269 FlatLightLaf.setup();
1271 Console.debug("Using FlatLightLaf");
1274 else if (SystemInfo.isLinux)
1278 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1280 Console.debug("Using FlatLightLaf");
1281 } catch (ClassNotFoundException | InstantiationException
1282 | IllegalAccessException | UnsupportedLookAndFeelException e)
1284 Console.debug("Exception loading FlatLightLaf", e);
1286 // enable custom window decorations
1287 JFrame.setDefaultLookAndFeelDecorated(true);
1288 JDialog.setDefaultLookAndFeelDecorated(true);
1289 SwingUtilities.invokeLater(() -> {
1290 FlatLightLaf.setup();
1292 Console.debug("Using FlatLightLaf");
1300 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1302 Console.debug("Using FlatLightLaf");
1303 } catch (ClassNotFoundException | InstantiationException
1304 | IllegalAccessException | UnsupportedLookAndFeelException e)
1306 Console.debug("Exception loading FlatLightLaf", e);
1312 UIManager.put("TabbedPane.tabType", "card");
1313 UIManager.put("TabbedPane.showTabSeparators", true);
1314 UIManager.put("TabbedPane.showContentSeparator", true);
1315 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1316 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1317 UIManager.put("TabbedPane.hasFullBorder", true);
1318 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1319 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1320 UIManager.put("TabbedPane.smoothScrolling", true);
1321 UIManager.put("TabbedPane.tabWidthMode", "compact");
1322 UIManager.put("TabbedPane.selectedBackground", Color.white);
1325 Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
1329 private static boolean setMacLookAndFeel()
1331 boolean set = false;
1332 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1333 ChannelProperties.getProperty("app_name"));
1334 System.setProperty("apple.laf.useScreenMenuBar", "true");
1336 * broken native LAFs on (ARM?) macbooks
1337 set = setQuaquaLookAndFeel();
1338 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1339 .toLowerCase(Locale.ROOT).contains("quaqua"))
1341 set = setVaquaLookAndFeel();
1344 set = setFlatLookAndFeel();
1348 private static boolean setLinuxLookAndFeel()
1350 boolean set = false;
1351 set = setFlatLookAndFeel();
1353 set = setMetalLookAndFeel();
1354 // avoid GtkLookAndFeel -- not good results especially on HiDPI
1356 set = setNimbusLookAndFeel();
1360 private static void showUsage()
1363 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1364 + "-nodisplay\tRun Jalview without User Interface.\n"
1365 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1366 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1367 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1368 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1369 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1370 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1371 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1372 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1373 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1374 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1375 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1376 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1377 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1378 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1379 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1380 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1381 + "-html FILE\tCreate HTML file from alignment.\n"
1382 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1383 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1384 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1385 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1386 + "-noquestionnaire\tTurn off questionnaire check.\n"
1387 + "-nonews\tTurn off check for Jalview news.\n"
1388 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1389 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1391 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1392 // after all other properties files have been read\n\t
1393 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1394 // passed in correctly)"
1395 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1396 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1397 + "-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"
1398 + "-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"
1399 + "-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"
1400 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1403 private static void startUsageStats(final Desktop desktop)
1406 * start a User Config prompt asking if we can log usage statistics.
1408 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
1409 "USAGESTATS", "Jalview Usage Statistics",
1410 "Do you want to help make Jalview better by enabling "
1411 + "the collection of usage statistics with Google Analytics ?"
1412 + "\n\n(you can enable or disable usage tracking in the preferences)",
1419 "Initialising googletracker for usage stats.");
1420 Cache.initGoogleTracker();
1421 Console.debug("Tracking enabled.");
1428 Console.debug("Not enabling Google Tracking.");
1431 desktop.addDialogThread(prompter);
1435 * Locate the given string as a file and pass it to the groovy interpreter.
1437 * @param groovyscript
1438 * the script to execute
1439 * @param jalviewContext
1440 * the Jalview Desktop object passed in to the groovy binding as the
1443 private void executeGroovyScript(String groovyscript, AlignFrame af)
1446 * for scripts contained in files
1453 if (groovyscript.trim().equals("STDIN"))
1455 // read from stdin into a tempfile and execute it
1458 tfile = File.createTempFile("jalview", "groovy");
1459 PrintWriter outfile = new PrintWriter(
1460 new OutputStreamWriter(new FileOutputStream(tfile)));
1461 BufferedReader br = new BufferedReader(
1462 new InputStreamReader(System.in));
1464 while ((line = br.readLine()) != null)
1466 outfile.write(line + "\n");
1472 } catch (Exception ex)
1474 System.err.println("Failed to read from STDIN into tempfile "
1475 + ((tfile == null) ? "(tempfile wasn't created)"
1476 : tfile.toString()));
1477 ex.printStackTrace();
1482 sfile = tfile.toURI().toURL();
1483 } catch (Exception x)
1486 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1488 x.printStackTrace();
1496 sfile = new URI(groovyscript).toURL();
1497 } catch (Exception x)
1499 tfile = new File(groovyscript);
1500 if (!tfile.exists())
1502 System.err.println("File '" + groovyscript + "' does not exist.");
1505 if (!tfile.canRead())
1507 System.err.println("File '" + groovyscript + "' cannot be read.");
1510 if (tfile.length() < 1)
1512 System.err.println("File '" + groovyscript + "' is empty.");
1517 sfile = tfile.getAbsoluteFile().toURI().toURL();
1518 } catch (Exception ex)
1520 System.err.println("Failed to create a file URL for "
1521 + tfile.getAbsoluteFile());
1528 Map<String, java.lang.Object> vbinding = new HashMap<>();
1529 vbinding.put("Jalview", this);
1532 vbinding.put("currentAlFrame", af);
1534 Binding gbinding = new Binding(vbinding);
1535 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1536 gse.run(sfile.toString(), gbinding);
1537 if ("STDIN".equals(groovyscript))
1539 // delete temp file that we made -
1540 // only if it was successfully executed
1543 } catch (Exception e)
1545 System.err.println("Exception Whilst trying to execute file " + sfile
1546 + " as a groovy script.");
1547 e.printStackTrace(System.err);
1552 public static boolean isHeadlessMode()
1554 String isheadless = System.getProperty("java.awt.headless");
1555 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1562 public AlignFrame[] getAlignFrames()
1564 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1565 : Desktop.getAlignFrames();
1570 * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
1574 // System.exit will run the shutdownHook first
1578 public static AlignFrame getCurrentAlignFrame()
1580 return Jalview.currentAlignFrame;
1583 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1585 Jalview.currentAlignFrame = currentAlignFrame;