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.OutputStreamWriter;
30 import java.io.PrintWriter;
31 import java.net.MalformedURLException;
33 import java.net.URISyntaxException;
35 import java.security.AllPermission;
36 import java.security.CodeSource;
37 import java.security.PermissionCollection;
38 import java.security.Permissions;
39 import java.security.Policy;
40 import java.util.HashMap;
41 import java.util.Locale;
43 import java.util.Properties;
44 import java.util.Vector;
45 import java.util.logging.ConsoleHandler;
46 import java.util.logging.Level;
47 import java.util.logging.Logger;
49 import javax.swing.JDialog;
50 import javax.swing.JFrame;
51 import javax.swing.JOptionPane;
52 import javax.swing.SwingUtilities;
53 import javax.swing.UIManager;
54 import javax.swing.UIManager.LookAndFeelInfo;
55 import javax.swing.UnsupportedLookAndFeelException;
57 import com.formdev.flatlaf.FlatLightLaf;
58 import com.formdev.flatlaf.themes.FlatMacLightLaf;
59 import com.formdev.flatlaf.util.SystemInfo;
60 import com.threerings.getdown.util.LaunchUtil;
62 //import edu.stanford.ejalbert.launching.IBrowserLaunching;
63 import groovy.lang.Binding;
64 import groovy.util.GroovyScriptEngine;
65 import jalview.bin.ArgParser.Arg;
66 import jalview.ext.so.SequenceOntology;
67 import jalview.gui.AlignFrame;
68 import jalview.gui.Desktop;
69 import jalview.gui.PromptUserConfig;
70 import jalview.gui.QuitHandler;
71 import jalview.gui.QuitHandler.QResponse;
72 import jalview.io.AppletFormatAdapter;
73 import jalview.io.BioJsHTMLOutput;
74 import jalview.io.DataSourceType;
75 import jalview.io.FileFormat;
76 import jalview.io.FileFormatException;
77 import jalview.io.FileFormatI;
78 import jalview.io.FileFormats;
79 import jalview.io.FileLoader;
80 import jalview.io.HtmlSvgOutput;
81 import jalview.io.IdentifyFile;
82 import jalview.io.NewickFile;
83 import jalview.io.gff.SequenceOntologyFactory;
84 import jalview.schemes.ColourSchemeI;
85 import jalview.schemes.ColourSchemeProperty;
86 import jalview.util.ChannelProperties;
87 import jalview.util.HttpUtils;
88 import jalview.util.LaunchUtils;
89 import jalview.util.MessageManager;
90 import jalview.util.Platform;
91 import jalview.ws.jws2.Jws2Discoverer;
94 * Main class for Jalview Application <br>
96 * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
99 * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
100 * jalview.bin.Jalview jalview.bin.Jalview
102 * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
103 * embellish '*' to e.g. '*.jar')
106 * @version $Revision$
112 Platform.getURLCommandArguments();
113 Platform.addJ2SDirectDatabaseCall("https://www.jalview.org");
114 Platform.addJ2SDirectDatabaseCall("http://www.jalview.org");
115 Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk");
116 Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk");
120 * singleton instance of this class
122 private static Jalview instance;
124 private Desktop desktop;
126 public static AlignFrame currentAlignFrame;
130 if (!Platform.isJS())
137 // grab all the rights we can for the JVM
138 Policy.setPolicy(new Policy()
141 public PermissionCollection getPermissions(CodeSource codesource)
143 Permissions perms = new Permissions();
144 perms.add(new AllPermission());
149 public void refresh()
157 * keep track of feature fetching tasks.
165 * TODO: generalise to track all jalview events to orchestrate batch processing
169 private int queued = 0;
171 private int running = 0;
173 public FeatureFetcher()
178 public void addFetcher(final AlignFrame af,
179 final Vector<String> dasSources)
181 final long id = System.currentTimeMillis();
183 final FeatureFetcher us = this;
184 new Thread(new Runnable()
196 af.setProgressBar(MessageManager
197 .getString("status.das_features_being_retrived"), id);
198 af.featureSettings_actionPerformed(null);
199 af.setProgressBar(null, id);
208 public synchronized boolean allFinished()
210 return queued == 0 && running == 0;
215 public static Jalview getInstance()
221 * main class for Jalview application
224 * open <em>filename</em>
226 public static void main(String[] args)
228 // setLogging(); // BH - for event debugging in JavaScript
229 instance = new Jalview();
230 instance.doMain(args);
233 private static void logClass(String name)
235 // BH - for event debugging in JavaScript
236 ConsoleHandler consoleHandler = new ConsoleHandler();
237 consoleHandler.setLevel(Level.ALL);
238 Logger logger = Logger.getLogger(name);
239 logger.setLevel(Level.ALL);
240 logger.addHandler(consoleHandler);
243 @SuppressWarnings("unused")
244 private static void setLogging()
252 System.out.println("not in js");
255 // BH - for event debugging in JavaScript (Java mode only)
256 if (!Platform.isJS())
263 Logger.getLogger("").setLevel(Level.ALL);
264 logClass("java.awt.EventDispatchThread");
265 logClass("java.awt.EventQueue");
266 logClass("java.awt.Component");
267 logClass("java.awt.focus.Component");
268 logClass("java.awt.focus.DefaultKeyboardFocusManager");
276 void doMain(String[] args)
279 if (!Platform.isJS())
281 System.setSecurityManager(null);
284 // get args needed before proper ArgParser
285 Map<ArgParser.Arg, String> bootstrapArgs = ArgParser
286 .bootstrapArgs(args);
289 .println("Java version: " + System.getProperty("java.version"));
290 System.out.println("Java Home: " + System.getProperty("java.home"));
291 System.out.println(System.getProperty("os.arch") + " "
292 + System.getProperty("os.name") + " "
293 + System.getProperty("os.version"));
295 String val = System.getProperty("sys.install4jVersion");
298 System.out.println("Install4j version: " + val);
300 val = System.getProperty("installer_template_version");
303 System.out.println("Install4j template version: " + val);
305 val = System.getProperty("launcher_version");
308 System.out.println("Launcher version: " + val);
311 if (Platform.isLinux() && LaunchUtils.getJavaVersion() < 11)
313 System.setProperty("flatlaf.uiScale", "1");
316 // get bootstrap properties (mainly for the logger level)
317 Properties bootstrapProperties = Cache
318 .bootstrapProperties(bootstrapArgs.get(Arg.PROPS));
320 // report Jalview version
321 Cache.loadBuildProperties(true);
324 ArgsParser aparser = new ArgsParser(args);
327 boolean headless = false;
329 boolean headlessArg = false;
333 String logLevel = bootstrapArgs.containsKey(Arg.DEBUG) ? "DEBUG"
335 if (logLevel == null && !(bootstrapProperties == null))
337 logLevel = bootstrapProperties.getProperty(Cache.JALVIEWLOGLEVEL);
339 Console.initLogger(logLevel);
340 } catch (NoClassDefFoundError error)
342 error.printStackTrace();
343 System.out.println("\nEssential logging libraries not found."
344 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
348 // register SIGTERM listener
349 Runtime.getRuntime().addShutdownHook(new Thread()
353 Console.debug("Running shutdown hook");
354 if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT)
356 // Got to here by a SIGTERM signal.
357 // Note we will not actually cancel the quit from here -- it's too
358 // late -- but we can wait for saving files.
359 Console.debug("Checking for saving files");
360 QuitHandler.getQuitResponse(false);
364 Console.debug("Nothing more to do");
366 Console.debug("Exiting, bye!");
367 // shutdownHook cannot be cancelled, JVM will now halt
371 String usrPropsFile = bootstrapArgs.containsKey(Arg.PROPS)
372 ? bootstrapArgs.get(Arg.PROPS)
373 : aparser.getValue("props");
374 Cache.loadProperties(usrPropsFile);
375 if (usrPropsFile != null)
378 "CMD [-props " + usrPropsFile + "] executed successfully!");
383 // --argfile=... -- OVERRIDES ALL NON-BOOTSTRAP ARGS
384 if (bootstrapArgs.containsKey(Arg.ARGFILE))
386 argparser = ArgParser.parseArgFile(bootstrapArgs.get(Arg.ARGFILE));
390 argparser = new ArgParser(args);
393 if (!Platform.isJS())
400 if (aparser.contains("help") || aparser.contains("h")
401 || argparser.getBool(Arg.HELP))
407 if (argparser.isSet(Arg.HEADLESS))
409 System.setProperty("java.awt.headless", "true");
411 headlessArg = argparser.getBool(Arg.HEADLESS);
413 if (aparser.contains("nodisplay") || aparser.contains("nogui")
414 || aparser.contains("headless"))
416 System.setProperty("java.awt.headless", "true");
422 // allow https handshakes to download intermediate certs if necessary
423 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
425 final String jabawsUrl = aparser.getValue("jabaws");
426 if (jabawsUrl != null)
430 Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
432 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
433 } catch (MalformedURLException e)
436 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
441 String defs = aparser.getValue("setprop");
444 int p = defs.indexOf('=');
447 System.err.println("Ignoring invalid setprop argument : " + defs);
451 System.out.println("Executing setprop argument: " + defs);
454 Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
456 // DISABLED FOR SECURITY REASONS
457 // TODO: add a property to allow properties to be overriden by cli args
458 // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
460 defs = aparser.getValue("setprop");
462 if (System.getProperty("java.awt.headless") != null
463 && System.getProperty("java.awt.headless").equals("true"))
467 System.setProperty("http.agent",
468 "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
472 Console.initLogger();
475 NoClassDefFoundError error)
477 error.printStackTrace();
478 System.out.println("\nEssential logging libraries not found."
479 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
484 if (!(headless || headlessArg))
488 * configure 'full' SO model if preferences say to, else use the default (full SO)
489 * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
491 boolean soDefault = !Platform.isJS();
492 if (Cache.getDefault("USE_FULL_SO", soDefault))
494 SequenceOntologyFactory.setInstance(new SequenceOntology());
497 if (!(headless || headlessArg))
499 Desktop.nosplash = aparser.contains("nosplash");
500 desktop = new Desktop();
501 desktop.setInBatchMode(true); // indicate we are starting up
505 JalviewTaskbar.setTaskbar(this);
506 } catch (Exception e)
508 Console.info("Cannot set Taskbar");
509 Console.error(e.getMessage());
510 // e.printStackTrace();
511 } catch (Throwable t)
513 Console.info("Cannot set Taskbar");
514 Console.error(t.getMessage());
515 // t.printStackTrace();
518 // set Proxy settings before all the internet calls
519 Cache.setProxyPropertiesFromPreferences();
521 desktop.setVisible(true);
523 if (!Platform.isJS())
532 * Check to see that the JVM version being run is suitable for the Java
533 * version this Jalview was compiled for. Popup a warning if not.
535 if (!LaunchUtils.checkJavaVersion())
537 Console.warn("The Java version being used (Java "
538 + LaunchUtils.getJavaVersion()
539 + ") may lead to problems. This installation of Jalview should be used with Java "
540 + LaunchUtils.getJavaCompileVersion() + ".");
543 .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
546 MessageManager.getString("label.continue") };
547 JOptionPane.showOptionDialog(null,
548 MessageManager.formatMessage(
549 "warning.wrong_jvm_version_message",
550 LaunchUtils.getJavaVersion(),
551 LaunchUtils.getJavaCompileVersion()),
553 .getString("warning.wrong_jvm_version_title"),
554 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
555 null, options, options[0]);
559 if (!aparser.contains("nowebservicediscovery"))
561 desktop.startServiceDiscovery();
563 if (!aparser.contains("nousagestats"))
565 startUsageStats(desktop);
569 System.err.println("CMD [-nousagestats] executed successfully!");
572 if (!aparser.contains("noquestionnaire"))
574 String url = aparser.getValue("questionnaire");
577 // Start the desktop questionnaire prompter with the specified
579 Console.debug("Starting questionnaire url at " + url);
580 desktop.checkForQuestionnaire(url);
581 System.out.println("CMD questionnaire[-" + url
582 + "] executed successfully!");
586 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
588 // Start the desktop questionnaire prompter with the specified
591 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
593 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
595 "Starting questionnaire with default url: " + defurl);
596 desktop.checkForQuestionnaire(defurl);
603 .println("CMD [-noquestionnaire] executed successfully!");
606 if (!aparser.contains("nonews")
607 || Cache.getProperty("NONEWS") == null)
609 desktop.checkForNews();
612 if (!aparser.contains("nohtmltemplates")
613 || Cache.getProperty("NOHTMLTEMPLATES") == null)
615 BioJsHTMLOutput.updateBioJS();
619 // Run Commands from cli
620 boolean commandsSuccess = Commands.processArgs(argparser, headlessArg);
623 Console.info("Successfully completed commands");
629 Console.warn("Error when running commands");
634 // Check if JVM and compile version might cause problems and log if it
636 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
638 Console.warn("The Java version being used (Java "
639 + LaunchUtils.getJavaVersion()
640 + ") may lead to problems. This installation of Jalview should be used with Java "
641 + LaunchUtils.getJavaCompileVersion() + ".");
644 // Move any new getdown-launcher-new.jar into place over old
645 // getdown-launcher.jar
646 String appdirString = System.getProperty("getdownappdir");
647 if (appdirString != null && appdirString.length() > 0)
649 final File appdir = new File(appdirString);
655 LaunchUtil.upgradeGetdown(
656 new File(appdir, "getdown-launcher-old.jar"),
657 new File(appdir, "getdown-launcher.jar"),
658 new File(appdir, "getdown-launcher-new.jar"));
663 String file = null, data = null;
665 FileFormatI format = null;
667 DataSourceType protocol = null;
669 FileLoader fileLoader = new FileLoader(!headless);
671 String groovyscript = null; // script to execute after all loading is
672 // completed one way or another
673 // extract groovy argument and execute if necessary
674 groovyscript = aparser.getValue("groovy", true);
675 file = aparser.getValue("open", true);
677 if (file == null && desktop == null)
679 System.out.println("No files to open!");
684 // Finally, deal with the remaining input data.
689 desktop.setProgressBar(
691 .getString("status.processing_commandline_args"),
692 progress = System.currentTimeMillis());
694 System.out.println("CMD [-open " + file + "] executed successfully!");
696 if (!Platform.isJS())
698 * ignore in JavaScript -- can't just file existence - could load it?
703 if (!HttpUtils.startsWithHttpOrHttps(file))
705 if (!(new File(file)).exists())
707 System.out.println("Can't find " + file);
716 protocol = AppletFormatAdapter.checkProtocol(file);
720 format = new IdentifyFile().identify(file, protocol);
721 } catch (FileFormatException e1)
726 AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
730 System.out.println("error");
734 setCurrentAlignFrame(af);
735 data = aparser.getValue("colour", true);
738 data.replaceAll("%20", " ");
740 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
741 af.getViewport(), af.getViewport().getAlignment(), data);
746 "CMD [-colour " + data + "] executed successfully!");
751 // Must maintain ability to use the groups flag
752 data = aparser.getValue("groups", true);
755 af.parseFeaturesFile(data,
756 AppletFormatAdapter.checkProtocol(data));
757 // System.out.println("Added " + data);
759 "CMD groups[-" + data + "] executed successfully!");
761 data = aparser.getValue("features", true);
764 af.parseFeaturesFile(data,
765 AppletFormatAdapter.checkProtocol(data));
766 // System.out.println("Added " + data);
768 "CMD [-features " + data + "] executed successfully!");
771 data = aparser.getValue("annotations", true);
774 af.loadJalviewDataFile(data, null, null, null);
775 // System.out.println("Added " + data);
777 "CMD [-annotations " + data + "] executed successfully!");
779 // set or clear the sortbytree flag.
780 if (aparser.contains("sortbytree"))
782 af.getViewport().setSortByTree(true);
783 if (af.getViewport().getSortByTree())
785 System.out.println("CMD [-sortbytree] executed successfully!");
788 if (aparser.contains("no-annotation"))
790 af.getViewport().setShowAnnotation(false);
791 if (!af.getViewport().isShowAnnotation())
793 System.out.println("CMD no-annotation executed successfully!");
796 if (aparser.contains("nosortbytree"))
798 af.getViewport().setSortByTree(false);
799 if (!af.getViewport().getSortByTree())
802 .println("CMD [-nosortbytree] executed successfully!");
805 data = aparser.getValue("tree", true);
811 "CMD [-tree " + data + "] executed successfully!");
812 NewickFile nf = new NewickFile(data,
813 AppletFormatAdapter.checkProtocol(data));
815 .setCurrentTree(af.showNewickTree(nf, data).getTree());
816 } catch (IOException ex)
818 System.err.println("Couldn't add tree " + data);
819 ex.printStackTrace(System.err);
822 // TODO - load PDB structure(s) to alignment JAL-629
823 // (associate with identical sequence in alignment, or a specified
825 if (groovyscript != null)
827 // Execute the groovy script after we've done all the rendering stuff
828 // and before any images or figures are generated.
829 System.out.println("Executing script " + groovyscript);
830 executeGroovyScript(groovyscript, af);
831 System.out.println("CMD groovy[" + groovyscript
832 + "] executed successfully!");
835 String imageName = "unnamed.png";
836 while (aparser.getSize() > 1)
838 String outputFormat = aparser.nextValue();
839 file = aparser.nextValue();
841 if (outputFormat.equalsIgnoreCase("png"))
843 af.createPNG(new File(file));
844 imageName = (new File(file)).getName();
845 System.out.println("Creating PNG image: " + file);
848 else if (outputFormat.equalsIgnoreCase("svg"))
850 File imageFile = new File(file);
851 imageName = imageFile.getName();
852 af.createSVG(imageFile);
853 System.out.println("Creating SVG image: " + file);
856 else if (outputFormat.equalsIgnoreCase("html"))
858 File imageFile = new File(file);
859 imageName = imageFile.getName();
860 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
861 htmlSVG.exportHTML(file);
863 System.out.println("Creating HTML image: " + file);
866 else if (outputFormat.equalsIgnoreCase("biojsmsa"))
870 System.err.println("The output html file must not be null");
875 BioJsHTMLOutput.refreshVersionInfo(
876 BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
877 } catch (URISyntaxException e)
881 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
882 bjs.exportHTML(file);
884 .println("Creating BioJS MSA Viwer HTML file: " + file);
887 else if (outputFormat.equalsIgnoreCase("imgMap"))
889 af.createImageMap(new File(file), imageName);
890 System.out.println("Creating image map: " + file);
893 else if (outputFormat.equalsIgnoreCase("eps"))
895 File outputFile = new File(file);
897 "Creating EPS file: " + outputFile.getAbsolutePath());
898 af.createEPS(outputFile);
901 FileFormatI outFormat = null;
904 outFormat = FileFormats.getInstance().forName(outputFormat);
905 } catch (Exception formatP)
907 System.out.println("Couldn't parse " + outFormat
908 + " as a valid Jalview format string.");
910 if (outFormat != null)
912 if (!outFormat.isWritable())
915 "This version of Jalview does not support alignment export as "
920 af.saveAlignment(file, outFormat);
921 if (af.isSaveAlignmentSuccessful())
923 System.out.println("Written alignment in "
924 + outFormat.getName() + " format to " + file);
928 System.out.println("Error writing file " + file + " in "
929 + outFormat.getName() + " format!!");
936 while (aparser.getSize() > 0)
938 System.out.println("Unknown arg: " + aparser.nextValue());
943 AlignFrame startUpAlframe = null;
944 // We'll only open the default file if the desktop is visible.
946 // ////////////////////
948 if (!Platform.isJS() && !headless && file == null
949 && Cache.getDefault("SHOW_STARTUP_FILE", true)
950 && !Commands.commandArgsProvided())
951 // don't open the startup file if command line args have been processed
952 // (&& !Commands.commandArgsProvided())
959 file = Cache.getDefault("STARTUP_FILE",
960 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
961 + "/examples/exampleFile_2_7.jvp");
962 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
964 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
966 file.replace("http:", "https:");
967 // hardwire upgrade of the startup file
968 file.replace("_2_3", "_2_7");
969 file.replace("2_7.jar", "2_7.jvp");
970 // and remove the stale setting
971 Cache.removeProperty("STARTUP_FILE");
974 protocol = AppletFormatAdapter.checkProtocol(file);
976 if (file.endsWith(".jar"))
978 format = FileFormat.Jalview;
984 format = new IdentifyFile().identify(file, protocol);
985 } catch (FileFormatException e)
991 startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
993 // don't ask to save when quitting if only the startup file has been
995 Console.debug("Resetting up-to-date flag for startup file");
996 startUpAlframe.getViewport().setSavedUpToDate(true);
997 // extract groovy arguments before anything else.
1000 // Once all other stuff is done, execute any groovy scripts (in order)
1001 if (groovyscript != null)
1003 if (Cache.groovyJarsPresent())
1005 System.out.println("Executing script " + groovyscript);
1006 executeGroovyScript(groovyscript, startUpAlframe);
1011 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
1015 // and finally, turn off batch mode indicator - if the desktop still exists
1016 if (desktop != null)
1020 desktop.setProgressBar(null, progress);
1022 desktop.setInBatchMode(false);
1026 private static void setLookAndFeel()
1028 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
1030 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
1031 // try Quaqua/Vaqua.
1032 String lafProp = System.getProperty("laf");
1033 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
1034 String laf = "none";
1035 if (lafProp != null)
1039 else if (lafSetting != null)
1043 boolean lafSet = false;
1046 case "crossplatform":
1047 lafSet = setCrossPlatformLookAndFeel();
1050 Console.error("Could not set requested laf=" + laf);
1054 lafSet = setSystemLookAndFeel();
1057 Console.error("Could not set requested laf=" + laf);
1061 lafSet = setGtkLookAndFeel();
1064 Console.error("Could not set requested laf=" + laf);
1068 lafSet = setMetalLookAndFeel();
1071 Console.error("Could not set requested laf=" + laf);
1075 lafSet = setNimbusLookAndFeel();
1078 Console.error("Could not set requested laf=" + laf);
1082 lafSet = setFlatLookAndFeel();
1085 Console.error("Could not set requested laf=" + laf);
1089 lafSet = setMacLookAndFeel();
1092 Console.error("Could not set requested laf=" + laf);
1098 Console.error("Requested laf=" + laf + " not implemented");
1102 setSystemLookAndFeel();
1103 if (Platform.isLinux())
1105 setLinuxLookAndFeel();
1107 if (Platform.isMac())
1109 setMacLookAndFeel();
1114 private static boolean setCrossPlatformLookAndFeel()
1116 boolean set = false;
1119 UIManager.setLookAndFeel(
1120 UIManager.getCrossPlatformLookAndFeelClassName());
1122 } catch (Exception ex)
1124 Console.error("Unexpected Look and Feel Exception");
1125 Console.error(ex.getMessage());
1126 Console.debug(Cache.getStackTraceString(ex));
1131 private static boolean setSystemLookAndFeel()
1133 boolean set = false;
1136 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1138 } catch (Exception ex)
1140 Console.error("Unexpected Look and Feel Exception");
1141 Console.error(ex.getMessage());
1142 Console.debug(Cache.getStackTraceString(ex));
1147 private static boolean setSpecificLookAndFeel(String name,
1148 String className, boolean nameStartsWith)
1150 boolean set = false;
1153 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1155 if (info.getName() != null && nameStartsWith
1156 ? info.getName().toLowerCase(Locale.ROOT)
1157 .startsWith(name.toLowerCase(Locale.ROOT))
1158 : info.getName().toLowerCase(Locale.ROOT)
1159 .equals(name.toLowerCase(Locale.ROOT)))
1161 className = info.getClassName();
1165 UIManager.setLookAndFeel(className);
1167 } catch (Exception ex)
1169 Console.error("Unexpected Look and Feel Exception");
1170 Console.error(ex.getMessage());
1171 Console.debug(Cache.getStackTraceString(ex));
1176 private static boolean setGtkLookAndFeel()
1178 return setSpecificLookAndFeel("gtk",
1179 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1182 private static boolean setMetalLookAndFeel()
1184 return setSpecificLookAndFeel("metal",
1185 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1188 private static boolean setNimbusLookAndFeel()
1190 return setSpecificLookAndFeel("nimbus",
1191 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1194 private static boolean setFlatLookAndFeel()
1196 boolean set = false;
1197 if (SystemInfo.isMacOS)
1201 UIManager.setLookAndFeel(
1202 "com.formdev.flatlaf.themes.FlatMacLightLaf");
1204 Console.debug("Using FlatMacLightLaf");
1205 } catch (ClassNotFoundException | InstantiationException
1206 | IllegalAccessException | UnsupportedLookAndFeelException e)
1208 Console.debug("Exception loading FlatLightLaf", e);
1210 System.setProperty("apple.laf.useScreenMenuBar", "true");
1211 System.setProperty("apple.awt.application.name",
1212 ChannelProperties.getProperty("app_name"));
1213 System.setProperty("apple.awt.application.appearance", "system");
1214 if (SystemInfo.isMacFullWindowContentSupported
1215 && Desktop.desktop != null)
1217 Console.debug("Setting transparent title bar");
1218 Desktop.desktop.getRootPane()
1219 .putClientProperty("apple.awt.fullWindowContent", true);
1220 Desktop.desktop.getRootPane()
1221 .putClientProperty("apple.awt.transparentTitleBar", true);
1222 Desktop.desktop.getRootPane()
1223 .putClientProperty("apple.awt.fullscreenable", true);
1225 SwingUtilities.invokeLater(() -> {
1226 FlatMacLightLaf.setup();
1228 Console.debug("Using FlatMacLightLaf");
1235 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1237 Console.debug("Using FlatLightLaf");
1238 } catch (ClassNotFoundException | InstantiationException
1239 | IllegalAccessException | UnsupportedLookAndFeelException e)
1241 Console.debug("Exception loading FlatLightLaf", e);
1243 // Windows specific properties here
1244 SwingUtilities.invokeLater(() -> {
1245 FlatLightLaf.setup();
1247 Console.debug("Using FlatLightLaf");
1250 else if (SystemInfo.isLinux)
1254 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1256 Console.debug("Using FlatLightLaf");
1257 } catch (ClassNotFoundException | InstantiationException
1258 | IllegalAccessException | UnsupportedLookAndFeelException e)
1260 Console.debug("Exception loading FlatLightLaf", e);
1262 // enable custom window decorations
1263 JFrame.setDefaultLookAndFeelDecorated(true);
1264 JDialog.setDefaultLookAndFeelDecorated(true);
1265 SwingUtilities.invokeLater(() -> {
1266 FlatLightLaf.setup();
1268 Console.debug("Using FlatLightLaf");
1276 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1278 Console.debug("Using FlatLightLaf");
1279 } catch (ClassNotFoundException | InstantiationException
1280 | IllegalAccessException | UnsupportedLookAndFeelException e)
1282 Console.debug("Exception loading FlatLightLaf", e);
1288 UIManager.put("TabbedPane.tabType", "card");
1289 UIManager.put("TabbedPane.showTabSeparators", true);
1290 UIManager.put("TabbedPane.showContentSeparator", true);
1291 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1292 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1293 UIManager.put("TabbedPane.hasFullBorder", true);
1294 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1295 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1296 UIManager.put("TabbedPane.smoothScrolling", true);
1297 UIManager.put("TabbedPane.tabWidthMode", "compact");
1298 UIManager.put("TabbedPane.selectedBackground", Color.white);
1301 Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
1305 private static boolean setMacLookAndFeel()
1307 boolean set = false;
1308 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1309 ChannelProperties.getProperty("app_name"));
1310 System.setProperty("apple.laf.useScreenMenuBar", "true");
1312 * broken native LAFs on (ARM?) macbooks
1313 set = setQuaquaLookAndFeel();
1314 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1315 .toLowerCase(Locale.ROOT).contains("quaqua"))
1317 set = setVaquaLookAndFeel();
1320 set = setFlatLookAndFeel();
1324 private static boolean setLinuxLookAndFeel()
1326 boolean set = false;
1327 set = setFlatLookAndFeel();
1329 set = setMetalLookAndFeel();
1330 // avoid GtkLookAndFeel -- not good results especially on HiDPI
1332 set = setNimbusLookAndFeel();
1336 private static void showUsage()
1339 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1340 + "-nodisplay\tRun Jalview without User Interface.\n"
1341 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1342 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1343 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1344 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1345 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1346 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1347 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1348 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1349 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1350 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1351 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1352 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1353 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1354 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1355 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1356 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1357 + "-html FILE\tCreate HTML file from alignment.\n"
1358 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1359 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1360 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1361 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1362 + "-noquestionnaire\tTurn off questionnaire check.\n"
1363 + "-nonews\tTurn off check for Jalview news.\n"
1364 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1365 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1367 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1368 // after all other properties files have been read\n\t
1369 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1370 // passed in correctly)"
1371 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1372 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1373 + "-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"
1374 + "-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"
1375 + "-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"
1376 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1379 private static void startUsageStats(final Desktop desktop)
1382 * start a User Config prompt asking if we can log usage statistics.
1384 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
1385 "USAGESTATS", "Jalview Usage Statistics",
1386 "Do you want to help make Jalview better by enabling "
1387 + "the collection of usage statistics with Google Analytics ?"
1388 + "\n\n(you can enable or disable usage tracking in the preferences)",
1395 "Initialising googletracker for usage stats.");
1396 Cache.initGoogleTracker();
1397 Console.debug("Tracking enabled.");
1404 Console.debug("Not enabling Google Tracking.");
1407 desktop.addDialogThread(prompter);
1411 * Locate the given string as a file and pass it to the groovy interpreter.
1413 * @param groovyscript
1414 * the script to execute
1415 * @param jalviewContext
1416 * the Jalview Desktop object passed in to the groovy binding as the
1419 private void executeGroovyScript(String groovyscript, AlignFrame af)
1422 * for scripts contained in files
1429 if (groovyscript.trim().equals("STDIN"))
1431 // read from stdin into a tempfile and execute it
1434 tfile = File.createTempFile("jalview", "groovy");
1435 PrintWriter outfile = new PrintWriter(
1436 new OutputStreamWriter(new FileOutputStream(tfile)));
1437 BufferedReader br = new BufferedReader(
1438 new InputStreamReader(System.in));
1440 while ((line = br.readLine()) != null)
1442 outfile.write(line + "\n");
1448 } catch (Exception ex)
1450 System.err.println("Failed to read from STDIN into tempfile "
1451 + ((tfile == null) ? "(tempfile wasn't created)"
1452 : tfile.toString()));
1453 ex.printStackTrace();
1458 sfile = tfile.toURI().toURL();
1459 } catch (Exception x)
1462 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1464 x.printStackTrace();
1472 sfile = new URI(groovyscript).toURL();
1473 } catch (Exception x)
1475 tfile = new File(groovyscript);
1476 if (!tfile.exists())
1478 System.err.println("File '" + groovyscript + "' does not exist.");
1481 if (!tfile.canRead())
1483 System.err.println("File '" + groovyscript + "' cannot be read.");
1486 if (tfile.length() < 1)
1488 System.err.println("File '" + groovyscript + "' is empty.");
1493 sfile = tfile.getAbsoluteFile().toURI().toURL();
1494 } catch (Exception ex)
1496 System.err.println("Failed to create a file URL for "
1497 + tfile.getAbsoluteFile());
1504 Map<String, java.lang.Object> vbinding = new HashMap<>();
1505 vbinding.put("Jalview", this);
1508 vbinding.put("currentAlFrame", af);
1510 Binding gbinding = new Binding(vbinding);
1511 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1512 gse.run(sfile.toString(), gbinding);
1513 if ("STDIN".equals(groovyscript))
1515 // delete temp file that we made -
1516 // only if it was successfully executed
1519 } catch (Exception e)
1521 System.err.println("Exception Whilst trying to execute file " + sfile
1522 + " as a groovy script.");
1523 e.printStackTrace(System.err);
1528 public static boolean isHeadlessMode()
1530 String isheadless = System.getProperty("java.awt.headless");
1531 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1538 public AlignFrame[] getAlignFrames()
1540 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1541 : Desktop.getAlignFrames();
1546 * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
1550 // System.exit will run the shutdownHook first
1554 public static AlignFrame getCurrentAlignFrame()
1556 return Jalview.currentAlignFrame;
1559 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1561 Jalview.currentAlignFrame = currentAlignFrame;