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)
421 Cache.loadProperties(usrPropsFile);
423 "CMD [-props " + usrPropsFile + "] executed successfully!");
428 // --argfile=... -- OVERRIDES ALL NON-BOOTSTRAP ARGS
429 if (bootstrapArgs.contains(Arg.ARGFILE))
431 argparser = ArgParser
432 .parseArgFiles(bootstrapArgs.getList(Arg.ARGFILE));
436 argparser = new ArgParser(args);
439 if (!Platform.isJS())
446 if (aparser.contains("help") || aparser.contains("h")
447 || argparser.getBool(Arg.HELP))
450 Jalview.exit(null, 0);
453 if (bootstrapArgs.contains(Arg.HEADLESS))
455 System.setProperty("java.awt.headless", "true");
457 headlessArg = argparser.getBool(Arg.HEADLESS);
459 if (aparser.contains("nodisplay") || aparser.contains("nogui")
460 || aparser.contains("headless"))
462 System.setProperty("java.awt.headless", "true");
468 // allow https handshakes to download intermediate certs if necessary
469 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
471 final String jabawsUrl = aparser.getValue("jabaws");
472 if (jabawsUrl != null)
476 Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
478 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
479 } catch (MalformedURLException e)
482 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
487 String defs = aparser.getValue("setprop");
490 int p = defs.indexOf('=');
493 System.err.println("Ignoring invalid setprop argument : " + defs);
497 System.out.println("Executing setprop argument: " + defs);
500 Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
502 // DISABLED FOR SECURITY REASONS
503 // TODO: add a property to allow properties to be overriden by cli args
504 // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
506 defs = aparser.getValue("setprop");
508 if (System.getProperty("java.awt.headless") != null
509 && System.getProperty("java.awt.headless").equals("true"))
513 System.setProperty("http.agent",
514 "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
518 Console.initLogger();
521 NoClassDefFoundError error)
523 error.printStackTrace();
524 String message = "\nEssential logging libraries not found."
525 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview";
526 Jalview.exit(message, 0);
530 if (!(headless || headlessArg))
534 * configure 'full' SO model if preferences say to, else use the default (full SO)
535 * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
537 boolean soDefault = !Platform.isJS();
538 if (Cache.getDefault("USE_FULL_SO", soDefault))
540 SequenceOntologyFactory.setInstance(new SequenceOntology());
543 if (!(headless || headlessArg))
545 Desktop.nosplash = aparser.contains("nosplash");
546 desktop = new Desktop();
547 desktop.setInBatchMode(true); // indicate we are starting up
551 JalviewTaskbar.setTaskbar(this);
552 } catch (Exception e)
554 Console.info("Cannot set Taskbar");
555 Console.error(e.getMessage());
556 // e.printStackTrace();
557 } catch (Throwable t)
559 Console.info("Cannot set Taskbar");
560 Console.error(t.getMessage());
561 // t.printStackTrace();
564 // set Proxy settings before all the internet calls
565 Cache.setProxyPropertiesFromPreferences();
567 desktop.setVisible(true);
569 if (!Platform.isJS())
578 * Check to see that the JVM version being run is suitable for the Java
579 * version this Jalview was compiled for. Popup a warning if not.
581 if (!LaunchUtils.checkJavaVersion())
583 Console.warn("The Java version being used (Java "
584 + LaunchUtils.getJavaVersion()
585 + ") may lead to problems. This installation of Jalview should be used with Java "
586 + LaunchUtils.getJavaCompileVersion() + ".");
589 .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
592 MessageManager.getString("label.continue") };
593 JOptionPane.showOptionDialog(null,
594 MessageManager.formatMessage(
595 "warning.wrong_jvm_version_message",
596 LaunchUtils.getJavaVersion(),
597 LaunchUtils.getJavaCompileVersion()),
599 .getString("warning.wrong_jvm_version_title"),
600 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
601 null, options, options[0]);
605 if (!aparser.contains("nowebservicediscovery"))
607 desktop.startServiceDiscovery();
609 if (!aparser.contains("nousagestats"))
611 startUsageStats(desktop);
615 System.err.println("CMD [-nousagestats] executed successfully!");
618 if (!aparser.contains("noquestionnaire"))
620 String url = aparser.getValue("questionnaire");
623 // Start the desktop questionnaire prompter with the specified
625 Console.debug("Starting questionnaire url at " + url);
626 desktop.checkForQuestionnaire(url);
627 System.out.println("CMD questionnaire[-" + url
628 + "] executed successfully!");
632 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
634 // Start the desktop questionnaire prompter with the specified
637 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
639 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
641 "Starting questionnaire with default url: " + defurl);
642 desktop.checkForQuestionnaire(defurl);
649 .println("CMD [-noquestionnaire] executed successfully!");
652 if ((!aparser.contains("nonews")
653 && Cache.getProperty("NONEWS") == null
654 && !"false".equals(bootstrapArgs.get(Arg.NEWS)))
655 || "true".equals(bootstrapArgs.get(Arg.NEWS)))
657 desktop.checkForNews();
660 if (!aparser.contains("nohtmltemplates")
661 && Cache.getProperty("NOHTMLTEMPLATES") == null)
663 BioJsHTMLOutput.updateBioJS();
667 // Run Commands from cli
668 cmds = new Commands(argparser, headlessArg);
669 boolean commandsSuccess = cmds.argsWereParsed();
674 Jalview.exit("Successfully completed commands in headless mode", 0);
676 Console.info("Successfully completed commands");
682 Jalview.exit("Error when running Commands in headless mode", 1);
684 Console.warn("Error when running commands");
687 // Check if JVM and compile version might cause problems and log if it
689 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
691 Console.warn("The Java version being used (Java "
692 + LaunchUtils.getJavaVersion()
693 + ") may lead to problems. This installation of Jalview should be used with Java "
694 + LaunchUtils.getJavaCompileVersion() + ".");
697 String file = null, data = null;
699 FileFormatI format = null;
701 DataSourceType protocol = null;
703 FileLoader fileLoader = new FileLoader(!headless);
705 String groovyscript = null; // script to execute after all loading is
706 // completed one way or another
707 // extract groovy argument and execute if necessary
708 groovyscript = aparser.getValue("groovy", true);
709 file = aparser.getValue("open", true);
711 if (file == null && desktop == null && !commandsSuccess)
713 Jalview.exit("No files to open!", 1);
717 // Finally, deal with the remaining input data.
722 desktop.setProgressBar(
724 .getString("status.processing_commandline_args"),
725 progress = System.currentTimeMillis());
727 System.out.println("CMD [-open " + file + "] executed successfully!");
729 if (!Platform.isJS())
731 * ignore in JavaScript -- can't just file existence - could load it?
736 if (!HttpUtils.startsWithHttpOrHttps(file))
738 if (!(new File(file)).exists())
743 "Can't find file '" + file + "' in headless mode", 1);
745 Console.warn("Can't find file'" + file + "'");
750 protocol = AppletFormatAdapter.checkProtocol(file);
754 format = new IdentifyFile().identify(file, protocol);
755 } catch (FileFormatException e1)
760 AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
764 System.out.println("error");
768 setCurrentAlignFrame(af);
769 data = aparser.getValue("colour", true);
772 data.replaceAll("%20", " ");
774 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
775 af.getViewport(), af.getViewport().getAlignment(), data);
780 "CMD [-colour " + data + "] executed successfully!");
785 // Must maintain ability to use the groups flag
786 data = aparser.getValue("groups", true);
789 af.parseFeaturesFile(data,
790 AppletFormatAdapter.checkProtocol(data));
791 // System.out.println("Added " + data);
793 "CMD groups[-" + data + "] executed successfully!");
795 data = aparser.getValue("features", true);
798 af.parseFeaturesFile(data,
799 AppletFormatAdapter.checkProtocol(data));
800 // System.out.println("Added " + data);
802 "CMD [-features " + data + "] executed successfully!");
805 data = aparser.getValue("annotations", true);
808 af.loadJalviewDataFile(data, null, null, null);
809 // System.out.println("Added " + data);
811 "CMD [-annotations " + data + "] executed successfully!");
813 // set or clear the sortbytree flag.
814 if (aparser.contains("sortbytree"))
816 af.getViewport().setSortByTree(true);
817 if (af.getViewport().getSortByTree())
819 System.out.println("CMD [-sortbytree] executed successfully!");
822 if (aparser.contains("no-annotation"))
824 af.getViewport().setShowAnnotation(false);
825 if (!af.getViewport().isShowAnnotation())
827 System.out.println("CMD no-annotation executed successfully!");
830 if (aparser.contains("nosortbytree"))
832 af.getViewport().setSortByTree(false);
833 if (!af.getViewport().getSortByTree())
836 .println("CMD [-nosortbytree] executed successfully!");
839 data = aparser.getValue("tree", true);
845 "CMD [-tree " + data + "] executed successfully!");
846 NewickFile nf = new NewickFile(data,
847 AppletFormatAdapter.checkProtocol(data));
849 .setCurrentTree(af.showNewickTree(nf, data).getTree());
850 } catch (IOException ex)
852 System.err.println("Couldn't add tree " + data);
853 ex.printStackTrace(System.err);
856 // TODO - load PDB structure(s) to alignment JAL-629
857 // (associate with identical sequence in alignment, or a specified
859 if (groovyscript != null)
861 // Execute the groovy script after we've done all the rendering stuff
862 // and before any images or figures are generated.
863 System.out.println("Executing script " + groovyscript);
864 executeGroovyScript(groovyscript, af);
865 System.out.println("CMD groovy[" + groovyscript
866 + "] executed successfully!");
869 String imageName = "unnamed.png";
870 while (aparser.getSize() > 1)
872 String outputFormat = aparser.nextValue();
873 file = aparser.nextValue();
875 if (outputFormat.equalsIgnoreCase("png"))
877 af.createPNG(new File(file));
878 imageName = (new File(file)).getName();
879 System.out.println("Creating PNG image: " + file);
882 else if (outputFormat.equalsIgnoreCase("svg"))
884 File imageFile = new File(file);
885 imageName = imageFile.getName();
886 af.createSVG(imageFile);
887 System.out.println("Creating SVG image: " + file);
890 else if (outputFormat.equalsIgnoreCase("html"))
892 File imageFile = new File(file);
893 imageName = imageFile.getName();
894 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
895 htmlSVG.exportHTML(file);
897 System.out.println("Creating HTML image: " + file);
900 else if (outputFormat.equalsIgnoreCase("biojsmsa"))
904 System.err.println("The output html file must not be null");
909 BioJsHTMLOutput.refreshVersionInfo(
910 BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
911 } catch (URISyntaxException e)
915 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
916 bjs.exportHTML(file);
918 .println("Creating BioJS MSA Viwer HTML file: " + file);
921 else if (outputFormat.equalsIgnoreCase("imgMap"))
923 af.createImageMap(new File(file), imageName);
924 System.out.println("Creating image map: " + file);
927 else if (outputFormat.equalsIgnoreCase("eps"))
929 File outputFile = new File(file);
931 "Creating EPS file: " + outputFile.getAbsolutePath());
932 af.createEPS(outputFile);
935 FileFormatI outFormat = null;
938 outFormat = FileFormats.getInstance().forName(outputFormat);
939 } catch (Exception formatP)
941 System.out.println("Couldn't parse " + outFormat
942 + " as a valid Jalview format string.");
944 if (outFormat != null)
946 if (!outFormat.isWritable())
949 "This version of Jalview does not support alignment export as "
954 af.saveAlignment(file, outFormat);
955 if (af.isSaveAlignmentSuccessful())
957 System.out.println("Written alignment in "
958 + outFormat.getName() + " format to " + file);
962 System.out.println("Error writing file " + file + " in "
963 + outFormat.getName() + " format!!");
970 while (aparser.getSize() > 0)
972 System.out.println("Unknown arg: " + aparser.nextValue());
977 AlignFrame startUpAlframe = null;
978 // We'll only open the default file if the desktop is visible.
980 // ////////////////////
982 if (!Platform.isJS() && !headless && file == null
983 && Cache.getDefault("SHOW_STARTUP_FILE", true)
984 && !cmds.commandArgsProvided())
985 // don't open the startup file if command line args have been processed
986 // (&& !Commands.commandArgsProvided())
993 file = Cache.getDefault("STARTUP_FILE",
994 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
995 + "/examples/exampleFile_2_7.jvp");
996 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
998 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
1000 file.replace("http:", "https:");
1001 // hardwire upgrade of the startup file
1002 file.replace("_2_3", "_2_7");
1003 file.replace("2_7.jar", "2_7.jvp");
1004 // and remove the stale setting
1005 Cache.removeProperty("STARTUP_FILE");
1008 protocol = AppletFormatAdapter.checkProtocol(file);
1010 if (file.endsWith(".jar"))
1012 format = FileFormat.Jalview;
1018 format = new IdentifyFile().identify(file, protocol);
1019 } catch (FileFormatException e)
1025 startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
1027 // don't ask to save when quitting if only the startup file has been
1029 Console.debug("Resetting up-to-date flag for startup file");
1030 startUpAlframe.getViewport().setSavedUpToDate(true);
1031 // extract groovy arguments before anything else.
1034 // Once all other stuff is done, execute any groovy scripts (in order)
1035 if (groovyscript != null)
1037 if (Cache.groovyJarsPresent())
1039 System.out.println("Executing script " + groovyscript);
1040 executeGroovyScript(groovyscript, startUpAlframe);
1045 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
1049 // and finally, turn off batch mode indicator - if the desktop still exists
1050 if (desktop != null)
1054 desktop.setProgressBar(null, progress);
1056 desktop.setInBatchMode(false);
1060 private static void setLookAndFeel()
1062 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
1064 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
1065 // try Quaqua/Vaqua.
1066 String lafProp = System.getProperty("laf");
1067 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
1068 String laf = "none";
1069 if (lafProp != null)
1073 else if (lafSetting != null)
1077 boolean lafSet = false;
1080 case "crossplatform":
1081 lafSet = setCrossPlatformLookAndFeel();
1084 Console.error("Could not set requested laf=" + laf);
1088 lafSet = setSystemLookAndFeel();
1091 Console.error("Could not set requested laf=" + laf);
1095 lafSet = setGtkLookAndFeel();
1098 Console.error("Could not set requested laf=" + laf);
1102 lafSet = setMetalLookAndFeel();
1105 Console.error("Could not set requested laf=" + laf);
1109 lafSet = setNimbusLookAndFeel();
1112 Console.error("Could not set requested laf=" + laf);
1116 lafSet = setFlatLookAndFeel();
1119 Console.error("Could not set requested laf=" + laf);
1123 lafSet = setMacLookAndFeel();
1126 Console.error("Could not set requested laf=" + laf);
1132 Console.error("Requested laf=" + laf + " not implemented");
1136 setSystemLookAndFeel();
1137 if (Platform.isLinux())
1139 setLinuxLookAndFeel();
1141 if (Platform.isMac())
1143 setMacLookAndFeel();
1148 private static boolean setCrossPlatformLookAndFeel()
1150 boolean set = false;
1153 UIManager.setLookAndFeel(
1154 UIManager.getCrossPlatformLookAndFeelClassName());
1156 } catch (Exception ex)
1158 Console.error("Unexpected Look and Feel Exception");
1159 Console.error(ex.getMessage());
1160 Console.debug(Cache.getStackTraceString(ex));
1165 private static boolean setSystemLookAndFeel()
1167 boolean set = false;
1170 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1172 } catch (Exception ex)
1174 Console.error("Unexpected Look and Feel Exception");
1175 Console.error(ex.getMessage());
1176 Console.debug(Cache.getStackTraceString(ex));
1181 private static boolean setSpecificLookAndFeel(String name,
1182 String className, boolean nameStartsWith)
1184 boolean set = false;
1187 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1189 if (info.getName() != null && nameStartsWith
1190 ? info.getName().toLowerCase(Locale.ROOT)
1191 .startsWith(name.toLowerCase(Locale.ROOT))
1192 : info.getName().toLowerCase(Locale.ROOT)
1193 .equals(name.toLowerCase(Locale.ROOT)))
1195 className = info.getClassName();
1199 UIManager.setLookAndFeel(className);
1201 } catch (Exception ex)
1203 Console.error("Unexpected Look and Feel Exception");
1204 Console.error(ex.getMessage());
1205 Console.debug(Cache.getStackTraceString(ex));
1210 private static boolean setGtkLookAndFeel()
1212 return setSpecificLookAndFeel("gtk",
1213 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1216 private static boolean setMetalLookAndFeel()
1218 return setSpecificLookAndFeel("metal",
1219 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1222 private static boolean setNimbusLookAndFeel()
1224 return setSpecificLookAndFeel("nimbus",
1225 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1228 private static boolean setFlatLookAndFeel()
1230 boolean set = false;
1231 if (SystemInfo.isMacOS)
1235 UIManager.setLookAndFeel(
1236 "com.formdev.flatlaf.themes.FlatMacLightLaf");
1238 Console.debug("Using FlatMacLightLaf");
1239 } catch (ClassNotFoundException | InstantiationException
1240 | IllegalAccessException | UnsupportedLookAndFeelException e)
1242 Console.debug("Exception loading FlatLightLaf", e);
1244 System.setProperty("apple.laf.useScreenMenuBar", "true");
1245 System.setProperty("apple.awt.application.name",
1246 ChannelProperties.getProperty("app_name"));
1247 System.setProperty("apple.awt.application.appearance", "system");
1248 if (SystemInfo.isMacFullWindowContentSupported
1249 && Desktop.desktop != null)
1251 Console.debug("Setting transparent title bar");
1252 Desktop.desktop.getRootPane()
1253 .putClientProperty("apple.awt.fullWindowContent", true);
1254 Desktop.desktop.getRootPane()
1255 .putClientProperty("apple.awt.transparentTitleBar", true);
1256 Desktop.desktop.getRootPane()
1257 .putClientProperty("apple.awt.fullscreenable", true);
1259 SwingUtilities.invokeLater(() -> {
1260 FlatMacLightLaf.setup();
1262 Console.debug("Using FlatMacLightLaf");
1269 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1271 Console.debug("Using FlatLightLaf");
1272 } catch (ClassNotFoundException | InstantiationException
1273 | IllegalAccessException | UnsupportedLookAndFeelException e)
1275 Console.debug("Exception loading FlatLightLaf", e);
1277 // Windows specific properties here
1278 SwingUtilities.invokeLater(() -> {
1279 FlatLightLaf.setup();
1281 Console.debug("Using FlatLightLaf");
1284 else if (SystemInfo.isLinux)
1288 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1290 Console.debug("Using FlatLightLaf");
1291 } catch (ClassNotFoundException | InstantiationException
1292 | IllegalAccessException | UnsupportedLookAndFeelException e)
1294 Console.debug("Exception loading FlatLightLaf", e);
1296 // enable custom window decorations
1297 JFrame.setDefaultLookAndFeelDecorated(true);
1298 JDialog.setDefaultLookAndFeelDecorated(true);
1299 SwingUtilities.invokeLater(() -> {
1300 FlatLightLaf.setup();
1302 Console.debug("Using FlatLightLaf");
1310 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1312 Console.debug("Using FlatLightLaf");
1313 } catch (ClassNotFoundException | InstantiationException
1314 | IllegalAccessException | UnsupportedLookAndFeelException e)
1316 Console.debug("Exception loading FlatLightLaf", e);
1322 UIManager.put("TabbedPane.tabType", "card");
1323 UIManager.put("TabbedPane.showTabSeparators", true);
1324 UIManager.put("TabbedPane.showContentSeparator", true);
1325 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1326 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1327 UIManager.put("TabbedPane.hasFullBorder", true);
1328 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1329 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1330 UIManager.put("TabbedPane.smoothScrolling", true);
1331 UIManager.put("TabbedPane.tabWidthMode", "compact");
1332 UIManager.put("TabbedPane.selectedBackground", Color.white);
1335 Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
1339 private static boolean setMacLookAndFeel()
1341 boolean set = false;
1342 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1343 ChannelProperties.getProperty("app_name"));
1344 System.setProperty("apple.laf.useScreenMenuBar", "true");
1346 * broken native LAFs on (ARM?) macbooks
1347 set = setQuaquaLookAndFeel();
1348 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1349 .toLowerCase(Locale.ROOT).contains("quaqua"))
1351 set = setVaquaLookAndFeel();
1354 set = setFlatLookAndFeel();
1358 private static boolean setLinuxLookAndFeel()
1360 boolean set = false;
1361 set = setFlatLookAndFeel();
1363 set = setMetalLookAndFeel();
1364 // avoid GtkLookAndFeel -- not good results especially on HiDPI
1366 set = setNimbusLookAndFeel();
1370 private static void showUsage()
1373 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1374 + "-nodisplay\tRun Jalview without User Interface.\n"
1375 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1376 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1377 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1378 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1379 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1380 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1381 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1382 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1383 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1384 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1385 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1386 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1387 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1388 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1389 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1390 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1391 + "-html FILE\tCreate HTML file from alignment.\n"
1392 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1393 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1394 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1395 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1396 + "-noquestionnaire\tTurn off questionnaire check.\n"
1397 + "-nonews\tTurn off check for Jalview news.\n"
1398 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1399 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1401 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1402 // after all other properties files have been read\n\t
1403 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1404 // passed in correctly)"
1405 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1406 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1407 + "-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"
1408 + "-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"
1409 + "-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"
1410 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1413 private static void startUsageStats(final Desktop desktop)
1416 * start a User Config prompt asking if we can log usage statistics.
1418 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
1419 "USAGESTATS", "Jalview Usage Statistics",
1420 "Do you want to help make Jalview better by enabling "
1421 + "the collection of usage statistics with Google Analytics ?"
1422 + "\n\n(you can enable or disable usage tracking in the preferences)",
1429 "Initialising googletracker for usage stats.");
1430 Cache.initGoogleTracker();
1431 Console.debug("Tracking enabled.");
1438 Console.debug("Not enabling Google Tracking.");
1441 desktop.addDialogThread(prompter);
1445 * Locate the given string as a file and pass it to the groovy interpreter.
1447 * @param groovyscript
1448 * the script to execute
1449 * @param jalviewContext
1450 * the Jalview Desktop object passed in to the groovy binding as the
1453 private void executeGroovyScript(String groovyscript, AlignFrame af)
1456 * for scripts contained in files
1463 if (groovyscript.trim().equals("STDIN"))
1465 // read from stdin into a tempfile and execute it
1468 tfile = File.createTempFile("jalview", "groovy");
1469 PrintWriter outfile = new PrintWriter(
1470 new OutputStreamWriter(new FileOutputStream(tfile)));
1471 BufferedReader br = new BufferedReader(
1472 new InputStreamReader(System.in));
1474 while ((line = br.readLine()) != null)
1476 outfile.write(line + "\n");
1482 } catch (Exception ex)
1484 System.err.println("Failed to read from STDIN into tempfile "
1485 + ((tfile == null) ? "(tempfile wasn't created)"
1486 : tfile.toString()));
1487 ex.printStackTrace();
1492 sfile = tfile.toURI().toURL();
1493 } catch (Exception x)
1496 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1498 x.printStackTrace();
1506 sfile = new URI(groovyscript).toURL();
1507 } catch (Exception x)
1509 tfile = new File(groovyscript);
1510 if (!tfile.exists())
1512 System.err.println("File '" + groovyscript + "' does not exist.");
1515 if (!tfile.canRead())
1517 System.err.println("File '" + groovyscript + "' cannot be read.");
1520 if (tfile.length() < 1)
1522 System.err.println("File '" + groovyscript + "' is empty.");
1527 sfile = tfile.getAbsoluteFile().toURI().toURL();
1528 } catch (Exception ex)
1530 System.err.println("Failed to create a file URL for "
1531 + tfile.getAbsoluteFile());
1538 Map<String, java.lang.Object> vbinding = new HashMap<>();
1539 vbinding.put("Jalview", this);
1542 vbinding.put("currentAlFrame", af);
1544 Binding gbinding = new Binding(vbinding);
1545 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1546 gse.run(sfile.toString(), gbinding);
1547 if ("STDIN".equals(groovyscript))
1549 // delete temp file that we made -
1550 // only if it was successfully executed
1553 } catch (Exception e)
1555 System.err.println("Exception Whilst trying to execute file " + sfile
1556 + " as a groovy script.");
1557 e.printStackTrace(System.err);
1562 public static boolean isHeadlessMode()
1564 String isheadless = System.getProperty("java.awt.headless");
1565 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1572 public AlignFrame[] getAlignFrames()
1574 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1575 : Desktop.getAlignFrames();
1580 * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
1584 // System.exit will run the shutdownHook first
1585 Jalview.exit("Quitting now. Bye!", 0);
1588 public static AlignFrame getCurrentAlignFrame()
1590 return Jalview.currentAlignFrame;
1593 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1595 Jalview.currentAlignFrame = currentAlignFrame;
1598 protected Commands getCommands()
1603 public static void exit(String message, int exitcode)
1605 Console.debug("Using Jalview.exit");
1606 if (message != null)
1608 Console.info(message);
1610 Console.error(message);
1612 System.exit(exitcode);