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.ArgParser;
69 import jalview.bin.argparser.BootstrapArgs;
70 import jalview.ext.so.SequenceOntology;
71 import jalview.gui.AlignFrame;
72 import jalview.gui.Desktop;
73 import jalview.gui.PromptUserConfig;
74 import jalview.gui.QuitHandler;
75 import jalview.gui.QuitHandler.QResponse;
76 import jalview.io.AppletFormatAdapter;
77 import jalview.io.BioJsHTMLOutput;
78 import jalview.io.DataSourceType;
79 import jalview.io.FileFormat;
80 import jalview.io.FileFormatException;
81 import jalview.io.FileFormatI;
82 import jalview.io.FileFormats;
83 import jalview.io.FileLoader;
84 import jalview.io.HtmlSvgOutput;
85 import jalview.io.IdentifyFile;
86 import jalview.io.NewickFile;
87 import jalview.io.gff.SequenceOntologyFactory;
88 import jalview.schemes.ColourSchemeI;
89 import jalview.schemes.ColourSchemeProperty;
90 import jalview.util.ChannelProperties;
91 import jalview.util.HttpUtils;
92 import jalview.util.LaunchUtils;
93 import jalview.util.MessageManager;
94 import jalview.util.Platform;
95 import jalview.ws.jws2.Jws2Discoverer;
98 * Main class for Jalview Application <br>
100 * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
101 * jalview.bin.Jalview
103 * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
104 * jalview.bin.Jalview jalview.bin.Jalview
106 * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
107 * embellish '*' to e.g. '*.jar')
110 * @version $Revision$
116 Platform.getURLCommandArguments();
117 Platform.addJ2SDirectDatabaseCall("https://www.jalview.org");
118 Platform.addJ2SDirectDatabaseCall("http://www.jalview.org");
119 Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk");
120 Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk");
124 * singleton instance of this class
126 private static Jalview instance;
128 private Desktop desktop;
130 protected Commands cmds;
132 public static AlignFrame currentAlignFrame;
136 if (!Platform.isJS())
143 // grab all the rights we can for the JVM
144 Policy.setPolicy(new Policy()
147 public PermissionCollection getPermissions(CodeSource codesource)
149 Permissions perms = new Permissions();
150 perms.add(new AllPermission());
155 public void refresh()
163 * keep track of feature fetching tasks.
171 * TODO: generalise to track all jalview events to orchestrate batch processing
175 private int queued = 0;
177 private int running = 0;
179 public FeatureFetcher()
184 public void addFetcher(final AlignFrame af,
185 final Vector<String> dasSources)
187 final long id = System.currentTimeMillis();
189 final FeatureFetcher us = this;
190 new Thread(new Runnable()
202 af.setProgressBar(MessageManager
203 .getString("status.das_features_being_retrived"), id);
204 af.featureSettings_actionPerformed(null);
205 af.setProgressBar(null, id);
214 public synchronized boolean allFinished()
216 return queued == 0 && running == 0;
221 public static Jalview getInstance()
227 * main class for Jalview application
230 * open <em>filename</em>
232 public static void main(String[] args)
234 // setLogging(); // BH - for event debugging in JavaScript
235 instance = new Jalview();
236 instance.doMain(args);
239 private static void logClass(String name)
241 // BH - for event debugging in JavaScript
242 ConsoleHandler consoleHandler = new ConsoleHandler();
243 consoleHandler.setLevel(Level.ALL);
244 Logger logger = Logger.getLogger(name);
245 logger.setLevel(Level.ALL);
246 logger.addHandler(consoleHandler);
249 @SuppressWarnings("unused")
250 private static void setLogging()
258 System.out.println("not in js");
261 // BH - for event debugging in JavaScript (Java mode only)
262 if (!Platform.isJS())
269 Logger.getLogger("").setLevel(Level.ALL);
270 logClass("java.awt.EventDispatchThread");
271 logClass("java.awt.EventQueue");
272 logClass("java.awt.Component");
273 logClass("java.awt.focus.Component");
274 logClass("java.awt.focus.DefaultKeyboardFocusManager");
282 void doMain(String[] args)
285 if (!Platform.isJS())
287 System.setSecurityManager(null);
290 // Move any new getdown-launcher-new.jar into place over old
291 // getdown-launcher.jar
292 String appdirString = System.getProperty("getdownappdir");
293 if (appdirString != null && appdirString.length() > 0)
295 final File appdir = new File(appdirString);
301 LaunchUtil.upgradeGetdown(
302 new File(appdir, "getdown-launcher-old.jar"),
303 new File(appdir, "getdown-launcher.jar"),
304 new File(appdir, "getdown-launcher-new.jar"));
309 // get args needed before proper ArgParser
310 BootstrapArgs bootstrapArgs = BootstrapArgs.getBootstrapArgs(args);
312 if (!Platform.isJS())
314 // are we being --quiet ?
315 if (bootstrapArgs.contains(Arg.QUIET))
317 OutputStream devNull = new OutputStream()
320 public void write(int b)
325 System.setOut(new PrintStream(devNull));
326 // redirecting stderr not working
327 if (bootstrapArgs.getList(Arg.QUIET).size() > 1)
329 System.setErr(new PrintStream(devNull));
335 .println("Java version: " + System.getProperty("java.version"));
336 System.out.println("Java Home: " + System.getProperty("java.home"));
337 System.out.println(System.getProperty("os.arch") + " "
338 + System.getProperty("os.name") + " "
339 + System.getProperty("os.version"));
341 String val = System.getProperty("sys.install4jVersion");
344 System.out.println("Install4j version: " + val);
346 val = System.getProperty("installer_template_version");
349 System.out.println("Install4j template version: " + val);
351 val = System.getProperty("launcher_version");
354 System.out.println("Launcher version: " + val);
357 if (Platform.isLinux() && LaunchUtils.getJavaVersion() < 11)
359 System.setProperty("flatlaf.uiScale", "1");
362 // get bootstrap properties (mainly for the logger level)
363 Properties bootstrapProperties = Cache
364 .bootstrapProperties(bootstrapArgs.get(Arg.PROPS));
366 // report Jalview version
367 Cache.loadBuildProperties(true);
370 ArgsParser aparser = new ArgsParser(args);
373 boolean headless = false;
375 boolean headlessArg = false;
379 String logLevel = bootstrapArgs.contains(Arg.DEBUG) ? "DEBUG" : null;
380 if (logLevel == null && !(bootstrapProperties == null))
382 logLevel = bootstrapProperties.getProperty(Cache.JALVIEWLOGLEVEL);
384 Console.initLogger(logLevel);
385 } catch (NoClassDefFoundError error)
387 error.printStackTrace();
388 String message = "\nEssential logging libraries not found."
389 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview";
390 Jalview.exit(message, 0);
393 // register SIGTERM listener
394 Runtime.getRuntime().addShutdownHook(new Thread()
398 Console.debug("Running shutdown hook");
399 if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT)
401 // Got to here by a SIGTERM signal.
402 // Note we will not actually cancel the quit from here -- it's too
403 // late -- but we can wait for saving files.
404 Console.debug("Checking for saving files");
405 QuitHandler.getQuitResponse(false);
409 Console.debug("Nothing more to do");
411 Console.debug("Exiting, bye!");
412 // shutdownHook cannot be cancelled, JVM will now halt
416 String usrPropsFile = bootstrapArgs.contains(Arg.PROPS)
417 ? bootstrapArgs.get(Arg.PROPS)
418 : aparser.getValue("props");
419 // if usrPropsFile == null, loadProperties will use the Channel
421 Cache.loadProperties(usrPropsFile);
422 if (usrPropsFile != null)
425 "CMD [-props " + usrPropsFile + "] executed successfully!");
430 // --argfile=... -- OVERRIDES ALL NON-BOOTSTRAP ARGS
431 if (bootstrapArgs.contains(Arg.ARGFILE))
433 argparser = ArgParser
434 .parseArgFiles(bootstrapArgs.getList(Arg.ARGFILE));
438 argparser = new ArgParser(args);
441 if (!Platform.isJS())
448 if (aparser.contains("help") || aparser.contains("h")
449 || argparser.getBool(Arg.HELP))
452 Jalview.exit(null, 0);
455 if (bootstrapArgs.contains(Arg.HEADLESS))
457 System.setProperty("java.awt.headless", "true");
459 headlessArg = argparser.getBool(Arg.HEADLESS);
461 if (aparser.contains("nodisplay") || aparser.contains("nogui")
462 || aparser.contains("headless"))
464 System.setProperty("java.awt.headless", "true");
470 // allow https handshakes to download intermediate certs if necessary
471 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
473 final String jabawsUrl = aparser.getValue("jabaws");
474 if (jabawsUrl != null)
478 Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
480 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
481 } catch (MalformedURLException e)
484 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
489 String defs = aparser.getValue("setprop");
492 int p = defs.indexOf('=');
495 System.err.println("Ignoring invalid setprop argument : " + defs);
499 System.out.println("Executing setprop argument: " + defs);
502 Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
504 // DISABLED FOR SECURITY REASONS
505 // TODO: add a property to allow properties to be overriden by cli args
506 // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
508 defs = aparser.getValue("setprop");
510 if (System.getProperty("java.awt.headless") != null
511 && System.getProperty("java.awt.headless").equals("true"))
515 System.setProperty("http.agent",
516 "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
520 Console.initLogger();
523 NoClassDefFoundError error)
525 error.printStackTrace();
526 String message = "\nEssential logging libraries not found."
527 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview";
528 Jalview.exit(message, 0);
532 if (!(headless || headlessArg))
536 * configure 'full' SO model if preferences say to, else use the default (full SO)
537 * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
539 boolean soDefault = !Platform.isJS();
540 if (Cache.getDefault("USE_FULL_SO", soDefault))
542 SequenceOntologyFactory.setInstance(new SequenceOntology());
545 if (!(headless || headlessArg))
547 Desktop.nosplash = "false".equals(bootstrapArgs.get(Arg.SPLASH))
548 || aparser.contains("nosplash");
549 desktop = new Desktop();
550 desktop.setInBatchMode(true); // indicate we are starting up
554 JalviewTaskbar.setTaskbar(this);
555 } catch (Exception e)
557 Console.info("Cannot set Taskbar");
558 Console.error(e.getMessage());
559 // e.printStackTrace();
560 } catch (Throwable t)
562 Console.info("Cannot set Taskbar");
563 Console.error(t.getMessage());
564 // t.printStackTrace();
567 // set Proxy settings before all the internet calls
568 Cache.setProxyPropertiesFromPreferences();
570 desktop.setVisible(true);
572 if (!Platform.isJS())
581 * Check to see that the JVM version being run is suitable for the Java
582 * version this Jalview was compiled for. Popup a warning if not.
584 if (!LaunchUtils.checkJavaVersion())
586 Console.warn("The Java version being used (Java "
587 + LaunchUtils.getJavaVersion()
588 + ") may lead to problems. This installation of Jalview should be used with Java "
589 + LaunchUtils.getJavaCompileVersion() + ".");
592 .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
595 MessageManager.getString("label.continue") };
596 JOptionPane.showOptionDialog(null,
597 MessageManager.formatMessage(
598 "warning.wrong_jvm_version_message",
599 LaunchUtils.getJavaVersion(),
600 LaunchUtils.getJavaCompileVersion()),
602 .getString("warning.wrong_jvm_version_title"),
603 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
604 null, options, options[0]);
608 if (!aparser.contains("nowebservicediscovery"))
610 desktop.startServiceDiscovery();
612 if (!aparser.contains("nousagestats"))
614 startUsageStats(desktop);
618 System.err.println("CMD [-nousagestats] executed successfully!");
621 if (!aparser.contains("noquestionnaire"))
623 String url = aparser.getValue("questionnaire");
626 // Start the desktop questionnaire prompter with the specified
628 Console.debug("Starting questionnaire url at " + url);
629 desktop.checkForQuestionnaire(url);
630 System.out.println("CMD questionnaire[-" + url
631 + "] executed successfully!");
635 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
637 // Start the desktop questionnaire prompter with the specified
640 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
642 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
644 "Starting questionnaire with default url: " + defurl);
645 desktop.checkForQuestionnaire(defurl);
652 .println("CMD [-noquestionnaire] executed successfully!");
655 if ((!aparser.contains("nonews")
656 && Cache.getProperty("NONEWS") == null
657 && !"false".equals(bootstrapArgs.get(Arg.NEWS)))
658 || "true".equals(bootstrapArgs.get(Arg.NEWS)))
660 desktop.checkForNews();
663 if (!aparser.contains("nohtmltemplates")
664 && Cache.getProperty("NOHTMLTEMPLATES") == null)
666 BioJsHTMLOutput.updateBioJS();
670 // Run Commands from cli
671 cmds = new Commands(argparser, headlessArg);
672 boolean commandsSuccess = cmds.argsWereParsed();
677 Jalview.exit("Successfully completed commands in headless mode", 0);
679 Console.info("Successfully completed commands");
685 Jalview.exit("Error when running Commands in headless mode", 1);
687 Console.warn("Error when running commands");
690 // Check if JVM and compile version might cause problems and log if it
692 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
694 Console.warn("The Java version being used (Java "
695 + LaunchUtils.getJavaVersion()
696 + ") may lead to problems. This installation of Jalview should be used with Java "
697 + LaunchUtils.getJavaCompileVersion() + ".");
700 String file = null, data = null;
702 FileFormatI format = null;
704 DataSourceType protocol = null;
706 FileLoader fileLoader = new FileLoader(!headless);
708 String groovyscript = null; // script to execute after all loading is
709 // completed one way or another
710 // extract groovy argument and execute if necessary
711 groovyscript = aparser.getValue("groovy", true);
712 file = aparser.getValue("open", true);
714 if (file == null && desktop == null && !commandsSuccess)
716 Jalview.exit("No files to open!", 1);
720 // Finally, deal with the remaining input data.
725 desktop.setProgressBar(
727 .getString("status.processing_commandline_args"),
728 progress = System.currentTimeMillis());
730 System.out.println("CMD [-open " + file + "] executed successfully!");
732 if (!Platform.isJS())
734 * ignore in JavaScript -- can't just file existence - could load it?
739 if (!HttpUtils.startsWithHttpOrHttps(file))
741 if (!(new File(file)).exists())
746 "Can't find file '" + file + "' in headless mode", 1);
748 Console.warn("Can't find file'" + file + "'");
753 protocol = AppletFormatAdapter.checkProtocol(file);
757 format = new IdentifyFile().identify(file, protocol);
758 } catch (FileFormatException e1)
763 AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
767 System.out.println("error");
771 setCurrentAlignFrame(af);
772 data = aparser.getValue("colour", true);
775 data.replaceAll("%20", " ");
777 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
778 af.getViewport(), af.getViewport().getAlignment(), data);
783 "CMD [-colour " + data + "] executed successfully!");
788 // Must maintain ability to use the groups flag
789 data = aparser.getValue("groups", true);
792 af.parseFeaturesFile(data,
793 AppletFormatAdapter.checkProtocol(data));
794 // System.out.println("Added " + data);
796 "CMD groups[-" + data + "] executed successfully!");
798 data = aparser.getValue("features", true);
801 af.parseFeaturesFile(data,
802 AppletFormatAdapter.checkProtocol(data));
803 // System.out.println("Added " + data);
805 "CMD [-features " + data + "] executed successfully!");
808 data = aparser.getValue("annotations", true);
811 af.loadJalviewDataFile(data, null, null, null);
812 // System.out.println("Added " + data);
814 "CMD [-annotations " + data + "] executed successfully!");
816 // set or clear the sortbytree flag.
817 if (aparser.contains("sortbytree"))
819 af.getViewport().setSortByTree(true);
820 if (af.getViewport().getSortByTree())
822 System.out.println("CMD [-sortbytree] executed successfully!");
825 if (aparser.contains("no-annotation"))
827 af.getViewport().setShowAnnotation(false);
828 if (!af.getViewport().isShowAnnotation())
830 System.out.println("CMD no-annotation executed successfully!");
833 if (aparser.contains("nosortbytree"))
835 af.getViewport().setSortByTree(false);
836 if (!af.getViewport().getSortByTree())
839 .println("CMD [-nosortbytree] executed successfully!");
842 data = aparser.getValue("tree", true);
848 "CMD [-tree " + data + "] executed successfully!");
849 NewickFile nf = new NewickFile(data,
850 AppletFormatAdapter.checkProtocol(data));
852 .setCurrentTree(af.showNewickTree(nf, data).getTree());
853 } catch (IOException ex)
855 System.err.println("Couldn't add tree " + data);
856 ex.printStackTrace(System.err);
859 // TODO - load PDB structure(s) to alignment JAL-629
860 // (associate with identical sequence in alignment, or a specified
862 if (groovyscript != null)
864 // Execute the groovy script after we've done all the rendering stuff
865 // and before any images or figures are generated.
866 System.out.println("Executing script " + groovyscript);
867 executeGroovyScript(groovyscript, af);
868 System.out.println("CMD groovy[" + groovyscript
869 + "] executed successfully!");
872 String imageName = "unnamed.png";
873 while (aparser.getSize() > 1)
875 String outputFormat = aparser.nextValue();
876 file = aparser.nextValue();
878 if (outputFormat.equalsIgnoreCase("png"))
880 af.createPNG(new File(file));
881 imageName = (new File(file)).getName();
882 System.out.println("Creating PNG image: " + file);
885 else if (outputFormat.equalsIgnoreCase("svg"))
887 File imageFile = new File(file);
888 imageName = imageFile.getName();
889 af.createSVG(imageFile);
890 System.out.println("Creating SVG image: " + file);
893 else if (outputFormat.equalsIgnoreCase("html"))
895 File imageFile = new File(file);
896 imageName = imageFile.getName();
897 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
898 htmlSVG.exportHTML(file);
900 System.out.println("Creating HTML image: " + file);
903 else if (outputFormat.equalsIgnoreCase("biojsmsa"))
907 System.err.println("The output html file must not be null");
912 BioJsHTMLOutput.refreshVersionInfo(
913 BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
914 } catch (URISyntaxException e)
918 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
919 bjs.exportHTML(file);
921 .println("Creating BioJS MSA Viwer HTML file: " + file);
924 else if (outputFormat.equalsIgnoreCase("imgMap"))
926 af.createImageMap(new File(file), imageName);
927 System.out.println("Creating image map: " + file);
930 else if (outputFormat.equalsIgnoreCase("eps"))
932 File outputFile = new File(file);
934 "Creating EPS file: " + outputFile.getAbsolutePath());
935 af.createEPS(outputFile);
938 FileFormatI outFormat = null;
941 outFormat = FileFormats.getInstance().forName(outputFormat);
942 } catch (Exception formatP)
944 System.out.println("Couldn't parse " + outFormat
945 + " as a valid Jalview format string.");
947 if (outFormat != null)
949 if (!outFormat.isWritable())
952 "This version of Jalview does not support alignment export as "
957 af.saveAlignment(file, outFormat);
958 if (af.isSaveAlignmentSuccessful())
960 System.out.println("Written alignment in "
961 + outFormat.getName() + " format to " + file);
965 System.out.println("Error writing file " + file + " in "
966 + outFormat.getName() + " format!!");
973 while (aparser.getSize() > 0)
975 System.out.println("Unknown arg: " + aparser.nextValue());
980 AlignFrame startUpAlframe = null;
981 // We'll only open the default file if the desktop is visible.
983 // ////////////////////
985 if (!Platform.isJS() && !headless && file == null
986 && Cache.getDefault("SHOW_STARTUP_FILE", true)
987 && !cmds.commandArgsProvided())
988 // don't open the startup file if command line args have been processed
989 // (&& !Commands.commandArgsProvided())
996 file = Cache.getDefault("STARTUP_FILE",
997 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
998 + "/examples/exampleFile_2_7.jvp");
999 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
1001 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
1003 file.replace("http:", "https:");
1004 // hardwire upgrade of the startup file
1005 file.replace("_2_3", "_2_7");
1006 file.replace("2_7.jar", "2_7.jvp");
1007 // and remove the stale setting
1008 Cache.removeProperty("STARTUP_FILE");
1011 protocol = AppletFormatAdapter.checkProtocol(file);
1013 if (file.endsWith(".jar"))
1015 format = FileFormat.Jalview;
1021 format = new IdentifyFile().identify(file, protocol);
1022 } catch (FileFormatException e)
1028 startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
1030 // don't ask to save when quitting if only the startup file has been
1032 Console.debug("Resetting up-to-date flag for startup file");
1033 startUpAlframe.getViewport().setSavedUpToDate(true);
1034 // extract groovy arguments before anything else.
1037 // Once all other stuff is done, execute any groovy scripts (in order)
1038 if (groovyscript != null)
1040 if (Cache.groovyJarsPresent())
1042 System.out.println("Executing script " + groovyscript);
1043 executeGroovyScript(groovyscript, startUpAlframe);
1048 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
1052 // and finally, turn off batch mode indicator - if the desktop still exists
1053 if (desktop != null)
1057 desktop.setProgressBar(null, progress);
1059 desktop.setInBatchMode(false);
1063 private static void setLookAndFeel()
1065 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
1067 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
1068 // try Quaqua/Vaqua.
1069 String lafProp = System.getProperty("laf");
1070 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
1071 String laf = "none";
1072 if (lafProp != null)
1076 else if (lafSetting != null)
1080 boolean lafSet = false;
1083 case "crossplatform":
1084 lafSet = setCrossPlatformLookAndFeel();
1087 Console.error("Could not set requested laf=" + laf);
1091 lafSet = setSystemLookAndFeel();
1094 Console.error("Could not set requested laf=" + laf);
1098 lafSet = setGtkLookAndFeel();
1101 Console.error("Could not set requested laf=" + laf);
1105 lafSet = setMetalLookAndFeel();
1108 Console.error("Could not set requested laf=" + laf);
1112 lafSet = setNimbusLookAndFeel();
1115 Console.error("Could not set requested laf=" + laf);
1119 lafSet = setFlatLookAndFeel();
1122 Console.error("Could not set requested laf=" + laf);
1126 lafSet = setMacLookAndFeel();
1129 Console.error("Could not set requested laf=" + laf);
1135 Console.error("Requested laf=" + laf + " not implemented");
1139 setSystemLookAndFeel();
1140 if (Platform.isLinux())
1142 setLinuxLookAndFeel();
1144 if (Platform.isMac())
1146 setMacLookAndFeel();
1151 private static boolean setCrossPlatformLookAndFeel()
1153 boolean set = false;
1156 UIManager.setLookAndFeel(
1157 UIManager.getCrossPlatformLookAndFeelClassName());
1159 } catch (Exception ex)
1161 Console.error("Unexpected Look and Feel Exception");
1162 Console.error(ex.getMessage());
1163 Console.debug(Cache.getStackTraceString(ex));
1168 private static boolean setSystemLookAndFeel()
1170 boolean set = false;
1173 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1175 } catch (Exception ex)
1177 Console.error("Unexpected Look and Feel Exception");
1178 Console.error(ex.getMessage());
1179 Console.debug(Cache.getStackTraceString(ex));
1184 private static boolean setSpecificLookAndFeel(String name,
1185 String className, boolean nameStartsWith)
1187 boolean set = false;
1190 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1192 if (info.getName() != null && nameStartsWith
1193 ? info.getName().toLowerCase(Locale.ROOT)
1194 .startsWith(name.toLowerCase(Locale.ROOT))
1195 : info.getName().toLowerCase(Locale.ROOT)
1196 .equals(name.toLowerCase(Locale.ROOT)))
1198 className = info.getClassName();
1202 UIManager.setLookAndFeel(className);
1204 } catch (Exception ex)
1206 Console.error("Unexpected Look and Feel Exception");
1207 Console.error(ex.getMessage());
1208 Console.debug(Cache.getStackTraceString(ex));
1213 private static boolean setGtkLookAndFeel()
1215 return setSpecificLookAndFeel("gtk",
1216 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1219 private static boolean setMetalLookAndFeel()
1221 return setSpecificLookAndFeel("metal",
1222 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1225 private static boolean setNimbusLookAndFeel()
1227 return setSpecificLookAndFeel("nimbus",
1228 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1231 private static boolean setFlatLookAndFeel()
1233 boolean set = false;
1234 if (SystemInfo.isMacOS)
1238 UIManager.setLookAndFeel(
1239 "com.formdev.flatlaf.themes.FlatMacLightLaf");
1241 Console.debug("Using FlatMacLightLaf");
1242 } catch (ClassNotFoundException | InstantiationException
1243 | IllegalAccessException | UnsupportedLookAndFeelException e)
1245 Console.debug("Exception loading FlatLightLaf", e);
1247 System.setProperty("apple.laf.useScreenMenuBar", "true");
1248 System.setProperty("apple.awt.application.name",
1249 ChannelProperties.getProperty("app_name"));
1250 System.setProperty("apple.awt.application.appearance", "system");
1251 if (SystemInfo.isMacFullWindowContentSupported
1252 && Desktop.desktop != null)
1254 Console.debug("Setting transparent title bar");
1255 Desktop.desktop.getRootPane()
1256 .putClientProperty("apple.awt.fullWindowContent", true);
1257 Desktop.desktop.getRootPane()
1258 .putClientProperty("apple.awt.transparentTitleBar", true);
1259 Desktop.desktop.getRootPane()
1260 .putClientProperty("apple.awt.fullscreenable", true);
1262 SwingUtilities.invokeLater(() -> {
1263 FlatMacLightLaf.setup();
1265 Console.debug("Using FlatMacLightLaf");
1272 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1274 Console.debug("Using FlatLightLaf");
1275 } catch (ClassNotFoundException | InstantiationException
1276 | IllegalAccessException | UnsupportedLookAndFeelException e)
1278 Console.debug("Exception loading FlatLightLaf", e);
1280 // Windows specific properties here
1281 SwingUtilities.invokeLater(() -> {
1282 FlatLightLaf.setup();
1284 Console.debug("Using FlatLightLaf");
1287 else if (SystemInfo.isLinux)
1291 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1293 Console.debug("Using FlatLightLaf");
1294 } catch (ClassNotFoundException | InstantiationException
1295 | IllegalAccessException | UnsupportedLookAndFeelException e)
1297 Console.debug("Exception loading FlatLightLaf", e);
1299 // enable custom window decorations
1300 JFrame.setDefaultLookAndFeelDecorated(true);
1301 JDialog.setDefaultLookAndFeelDecorated(true);
1302 SwingUtilities.invokeLater(() -> {
1303 FlatLightLaf.setup();
1305 Console.debug("Using FlatLightLaf");
1313 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1315 Console.debug("Using FlatLightLaf");
1316 } catch (ClassNotFoundException | InstantiationException
1317 | IllegalAccessException | UnsupportedLookAndFeelException e)
1319 Console.debug("Exception loading FlatLightLaf", e);
1325 UIManager.put("TabbedPane.tabType", "card");
1326 UIManager.put("TabbedPane.showTabSeparators", true);
1327 UIManager.put("TabbedPane.showContentSeparator", true);
1328 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1329 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1330 UIManager.put("TabbedPane.hasFullBorder", true);
1331 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1332 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1333 UIManager.put("TabbedPane.smoothScrolling", true);
1334 UIManager.put("TabbedPane.tabWidthMode", "compact");
1335 UIManager.put("TabbedPane.selectedBackground", Color.white);
1338 Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
1342 private static boolean setMacLookAndFeel()
1344 boolean set = false;
1345 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1346 ChannelProperties.getProperty("app_name"));
1347 System.setProperty("apple.laf.useScreenMenuBar", "true");
1349 * broken native LAFs on (ARM?) macbooks
1350 set = setQuaquaLookAndFeel();
1351 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1352 .toLowerCase(Locale.ROOT).contains("quaqua"))
1354 set = setVaquaLookAndFeel();
1357 set = setFlatLookAndFeel();
1361 private static boolean setLinuxLookAndFeel()
1363 boolean set = false;
1364 set = setFlatLookAndFeel();
1366 set = setMetalLookAndFeel();
1367 // avoid GtkLookAndFeel -- not good results especially on HiDPI
1369 set = setNimbusLookAndFeel();
1373 private static void showUsage()
1376 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1377 + "-nodisplay\tRun Jalview without User Interface.\n"
1378 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1379 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1380 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1381 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1382 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1383 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1384 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1385 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1386 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1387 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1388 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1389 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1390 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1391 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1392 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1393 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1394 + "-html FILE\tCreate HTML file from alignment.\n"
1395 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1396 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1397 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1398 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1399 + "-noquestionnaire\tTurn off questionnaire check.\n"
1400 + "-nonews\tTurn off check for Jalview news.\n"
1401 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1402 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1404 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1405 // after all other properties files have been read\n\t
1406 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1407 // passed in correctly)"
1408 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1409 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1410 + "-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"
1411 + "-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"
1412 + "-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"
1413 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1416 private static void startUsageStats(final Desktop desktop)
1419 * start a User Config prompt asking if we can log usage statistics.
1421 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
1422 "USAGESTATS", "Jalview Usage Statistics",
1423 "Do you want to help make Jalview better by enabling "
1424 + "the collection of usage statistics with Google Analytics ?"
1425 + "\n\n(you can enable or disable usage tracking in the preferences)",
1432 "Initialising googletracker for usage stats.");
1433 Cache.initGoogleTracker();
1434 Console.debug("Tracking enabled.");
1441 Console.debug("Not enabling Google Tracking.");
1444 desktop.addDialogThread(prompter);
1448 * Locate the given string as a file and pass it to the groovy interpreter.
1450 * @param groovyscript
1451 * the script to execute
1452 * @param jalviewContext
1453 * the Jalview Desktop object passed in to the groovy binding as the
1456 private void executeGroovyScript(String groovyscript, AlignFrame af)
1459 * for scripts contained in files
1466 if (groovyscript.trim().equals("STDIN"))
1468 // read from stdin into a tempfile and execute it
1471 tfile = File.createTempFile("jalview", "groovy");
1472 PrintWriter outfile = new PrintWriter(
1473 new OutputStreamWriter(new FileOutputStream(tfile)));
1474 BufferedReader br = new BufferedReader(
1475 new InputStreamReader(System.in));
1477 while ((line = br.readLine()) != null)
1479 outfile.write(line + "\n");
1485 } catch (Exception ex)
1487 System.err.println("Failed to read from STDIN into tempfile "
1488 + ((tfile == null) ? "(tempfile wasn't created)"
1489 : tfile.toString()));
1490 ex.printStackTrace();
1495 sfile = tfile.toURI().toURL();
1496 } catch (Exception x)
1499 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1501 x.printStackTrace();
1509 sfile = new URI(groovyscript).toURL();
1510 } catch (Exception x)
1512 tfile = new File(groovyscript);
1513 if (!tfile.exists())
1515 System.err.println("File '" + groovyscript + "' does not exist.");
1518 if (!tfile.canRead())
1520 System.err.println("File '" + groovyscript + "' cannot be read.");
1523 if (tfile.length() < 1)
1525 System.err.println("File '" + groovyscript + "' is empty.");
1530 sfile = tfile.getAbsoluteFile().toURI().toURL();
1531 } catch (Exception ex)
1533 System.err.println("Failed to create a file URL for "
1534 + tfile.getAbsoluteFile());
1541 Map<String, java.lang.Object> vbinding = new HashMap<>();
1542 vbinding.put("Jalview", this);
1545 vbinding.put("currentAlFrame", af);
1547 Binding gbinding = new Binding(vbinding);
1548 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1549 gse.run(sfile.toString(), gbinding);
1550 if ("STDIN".equals(groovyscript))
1552 // delete temp file that we made -
1553 // only if it was successfully executed
1556 } catch (Exception e)
1558 System.err.println("Exception Whilst trying to execute file " + sfile
1559 + " as a groovy script.");
1560 e.printStackTrace(System.err);
1565 public static boolean isHeadlessMode()
1567 String isheadless = System.getProperty("java.awt.headless");
1568 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1575 public AlignFrame[] getAlignFrames()
1577 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1578 : Desktop.getAlignFrames();
1583 * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
1587 // System.exit will run the shutdownHook first
1588 Jalview.exit("Quitting now. Bye!", 0);
1591 public static AlignFrame getCurrentAlignFrame()
1593 return Jalview.currentAlignFrame;
1596 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1598 Jalview.currentAlignFrame = currentAlignFrame;
1601 protected Commands getCommands()
1606 public static void exit(String message, int exitcode)
1608 Console.debug("Using Jalview.exit");
1609 if (message != null)
1611 Console.info(message);
1613 Console.error(message);
1615 System.exit(exitcode);