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.ArrayList;
43 import java.util.HashMap;
44 import java.util.List;
45 import java.util.Locale;
47 import java.util.Properties;
48 import java.util.Vector;
49 import java.util.logging.ConsoleHandler;
50 import java.util.logging.Level;
51 import java.util.logging.Logger;
53 import javax.swing.JDialog;
54 import javax.swing.JFrame;
55 import javax.swing.JOptionPane;
56 import javax.swing.SwingUtilities;
57 import javax.swing.UIManager;
58 import javax.swing.UIManager.LookAndFeelInfo;
59 import javax.swing.UnsupportedLookAndFeelException;
61 import com.formdev.flatlaf.FlatLightLaf;
62 import com.formdev.flatlaf.themes.FlatMacLightLaf;
63 import com.formdev.flatlaf.util.SystemInfo;
64 import com.threerings.getdown.util.LaunchUtil;
66 //import edu.stanford.ejalbert.launching.IBrowserLaunching;
67 import groovy.lang.Binding;
68 import groovy.util.GroovyScriptEngine;
69 import jalview.bin.argparser.Arg;
70 import jalview.bin.argparser.Arg.Opt;
71 import jalview.bin.argparser.ArgParser;
72 import jalview.bin.argparser.BootstrapArgs;
73 import jalview.ext.so.SequenceOntology;
74 import jalview.gui.AlignFrame;
75 import jalview.gui.Desktop;
76 import jalview.gui.PromptUserConfig;
77 import jalview.gui.QuitHandler;
78 import jalview.gui.QuitHandler.QResponse;
79 import jalview.io.AppletFormatAdapter;
80 import jalview.io.BioJsHTMLOutput;
81 import jalview.io.DataSourceType;
82 import jalview.io.FileFormat;
83 import jalview.io.FileFormatException;
84 import jalview.io.FileFormatI;
85 import jalview.io.FileFormats;
86 import jalview.io.FileLoader;
87 import jalview.io.HtmlSvgOutput;
88 import jalview.io.IdentifyFile;
89 import jalview.io.NewickFile;
90 import jalview.io.gff.SequenceOntologyFactory;
91 import jalview.schemes.ColourSchemeI;
92 import jalview.schemes.ColourSchemeProperty;
93 import jalview.util.ChannelProperties;
94 import jalview.util.HttpUtils;
95 import jalview.util.LaunchUtils;
96 import jalview.util.MessageManager;
97 import jalview.util.Platform;
98 import jalview.ws.jws2.Jws2Discoverer;
101 * Main class for Jalview Application <br>
103 * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
104 * jalview.bin.Jalview
106 * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
107 * jalview.bin.Jalview jalview.bin.Jalview
109 * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
110 * embellish '*' to e.g. '*.jar')
113 * @version $Revision$
119 Platform.getURLCommandArguments();
120 Platform.addJ2SDirectDatabaseCall("https://www.jalview.org");
121 Platform.addJ2SDirectDatabaseCall("http://www.jalview.org");
122 Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk");
123 Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk");
127 * singleton instance of this class
129 private static Jalview instance;
131 private Desktop desktop;
133 protected Commands cmds;
135 public static AlignFrame currentAlignFrame;
137 public ArgParser argparser = null;
139 public BootstrapArgs bootstrapArgs = null;
141 private boolean QUIET = false;
143 public boolean quiet()
150 if (!Platform.isJS())
157 // grab all the rights we can for the JVM
158 Policy.setPolicy(new Policy()
161 public PermissionCollection getPermissions(CodeSource codesource)
163 Permissions perms = new Permissions();
164 perms.add(new AllPermission());
169 public void refresh()
177 * keep track of feature fetching tasks.
185 * TODO: generalise to track all jalview events to orchestrate batch processing
189 private int queued = 0;
191 private int running = 0;
193 public FeatureFetcher()
198 public void addFetcher(final AlignFrame af,
199 final Vector<String> dasSources)
201 final long id = System.currentTimeMillis();
203 final FeatureFetcher us = this;
204 new Thread(new Runnable()
216 af.setProgressBar(MessageManager
217 .getString("status.das_features_being_retrived"), id);
218 af.featureSettings_actionPerformed(null);
219 af.setProgressBar(null, id);
228 public synchronized boolean allFinished()
230 return queued == 0 && running == 0;
235 public static Jalview getInstance()
241 * main class for Jalview application
244 * open <em>filename</em>
246 public static void main(String[] args)
248 // setLogging(); // BH - for event debugging in JavaScript
249 instance = new Jalview();
250 instance.doMain(args);
253 private static void logClass(String name)
255 // BH - for event debugging in JavaScript
256 ConsoleHandler consoleHandler = new ConsoleHandler();
257 consoleHandler.setLevel(Level.ALL);
258 Logger logger = Logger.getLogger(name);
259 logger.setLevel(Level.ALL);
260 logger.addHandler(consoleHandler);
263 @SuppressWarnings("unused")
264 private static void setLogging()
272 System.out.println("not in js");
275 // BH - for event debugging in JavaScript (Java mode only)
276 if (!Platform.isJS())
283 Logger.getLogger("").setLevel(Level.ALL);
284 logClass("java.awt.EventDispatchThread");
285 logClass("java.awt.EventQueue");
286 logClass("java.awt.Component");
287 logClass("java.awt.focus.Component");
288 logClass("java.awt.focus.DefaultKeyboardFocusManager");
296 void doMain(String[] args)
298 if (!Platform.isJS())
300 System.setSecurityManager(null);
304 args = new String[] {};
306 // get args needed before proper ArgParser
307 bootstrapArgs = BootstrapArgs.getBootstrapArgs(args);
309 if (!Platform.isJS())
311 // are we being --quiet ?
312 if (bootstrapArgs.contains(Arg.QUIET))
315 OutputStream devNull = new OutputStream()
319 public void write(int b)
324 System.setOut(new PrintStream(devNull));
325 // redirecting stderr not working
326 if (bootstrapArgs.getList(Arg.QUIET).size() > 1)
328 System.setErr(new PrintStream(devNull));
332 if (bootstrapArgs.contains(Arg.HELP))
338 // Move any new getdown-launcher-new.jar into place over old
339 // getdown-launcher.jar
340 String appdirString = System.getProperty("getdownappdir");
341 if (appdirString != null && appdirString.length() > 0)
343 final File appdir = new File(appdirString);
349 LaunchUtil.upgradeGetdown(
350 new File(appdir, "getdown-launcher-old.jar"),
351 new File(appdir, "getdown-launcher.jar"),
352 new File(appdir, "getdown-launcher-new.jar"));
360 "Java version: " + System.getProperty("java.version"));
361 System.out.println("Java Home: " + System.getProperty("java.home"));
362 System.out.println(System.getProperty("os.arch") + " "
363 + System.getProperty("os.name") + " "
364 + System.getProperty("os.version"));
366 String val = System.getProperty("sys.install4jVersion");
369 System.out.println("Install4j version: " + val);
371 val = System.getProperty("installer_template_version");
374 System.out.println("Install4j template version: " + val);
376 val = System.getProperty("launcher_version");
379 System.out.println("Launcher version: " + val);
383 if (Platform.isLinux() && LaunchUtils.getJavaVersion() < 11)
385 System.setProperty("flatlaf.uiScale", "1");
388 // get bootstrap properties (mainly for the logger level)
389 Properties bootstrapProperties = Cache
390 .bootstrapProperties(bootstrapArgs.get(Arg.PROPS));
392 // report Jalview version
393 Cache.loadBuildProperties(true);
396 ArgsParser aparser = new ArgsParser(args);
399 boolean headless = false;
401 boolean headlessArg = false;
405 String logLevel = null;
406 if (bootstrapArgs.contains(Arg.TRACE))
410 else if (bootstrapArgs.contains(Arg.DEBUG))
414 if (logLevel == null && !(bootstrapProperties == null))
416 logLevel = bootstrapProperties.getProperty(Cache.JALVIEWLOGLEVEL);
418 Console.initLogger(logLevel);
419 } catch (NoClassDefFoundError error)
421 error.printStackTrace();
422 String message = "\nEssential logging libraries not found."
423 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview";
424 Jalview.exit(message, 0);
427 // register SIGTERM listener
428 Runtime.getRuntime().addShutdownHook(new Thread()
432 Console.debug("Running shutdown hook");
433 if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT)
435 // Got to here by a SIGTERM signal.
436 // Note we will not actually cancel the quit from here -- it's too
437 // late -- but we can wait for saving files.
438 Console.debug("Checking for saving files");
439 QuitHandler.getQuitResponse(false);
443 Console.debug("Nothing more to do");
445 Console.debug("Exiting, bye!");
446 // shutdownHook cannot be cancelled, JVM will now halt
450 String usrPropsFile = bootstrapArgs.contains(Arg.PROPS)
451 ? bootstrapArgs.get(Arg.PROPS)
452 : aparser.getValue("props");
453 // if usrPropsFile == null, loadProperties will use the Channel
455 Cache.loadProperties(usrPropsFile);
456 if (usrPropsFile != null)
459 "CMD [-props " + usrPropsFile + "] executed successfully!");
460 testoutput(bootstrapArgs, Arg.PROPS,
461 "test/jalview/bin/testProps.jvprops", usrPropsFile);
464 // --argfile=... -- OVERRIDES ALL NON-BOOTSTRAP ARGS
465 if (bootstrapArgs.contains(Arg.ARGFILE))
467 argparser = ArgParser.parseArgFiles(
468 bootstrapArgs.getList(Arg.ARGFILE),
469 bootstrapArgs.getBoolean(Arg.INITSUBSTITUTIONS),
474 argparser = new ArgParser(args,
475 bootstrapArgs.getBoolean(Arg.INITSUBSTITUTIONS),
479 if (!Platform.isJS())
486 if (bootstrapArgs.contains(Arg.HELP))
488 System.out.println(Arg.usage());
489 Jalview.exit(null, 0);
491 if (aparser.contains("help") || aparser.contains("h"))
494 Jalview.exit(null, 0);
497 if (bootstrapArgs.contains(Arg.HEADLESS))
499 System.setProperty("java.awt.headless", "true");
501 headlessArg = bootstrapArgs.getBoolean(Arg.HEADLESS);
503 if (aparser.contains("nodisplay") || aparser.contains("nogui")
504 || aparser.contains("headless"))
506 System.setProperty("java.awt.headless", "true");
512 // allow https handshakes to download intermediate certs if necessary
513 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
515 String jabawsUrl = bootstrapArgs.get(Arg.JABAWS);
516 if (jabawsUrl == null)
517 jabawsUrl = aparser.getValue("jabaws");
518 if (jabawsUrl != null)
522 Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
524 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
525 testoutput(bootstrapArgs, Arg.JABAWS,
526 "http://www.compbio.dundee.ac.uk/jabaws", jabawsUrl);
527 } catch (MalformedURLException e)
530 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
535 List<String> setprops = new ArrayList<>();
536 if (bootstrapArgs.contains(Arg.SETPROP))
538 setprops = bootstrapArgs.getList(Arg.SETPROP);
542 String sp = aparser.getValue("setprop");
546 sp = aparser.getValue("setprop");
549 for (String setprop : setprops)
551 int p = setprop.indexOf('=');
555 .println("Ignoring invalid setprop argument : " + setprop);
559 System.out.println("Executing setprop argument: " + setprop);
562 Cache.setProperty(setprop.substring(0, p),
563 setprop.substring(p + 1));
565 // DISABLED FOR SECURITY REASONS
566 // TODO: add a property to allow properties to be overriden by cli args
567 // Cache.setProperty(setprop.substring(0,p), setprop.substring(p+1));
570 if (System.getProperty("java.awt.headless") != null
571 && System.getProperty("java.awt.headless").equals("true"))
575 System.setProperty("http.agent",
576 "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
580 Console.initLogger();
583 NoClassDefFoundError error)
585 error.printStackTrace();
586 String message = "\nEssential logging libraries not found."
587 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview";
588 Jalview.exit(message, 0);
592 if (!(headless || headlessArg))
596 * configure 'full' SO model if preferences say to, else use the default (full SO)
597 * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
599 boolean soDefault = !Platform.isJS();
600 if (Cache.getDefault("USE_FULL_SO", soDefault))
602 SequenceOntologyFactory.setInstance(new SequenceOntology());
605 if (!(headless || headlessArg))
607 Desktop.nosplash = "false".equals(bootstrapArgs.get(Arg.SPLASH))
608 || aparser.contains("nosplash")
609 || Cache.getDefault("SPLASH", "true").equals("false");
610 desktop = new Desktop();
611 desktop.setInBatchMode(true); // indicate we are starting up
615 JalviewTaskbar.setTaskbar(this);
616 } catch (Exception e)
618 Console.info("Cannot set Taskbar");
619 Console.error(e.getMessage());
620 // e.printStackTrace();
621 } catch (Throwable t)
623 Console.info("Cannot set Taskbar");
624 Console.error(t.getMessage());
625 // t.printStackTrace();
628 // set Proxy settings before all the internet calls
629 Cache.setProxyPropertiesFromPreferences();
631 desktop.setVisible(true);
633 if (!Platform.isJS())
642 * Check to see that the JVM version being run is suitable for the Java
643 * version this Jalview was compiled for. Popup a warning if not.
645 if (!LaunchUtils.checkJavaVersion())
647 Console.warn("The Java version being used (Java "
648 + LaunchUtils.getJavaVersion()
649 + ") may lead to problems. This installation of Jalview should be used with Java "
650 + LaunchUtils.getJavaCompileVersion() + ".");
653 .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
656 MessageManager.getString("label.continue") };
657 JOptionPane.showOptionDialog(null,
658 MessageManager.formatMessage(
659 "warning.wrong_jvm_version_message",
660 LaunchUtils.getJavaVersion(),
661 LaunchUtils.getJavaCompileVersion()),
663 .getString("warning.wrong_jvm_version_title"),
664 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
665 null, options, options[0]);
669 boolean webservicediscovery = bootstrapArgs
670 .getBoolean(Arg.WEBSERVICEDISCOVERY);
671 if (aparser.contains("nowebservicediscovery"))
672 webservicediscovery = false;
673 if (webservicediscovery)
675 desktop.startServiceDiscovery();
679 testoutput(argparser, Arg.WEBSERVICEDISCOVERY);
682 boolean usagestats = bootstrapArgs.getBoolean(Arg.USAGESTATS);
683 if (aparser.contains("nousagestats"))
687 startUsageStats(desktop);
688 testoutput(argparser, Arg.USAGESTATS);
692 System.out.println("CMD [-nousagestats] executed successfully!");
693 testoutput(argparser, Arg.USAGESTATS);
696 boolean questionnaire = bootstrapArgs.getBoolean(Arg.QUESTIONNAIRE);
697 if (aparser.contains("noquestionnaire"))
698 questionnaire = false;
701 String url = aparser.getValue("questionnaire");
704 // Start the desktop questionnaire prompter with the specified
706 Console.debug("Starting questionnaire url at " + url);
707 desktop.checkForQuestionnaire(url);
708 System.out.println("CMD questionnaire[-" + url
709 + "] executed successfully!");
713 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
715 // Start the desktop questionnaire prompter with the specified
718 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
720 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
722 "Starting questionnaire with default url: " + defurl);
723 desktop.checkForQuestionnaire(defurl);
730 .println("CMD [-noquestionnaire] executed successfully!");
731 testoutput(argparser, Arg.QUESTIONNAIRE);
734 if ((!aparser.contains("nonews")
735 && Cache.getProperty("NONEWS") == null
736 && !"false".equals(bootstrapArgs.get(Arg.NEWS)))
737 || "true".equals(bootstrapArgs.get(Arg.NEWS)))
739 desktop.checkForNews();
742 if (!aparser.contains("nohtmltemplates")
743 && Cache.getProperty("NOHTMLTEMPLATES") == null)
745 BioJsHTMLOutput.updateBioJS();
749 // Run Commands from cli
750 cmds = new Commands(argparser, headlessArg);
751 boolean commandsSuccess = cmds.argsWereParsed();
756 Jalview.exit("Successfully completed commands in headless mode", 0);
758 Console.info("Successfully completed commands");
764 Jalview.exit("Error when running Commands in headless mode", 1);
766 Console.warn("Error when running commands");
769 // Check if JVM and compile version might cause problems and log if it
771 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
773 Console.warn("The Java version being used (Java "
774 + LaunchUtils.getJavaVersion()
775 + ") may lead to problems. This installation of Jalview should be used with Java "
776 + LaunchUtils.getJavaCompileVersion() + ".");
779 String file = null, data = null;
781 FileFormatI format = null;
783 DataSourceType protocol = null;
785 FileLoader fileLoader = new FileLoader(!headless);
787 String groovyscript = null; // script to execute after all loading is
788 // completed one way or another
789 // extract groovy argument and execute if necessary
790 groovyscript = aparser.getValue("groovy", true);
791 file = aparser.getValue("open", true);
793 if (file == null && desktop == null && !commandsSuccess)
795 Jalview.exit("No files to open!", 1);
799 // Finally, deal with the remaining input data.
804 desktop.setProgressBar(
806 .getString("status.processing_commandline_args"),
807 progress = System.currentTimeMillis());
809 System.out.println("CMD [-open " + file + "] executed successfully!");
811 if (!Platform.isJS())
813 * ignore in JavaScript -- can't just file existence - could load it?
818 if (!HttpUtils.startsWithHttpOrHttps(file))
820 if (!(new File(file)).exists())
825 "Can't find file '" + file + "' in headless mode", 1);
827 Console.warn("Can't find file'" + file + "'");
832 protocol = AppletFormatAdapter.checkProtocol(file);
836 format = new IdentifyFile().identify(file, protocol);
837 } catch (FileFormatException e1)
842 AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
846 System.out.println("error");
850 setCurrentAlignFrame(af);
851 data = aparser.getValue("colour", true);
854 data.replaceAll("%20", " ");
856 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
857 af.getViewport(), af.getViewport().getAlignment(), data);
862 "CMD [-colour " + data + "] executed successfully!");
867 // Must maintain ability to use the groups flag
868 data = aparser.getValue("groups", true);
871 af.parseFeaturesFile(data,
872 AppletFormatAdapter.checkProtocol(data));
873 // System.out.println("Added " + data);
875 "CMD groups[-" + data + "] executed successfully!");
877 data = aparser.getValue("features", true);
880 af.parseFeaturesFile(data,
881 AppletFormatAdapter.checkProtocol(data));
882 // System.out.println("Added " + data);
884 "CMD [-features " + data + "] executed successfully!");
887 data = aparser.getValue("annotations", true);
890 af.loadJalviewDataFile(data, null, null, null);
891 // System.out.println("Added " + data);
893 "CMD [-annotations " + data + "] executed successfully!");
895 // set or clear the sortbytree flag.
896 if (aparser.contains("sortbytree"))
898 af.getViewport().setSortByTree(true);
899 if (af.getViewport().getSortByTree())
901 System.out.println("CMD [-sortbytree] executed successfully!");
904 if (aparser.contains("no-annotation"))
906 af.getViewport().setShowAnnotation(false);
907 if (!af.getViewport().isShowAnnotation())
909 System.out.println("CMD no-annotation executed successfully!");
912 if (aparser.contains("nosortbytree"))
914 af.getViewport().setSortByTree(false);
915 if (!af.getViewport().getSortByTree())
918 .println("CMD [-nosortbytree] executed successfully!");
921 data = aparser.getValue("tree", true);
927 "CMD [-tree " + data + "] executed successfully!");
928 NewickFile nf = new NewickFile(data,
929 AppletFormatAdapter.checkProtocol(data));
931 .setCurrentTree(af.showNewickTree(nf, data).getTree());
932 } catch (IOException ex)
934 System.err.println("Couldn't add tree " + data);
935 ex.printStackTrace(System.err);
938 // TODO - load PDB structure(s) to alignment JAL-629
939 // (associate with identical sequence in alignment, or a specified
941 if (groovyscript != null)
943 // Execute the groovy script after we've done all the rendering stuff
944 // and before any images or figures are generated.
945 System.out.println("Executing script " + groovyscript);
946 executeGroovyScript(groovyscript, af);
947 System.out.println("CMD groovy[" + groovyscript
948 + "] executed successfully!");
951 String imageName = "unnamed.png";
952 while (aparser.getSize() > 1)
954 String outputFormat = aparser.nextValue();
955 file = aparser.nextValue();
957 if (outputFormat.equalsIgnoreCase("png"))
959 af.createPNG(new File(file));
960 imageName = (new File(file)).getName();
961 System.out.println("Creating PNG image: " + file);
964 else if (outputFormat.equalsIgnoreCase("svg"))
966 File imageFile = new File(file);
967 imageName = imageFile.getName();
968 af.createSVG(imageFile);
969 System.out.println("Creating SVG image: " + file);
972 else if (outputFormat.equalsIgnoreCase("html"))
974 File imageFile = new File(file);
975 imageName = imageFile.getName();
976 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
977 htmlSVG.exportHTML(file);
979 System.out.println("Creating HTML image: " + file);
982 else if (outputFormat.equalsIgnoreCase("biojsmsa"))
986 System.err.println("The output html file must not be null");
991 BioJsHTMLOutput.refreshVersionInfo(
992 BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
993 } catch (URISyntaxException e)
997 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
998 bjs.exportHTML(file);
1000 .println("Creating BioJS MSA Viwer HTML file: " + file);
1003 else if (outputFormat.equalsIgnoreCase("imgMap"))
1005 af.createImageMap(new File(file), imageName);
1006 System.out.println("Creating image map: " + file);
1009 else if (outputFormat.equalsIgnoreCase("eps"))
1011 File outputFile = new File(file);
1013 "Creating EPS file: " + outputFile.getAbsolutePath());
1014 af.createEPS(outputFile);
1017 FileFormatI outFormat = null;
1020 outFormat = FileFormats.getInstance().forName(outputFormat);
1021 } catch (Exception formatP)
1023 System.out.println("Couldn't parse " + outFormat
1024 + " as a valid Jalview format string.");
1026 if (outFormat != null)
1028 if (!outFormat.isWritable())
1031 "This version of Jalview does not support alignment export as "
1036 af.saveAlignment(file, outFormat);
1037 if (af.isSaveAlignmentSuccessful())
1039 System.out.println("Written alignment in "
1040 + outFormat.getName() + " format to " + file);
1044 System.out.println("Error writing file " + file + " in "
1045 + outFormat.getName() + " format!!");
1052 while (aparser.getSize() > 0)
1054 System.out.println("Unknown arg: " + aparser.nextValue());
1059 AlignFrame startUpAlframe = null;
1060 // We'll only open the default file if the desktop is visible.
1062 // ////////////////////
1064 if (!Platform.isJS() && !headless && file == null
1065 && Cache.getDefault("SHOW_STARTUP_FILE", true)
1066 && !cmds.commandArgsProvided())
1067 // don't open the startup file if command line args have been processed
1068 // (&& !Commands.commandArgsProvided())
1075 file = Cache.getDefault("STARTUP_FILE",
1076 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
1077 + "/examples/exampleFile_2_7.jvp");
1078 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
1080 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
1082 file.replace("http:", "https:");
1083 // hardwire upgrade of the startup file
1084 file.replace("_2_3", "_2_7");
1085 file.replace("2_7.jar", "2_7.jvp");
1086 // and remove the stale setting
1087 Cache.removeProperty("STARTUP_FILE");
1090 protocol = AppletFormatAdapter.checkProtocol(file);
1092 if (file.endsWith(".jar"))
1094 format = FileFormat.Jalview;
1100 format = new IdentifyFile().identify(file, protocol);
1101 } catch (FileFormatException e)
1107 startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
1109 // don't ask to save when quitting if only the startup file has been
1111 Console.debug("Resetting up-to-date flag for startup file");
1112 startUpAlframe.getViewport().setSavedUpToDate(true);
1113 // extract groovy arguments before anything else.
1116 // Once all other stuff is done, execute any groovy scripts (in order)
1117 if (groovyscript != null)
1119 if (Cache.groovyJarsPresent())
1121 System.out.println("Executing script " + groovyscript);
1122 executeGroovyScript(groovyscript, startUpAlframe);
1127 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
1131 // and finally, turn off batch mode indicator - if the desktop still exists
1132 if (desktop != null)
1136 desktop.setProgressBar(null, progress);
1138 desktop.setInBatchMode(false);
1142 private static void setLookAndFeel()
1144 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
1146 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
1147 // try Quaqua/Vaqua.
1148 String lafProp = System.getProperty("laf");
1149 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
1150 String laf = "none";
1151 if (lafProp != null)
1155 else if (lafSetting != null)
1159 boolean lafSet = false;
1162 case "crossplatform":
1163 lafSet = setCrossPlatformLookAndFeel();
1166 Console.error("Could not set requested laf=" + laf);
1170 lafSet = setSystemLookAndFeel();
1173 Console.error("Could not set requested laf=" + laf);
1177 lafSet = setGtkLookAndFeel();
1180 Console.error("Could not set requested laf=" + laf);
1184 lafSet = setMetalLookAndFeel();
1187 Console.error("Could not set requested laf=" + laf);
1191 lafSet = setNimbusLookAndFeel();
1194 Console.error("Could not set requested laf=" + laf);
1198 lafSet = setFlatLookAndFeel();
1201 Console.error("Could not set requested laf=" + laf);
1205 lafSet = setMacLookAndFeel();
1208 Console.error("Could not set requested laf=" + laf);
1214 Console.error("Requested laf=" + laf + " not implemented");
1218 setSystemLookAndFeel();
1219 if (Platform.isLinux())
1221 setLinuxLookAndFeel();
1223 if (Platform.isMac())
1225 setMacLookAndFeel();
1230 private static boolean setCrossPlatformLookAndFeel()
1232 boolean set = false;
1235 UIManager.setLookAndFeel(
1236 UIManager.getCrossPlatformLookAndFeelClassName());
1238 } catch (Exception ex)
1240 Console.error("Unexpected Look and Feel Exception");
1241 Console.error(ex.getMessage());
1242 Console.debug(Cache.getStackTraceString(ex));
1247 private static boolean setSystemLookAndFeel()
1249 boolean set = false;
1252 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1254 } catch (Exception ex)
1256 Console.error("Unexpected Look and Feel Exception");
1257 Console.error(ex.getMessage());
1258 Console.debug(Cache.getStackTraceString(ex));
1263 private static boolean setSpecificLookAndFeel(String name,
1264 String className, boolean nameStartsWith)
1266 boolean set = false;
1269 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1271 if (info.getName() != null && nameStartsWith
1272 ? info.getName().toLowerCase(Locale.ROOT)
1273 .startsWith(name.toLowerCase(Locale.ROOT))
1274 : info.getName().toLowerCase(Locale.ROOT)
1275 .equals(name.toLowerCase(Locale.ROOT)))
1277 className = info.getClassName();
1281 UIManager.setLookAndFeel(className);
1283 } catch (Exception ex)
1285 Console.error("Unexpected Look and Feel Exception");
1286 Console.error(ex.getMessage());
1287 Console.debug(Cache.getStackTraceString(ex));
1292 private static boolean setGtkLookAndFeel()
1294 return setSpecificLookAndFeel("gtk",
1295 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1298 private static boolean setMetalLookAndFeel()
1300 return setSpecificLookAndFeel("metal",
1301 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1304 private static boolean setNimbusLookAndFeel()
1306 return setSpecificLookAndFeel("nimbus",
1307 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1310 private static boolean setFlatLookAndFeel()
1312 boolean set = false;
1313 if (SystemInfo.isMacOS)
1317 UIManager.setLookAndFeel(
1318 "com.formdev.flatlaf.themes.FlatMacLightLaf");
1320 Console.debug("Using FlatMacLightLaf");
1321 } catch (ClassNotFoundException | InstantiationException
1322 | IllegalAccessException | UnsupportedLookAndFeelException e)
1324 Console.debug("Exception loading FlatLightLaf", e);
1326 System.setProperty("apple.laf.useScreenMenuBar", "true");
1327 System.setProperty("apple.awt.application.name",
1328 ChannelProperties.getProperty("app_name"));
1329 System.setProperty("apple.awt.application.appearance", "system");
1330 if (SystemInfo.isMacFullWindowContentSupported
1331 && Desktop.desktop != null)
1333 Console.debug("Setting transparent title bar");
1334 Desktop.desktop.getRootPane()
1335 .putClientProperty("apple.awt.fullWindowContent", true);
1336 Desktop.desktop.getRootPane()
1337 .putClientProperty("apple.awt.transparentTitleBar", true);
1338 Desktop.desktop.getRootPane()
1339 .putClientProperty("apple.awt.fullscreenable", true);
1341 SwingUtilities.invokeLater(() -> {
1342 FlatMacLightLaf.setup();
1344 Console.debug("Using FlatMacLightLaf");
1351 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1353 Console.debug("Using FlatLightLaf");
1354 } catch (ClassNotFoundException | InstantiationException
1355 | IllegalAccessException | UnsupportedLookAndFeelException e)
1357 Console.debug("Exception loading FlatLightLaf", e);
1359 // Windows specific properties here
1360 SwingUtilities.invokeLater(() -> {
1361 FlatLightLaf.setup();
1363 Console.debug("Using FlatLightLaf");
1366 else if (SystemInfo.isLinux)
1370 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1372 Console.debug("Using FlatLightLaf");
1373 } catch (ClassNotFoundException | InstantiationException
1374 | IllegalAccessException | UnsupportedLookAndFeelException e)
1376 Console.debug("Exception loading FlatLightLaf", e);
1378 // enable custom window decorations
1379 JFrame.setDefaultLookAndFeelDecorated(true);
1380 JDialog.setDefaultLookAndFeelDecorated(true);
1381 SwingUtilities.invokeLater(() -> {
1382 FlatLightLaf.setup();
1384 Console.debug("Using FlatLightLaf");
1392 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1394 Console.debug("Using FlatLightLaf");
1395 } catch (ClassNotFoundException | InstantiationException
1396 | IllegalAccessException | UnsupportedLookAndFeelException e)
1398 Console.debug("Exception loading FlatLightLaf", e);
1404 UIManager.put("TabbedPane.tabType", "card");
1405 UIManager.put("TabbedPane.showTabSeparators", true);
1406 UIManager.put("TabbedPane.showContentSeparator", true);
1407 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1408 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1409 UIManager.put("TabbedPane.hasFullBorder", true);
1410 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1411 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1412 UIManager.put("TabbedPane.smoothScrolling", true);
1413 UIManager.put("TabbedPane.tabWidthMode", "compact");
1414 UIManager.put("TabbedPane.selectedBackground", Color.white);
1417 Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
1421 private static boolean setMacLookAndFeel()
1423 boolean set = false;
1424 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1425 ChannelProperties.getProperty("app_name"));
1426 System.setProperty("apple.laf.useScreenMenuBar", "true");
1428 * broken native LAFs on (ARM?) macbooks
1429 set = setQuaquaLookAndFeel();
1430 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1431 .toLowerCase(Locale.ROOT).contains("quaqua"))
1433 set = setVaquaLookAndFeel();
1436 set = setFlatLookAndFeel();
1440 private static boolean setLinuxLookAndFeel()
1442 boolean set = false;
1443 set = setFlatLookAndFeel();
1445 set = setMetalLookAndFeel();
1446 // avoid GtkLookAndFeel -- not good results especially on HiDPI
1448 set = setNimbusLookAndFeel();
1452 private static void showUsage()
1455 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1456 + "-nodisplay\tRun Jalview without User Interface.\n"
1457 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1458 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1459 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1460 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1461 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1462 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1463 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1464 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1465 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1466 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1467 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1468 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1469 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1470 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1471 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1472 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1473 + "-html FILE\tCreate HTML file from alignment.\n"
1474 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1475 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1476 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1477 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1478 + "-noquestionnaire\tTurn off questionnaire check.\n"
1479 + "-nonews\tTurn off check for Jalview news.\n"
1480 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1481 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1483 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1484 // after all other properties files have been read\n\t
1485 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1486 // passed in correctly)"
1487 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1488 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1489 + "-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"
1490 + "-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"
1491 + "-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"
1492 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1495 private static void startUsageStats(final Desktop desktop)
1498 * start a User Config prompt asking if we can log usage statistics.
1500 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
1501 "USAGESTATS", "Jalview Usage Statistics",
1502 "Do you want to help make Jalview better by enabling "
1503 + "the collection of usage statistics with Google Analytics ?"
1504 + "\n\n(you can enable or disable usage tracking in the preferences)",
1511 "Initialising googletracker for usage stats.");
1512 Cache.initGoogleTracker();
1513 Console.debug("Tracking enabled.");
1520 Console.debug("Not enabling Google Tracking.");
1523 desktop.addDialogThread(prompter);
1527 * Locate the given string as a file and pass it to the groovy interpreter.
1529 * @param groovyscript
1530 * the script to execute
1531 * @param jalviewContext
1532 * the Jalview Desktop object passed in to the groovy binding as the
1535 protected void executeGroovyScript(String groovyscript, AlignFrame af)
1538 * for scripts contained in files
1545 if (groovyscript.trim().equals("STDIN"))
1547 // read from stdin into a tempfile and execute it
1550 tfile = File.createTempFile("jalview", "groovy");
1551 PrintWriter outfile = new PrintWriter(
1552 new OutputStreamWriter(new FileOutputStream(tfile)));
1553 BufferedReader br = new BufferedReader(
1554 new InputStreamReader(System.in));
1556 while ((line = br.readLine()) != null)
1558 outfile.write(line + "\n");
1564 } catch (Exception ex)
1566 System.err.println("Failed to read from STDIN into tempfile "
1567 + ((tfile == null) ? "(tempfile wasn't created)"
1568 : tfile.toString()));
1569 ex.printStackTrace();
1574 sfile = tfile.toURI().toURL();
1575 } catch (Exception x)
1578 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1580 x.printStackTrace();
1588 sfile = new URI(groovyscript).toURL();
1589 } catch (Exception x)
1591 tfile = new File(groovyscript);
1592 if (!tfile.exists())
1594 System.err.println("File '" + groovyscript + "' does not exist.");
1597 if (!tfile.canRead())
1599 System.err.println("File '" + groovyscript + "' cannot be read.");
1602 if (tfile.length() < 1)
1604 System.err.println("File '" + groovyscript + "' is empty.");
1609 sfile = tfile.getAbsoluteFile().toURI().toURL();
1610 } catch (Exception ex)
1612 System.err.println("Failed to create a file URL for "
1613 + tfile.getAbsoluteFile());
1620 Map<String, java.lang.Object> vbinding = new HashMap<>();
1621 vbinding.put("Jalview", this);
1624 vbinding.put("currentAlFrame", af);
1626 Binding gbinding = new Binding(vbinding);
1627 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1628 gse.run(sfile.toString(), gbinding);
1629 if ("STDIN".equals(groovyscript))
1631 // delete temp file that we made -
1632 // only if it was successfully executed
1635 } catch (Exception e)
1637 System.err.println("Exception Whilst trying to execute file " + sfile
1638 + " as a groovy script.");
1639 e.printStackTrace(System.err);
1644 public static boolean isHeadlessMode()
1646 String isheadless = System.getProperty("java.awt.headless");
1647 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1654 public AlignFrame[] getAlignFrames()
1656 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1657 : Desktop.getAlignFrames();
1662 * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
1666 // System.exit will run the shutdownHook first
1667 Jalview.exit("Quitting now. Bye!", 0);
1670 public static AlignFrame getCurrentAlignFrame()
1672 return Jalview.currentAlignFrame;
1675 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1677 Jalview.currentAlignFrame = currentAlignFrame;
1680 protected Commands getCommands()
1685 public static void exit(String message, int exitcode)
1687 Console.debug("Using Jalview.exit");
1688 if (message != null)
1690 Console.info(message);
1692 Console.error(message);
1694 System.exit(exitcode);
1698 * testoutput for string values
1700 protected static void testoutput(ArgParser ap, Arg a, String s1,
1703 BootstrapArgs bsa = ap.getBootstrapArgs();
1704 if (!bsa.getBoolean(Arg.TESTOUTPUT))
1706 if (!((s1 == null && s2 == null) || (s1 != null && s1.equals(s2))))
1708 Console.debug("testoutput with unmatching values '" + s1 + "' and '"
1709 + s2 + "' for arg " + a.argString());
1712 boolean isset = a.hasOption(Opt.BOOTSTRAP) ? bsa.contains(a)
1716 Console.warn("Arg '" + a.getName() + "' not set at all");
1719 testoutput(true, a, s1, s2);
1722 protected static void testoutput(BootstrapArgs bsa, Arg a, String s1,
1725 if (!bsa.getBoolean(Arg.TESTOUTPUT))
1727 if (!((s1 == null && s2 == null) || (s1 != null && s1.equals(s2))))
1729 Console.debug("testoutput with unmatching values '" + s1 + "' and '"
1730 + s2 + "' for arg " + a.argString());
1733 if (!a.hasOption(Opt.BOOTSTRAP))
1735 Console.error("Non-bootstrap Arg '" + a.getName()
1736 + "' given to testoutput(BootstrapArgs bsa, Arg a, String s1, String s2) with only BootstrapArgs");
1738 if (!bsa.contains(a))
1740 Console.warn("Arg '" + a.getName() + "' not set at all");
1743 testoutput(true, a, s1, s2);
1746 private static void testoutput(boolean yes, Arg a, String s1, String s2)
1748 if (yes && ((s1 == null && s2 == null)
1749 || (s1 != null && s1.equals(s2))))
1751 System.out.println("[TESTOUTPUT] arg " + a.argString() + "='" + s1
1757 * testoutput for boolean values
1759 protected static void testoutput(ArgParser ap, Arg a)
1763 BootstrapArgs bsa = ap.getBootstrapArgs();
1766 if (!bsa.getBoolean(Arg.TESTOUTPUT))
1768 boolean val = a.hasOption(Opt.BOOTSTRAP) ? bsa.getBoolean(a)
1770 boolean isset = a.hasOption(Opt.BOOTSTRAP) ? bsa.contains(a)
1774 Console.warn("Arg '" + a.getName() + "' not set at all");
1780 protected static void testoutput(BootstrapArgs bsa, Arg a)
1782 if (!bsa.getBoolean(Arg.TESTOUTPUT))
1784 if (!a.hasOption(Opt.BOOTSTRAP))
1786 Console.warn("Non-bootstrap Arg '" + a.getName()
1787 + "' given to testoutput(BootstrapArgs bsa, Arg a) with only BootstrapArgs");
1790 if (!bsa.contains(a))
1792 Console.warn("Arg '" + a.getName() + "' not set at all");
1795 testoutput(bsa.getBoolean(a), a);
1798 private static void testoutput(boolean yes, Arg a)
1800 System.out.println("[TESTOUTPUT] arg "
1801 + (yes ? a.argString() : a.negateArgString()) + " was set");