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.Vector;
44 import java.util.logging.ConsoleHandler;
45 import java.util.logging.Level;
46 import java.util.logging.Logger;
48 import javax.swing.JDialog;
49 import javax.swing.JFrame;
50 import javax.swing.JOptionPane;
51 import javax.swing.SwingUtilities;
52 import javax.swing.UIManager;
53 import javax.swing.UIManager.LookAndFeelInfo;
54 import javax.swing.UnsupportedLookAndFeelException;
56 import com.formdev.flatlaf.FlatLightLaf;
57 import com.formdev.flatlaf.themes.FlatMacLightLaf;
58 import com.formdev.flatlaf.util.SystemInfo;
59 import com.threerings.getdown.util.LaunchUtil;
61 //import edu.stanford.ejalbert.launching.IBrowserLaunching;
62 import groovy.lang.Binding;
63 import groovy.util.GroovyScriptEngine;
64 import jalview.bin.ArgParser.Arg;
65 import jalview.ext.so.SequenceOntology;
66 import jalview.gui.AlignFrame;
67 import jalview.gui.Desktop;
68 import jalview.gui.PromptUserConfig;
69 import jalview.gui.QuitHandler;
70 import jalview.gui.QuitHandler.QResponse;
71 import jalview.io.AppletFormatAdapter;
72 import jalview.io.BioJsHTMLOutput;
73 import jalview.io.DataSourceType;
74 import jalview.io.FileFormat;
75 import jalview.io.FileFormatException;
76 import jalview.io.FileFormatI;
77 import jalview.io.FileFormats;
78 import jalview.io.FileLoader;
79 import jalview.io.HtmlSvgOutput;
80 import jalview.io.IdentifyFile;
81 import jalview.io.NewickFile;
82 import jalview.io.gff.SequenceOntologyFactory;
83 import jalview.schemes.ColourSchemeI;
84 import jalview.schemes.ColourSchemeProperty;
85 import jalview.util.ChannelProperties;
86 import jalview.util.HttpUtils;
87 import jalview.util.LaunchUtils;
88 import jalview.util.MessageManager;
89 import jalview.util.Platform;
90 import jalview.ws.jws2.Jws2Discoverer;
93 * Main class for Jalview Application <br>
95 * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
98 * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
99 * jalview.bin.Jalview jalview.bin.Jalview
101 * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
102 * embellish '*' to e.g. '*.jar')
105 * @version $Revision$
111 Platform.getURLCommandArguments();
112 Platform.addJ2SDirectDatabaseCall("https://www.jalview.org");
113 Platform.addJ2SDirectDatabaseCall("http://www.jalview.org");
114 Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk");
115 Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk");
119 * singleton instance of this class
121 private static Jalview instance;
123 private Desktop desktop;
125 public static AlignFrame currentAlignFrame;
129 if (!Platform.isJS())
136 // grab all the rights we can for the JVM
137 Policy.setPolicy(new Policy()
140 public PermissionCollection getPermissions(CodeSource codesource)
142 Permissions perms = new Permissions();
143 perms.add(new AllPermission());
148 public void refresh()
156 * keep track of feature fetching tasks.
164 * TODO: generalise to track all jalview events to orchestrate batch processing
168 private int queued = 0;
170 private int running = 0;
172 public FeatureFetcher()
177 public void addFetcher(final AlignFrame af,
178 final Vector<String> dasSources)
180 final long id = System.currentTimeMillis();
182 final FeatureFetcher us = this;
183 new Thread(new Runnable()
195 af.setProgressBar(MessageManager
196 .getString("status.das_features_being_retrived"), id);
197 af.featureSettings_actionPerformed(null);
198 af.setProgressBar(null, id);
207 public synchronized boolean allFinished()
209 return queued == 0 && running == 0;
214 public static Jalview getInstance()
220 * main class for Jalview application
223 * open <em>filename</em>
225 public static void main(String[] args)
227 // setLogging(); // BH - for event debugging in JavaScript
228 instance = new Jalview();
229 instance.doMain(args);
232 private static void logClass(String name)
234 // BH - for event debugging in JavaScript
235 ConsoleHandler consoleHandler = new ConsoleHandler();
236 consoleHandler.setLevel(Level.ALL);
237 Logger logger = Logger.getLogger(name);
238 logger.setLevel(Level.ALL);
239 logger.addHandler(consoleHandler);
242 @SuppressWarnings("unused")
243 private static void setLogging()
251 System.out.println("not in js");
254 // BH - for event debugging in JavaScript (Java mode only)
255 if (!Platform.isJS())
262 Logger.getLogger("").setLevel(Level.ALL);
263 logClass("java.awt.EventDispatchThread");
264 logClass("java.awt.EventQueue");
265 logClass("java.awt.Component");
266 logClass("java.awt.focus.Component");
267 logClass("java.awt.focus.DefaultKeyboardFocusManager");
275 void doMain(String[] args)
278 if (!Platform.isJS())
280 System.setSecurityManager(null);
282 Runtime.getRuntime().addShutdownHook(new Thread()
286 Console.debug("Running shutdown hook");
287 if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT)
289 // Got to here by a SIGTERM signal.
290 // Note we will not actually cancel the quit from here -- it's too
291 // late -- but we can wait for saving files.
292 Console.debug("Checking for saving files");
293 QuitHandler.getQuitResponse(false);
297 Console.debug("Nothing more to do");
299 Console.debug("Exiting, bye!");
300 // shutdownHook cannot be cancelled, JVM will now halt
306 .println("Java version: " + System.getProperty("java.version"));
307 System.out.println("Java Home: " + System.getProperty("java.home"));
308 System.out.println(System.getProperty("os.arch") + " "
309 + System.getProperty("os.name") + " "
310 + System.getProperty("os.version"));
312 String val = System.getProperty("sys.install4jVersion");
315 System.out.println("Install4j version: " + val);
317 val = System.getProperty("installer_template_version");
320 System.out.println("Install4j template version: " + val);
322 val = System.getProperty("launcher_version");
325 System.out.println("Launcher version: " + val);
328 if (Platform.isLinux() && LaunchUtils.getJavaVersion() < 11)
330 System.setProperty("flatlaf.uiScale", "1");
333 // report Jalview version
334 Cache.loadBuildProperties(true);
337 ArgsParser aparser = new ArgsParser(args);
339 boolean headless = false;
343 Console.initLogger();
344 } catch (NoClassDefFoundError error)
346 error.printStackTrace();
347 System.out.println("\nEssential logging libraries not found."
348 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
352 String usrPropsFile = aparser.getValue("props");
353 Cache.loadProperties(usrPropsFile); // must do this
355 if (usrPropsFile != null)
358 "CMD [-props " + usrPropsFile + "] executed successfully!");
361 // set log level from cache properties
362 Console.setLogLevel(Cache.getDefault(Cache.JALVIEWLOGLEVEL, "INFO"));
365 ArgParser argparser = new ArgParser(args); // do this after
366 // Console.initLogger, but TODO
367 // want --props before then
370 if (argparser.isSet(Arg.HEADLESS))
371 headless = argparser.getBool(Arg.HEADLESS);
372 boolean commandsSuccess = Commands.processArgs(argparser, headless);
375 Console.info("Successfully completed commands");
381 Console.warn("Error when running commands");
386 if (!Platform.isJS())
393 if (argparser.isSet(Arg.HEADLESS))
395 headless = argparser.getBool(Arg.HEADLESS);
398 if (aparser.contains("help") || aparser.contains("h"))
403 if (headless || aparser.contains("nodisplay")
404 || aparser.contains("nogui") || aparser.contains("headless"))
406 System.setProperty("java.awt.headless", "true");
411 // allow https handshakes to download intermediate certs if necessary
412 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
414 final String jabawsUrl = aparser.getValue("jabaws");
415 if (jabawsUrl != null)
419 Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
421 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
422 } catch (MalformedURLException e)
425 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
430 String defs = aparser.getValue("setprop");
433 int p = defs.indexOf('=');
436 System.err.println("Ignoring invalid setprop argument : " + defs);
440 System.out.println("Executing setprop argument: " + defs);
443 Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
445 // DISABLED FOR SECURITY REASONS
446 // TODO: add a property to allow properties to be overriden by cli args
447 // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
449 defs = aparser.getValue("setprop");
451 if (System.getProperty("java.awt.headless") != null
452 && System.getProperty("java.awt.headless").equals("true"))
456 System.setProperty("http.agent",
457 "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
461 Console.initLogger();
464 NoClassDefFoundError error)
466 error.printStackTrace();
467 System.out.println("\nEssential logging libraries not found."
468 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
477 * configure 'full' SO model if preferences say to, else use the default (full SO)
478 * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
480 boolean soDefault = !Platform.isJS();
481 if (Cache.getDefault("USE_FULL_SO", soDefault))
483 SequenceOntologyFactory.setInstance(new SequenceOntology());
488 Desktop.nosplash = aparser.contains("nosplash");
489 desktop = new Desktop();
490 desktop.setInBatchMode(true); // indicate we are starting up
494 JalviewTaskbar.setTaskbar(this);
495 } catch (Exception e)
497 Console.info("Cannot set Taskbar");
498 Console.error(e.getMessage());
499 // e.printStackTrace();
500 } catch (Throwable t)
502 Console.info("Cannot set Taskbar");
503 Console.error(t.getMessage());
504 // t.printStackTrace();
507 // set Proxy settings before all the internet calls
508 Cache.setProxyPropertiesFromPreferences();
510 desktop.setVisible(true);
512 if (!Platform.isJS())
521 * Check to see that the JVM version being run is suitable for the Java
522 * version this Jalview was compiled for. Popup a warning if not.
524 if (!LaunchUtils.checkJavaVersion())
526 Console.warn("The Java version being used (Java "
527 + LaunchUtils.getJavaVersion()
528 + ") may lead to problems. This installation of Jalview should be used with Java "
529 + LaunchUtils.getJavaCompileVersion() + ".");
532 .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
535 MessageManager.getString("label.continue") };
536 JOptionPane.showOptionDialog(null,
537 MessageManager.formatMessage(
538 "warning.wrong_jvm_version_message",
539 LaunchUtils.getJavaVersion(),
540 LaunchUtils.getJavaCompileVersion()),
542 .getString("warning.wrong_jvm_version_title"),
543 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
544 null, options, options[0]);
548 if (!aparser.contains("nowebservicediscovery"))
550 desktop.startServiceDiscovery();
552 if (!aparser.contains("nousagestats"))
554 startUsageStats(desktop);
558 System.err.println("CMD [-nousagestats] executed successfully!");
561 if (!aparser.contains("noquestionnaire"))
563 String url = aparser.getValue("questionnaire");
566 // Start the desktop questionnaire prompter with the specified
568 Console.debug("Starting questionnaire url at " + url);
569 desktop.checkForQuestionnaire(url);
570 System.out.println("CMD questionnaire[-" + url
571 + "] executed successfully!");
575 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
577 // Start the desktop questionnaire prompter with the specified
580 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
582 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
584 "Starting questionnaire with default url: " + defurl);
585 desktop.checkForQuestionnaire(defurl);
592 .println("CMD [-noquestionnaire] executed successfully!");
595 if (!aparser.contains("nonews")
596 || Cache.getProperty("NONEWS") == null)
598 desktop.checkForNews();
601 if (!aparser.contains("nohtmltemplates")
602 || Cache.getProperty("NOHTMLTEMPLATES") == null)
604 BioJsHTMLOutput.updateBioJS();
609 // Check if JVM and compile version might cause problems and log if it
611 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
613 Console.warn("The Java version being used (Java "
614 + LaunchUtils.getJavaVersion()
615 + ") may lead to problems. This installation of Jalview should be used with Java "
616 + LaunchUtils.getJavaCompileVersion() + ".");
619 // Move any new getdown-launcher-new.jar into place over old
620 // getdown-launcher.jar
621 String appdirString = System.getProperty("getdownappdir");
622 if (appdirString != null && appdirString.length() > 0)
624 final File appdir = new File(appdirString);
630 LaunchUtil.upgradeGetdown(
631 new File(appdir, "getdown-launcher-old.jar"),
632 new File(appdir, "getdown-launcher.jar"),
633 new File(appdir, "getdown-launcher-new.jar"));
638 String file = null, data = null;
640 FileFormatI format = null;
642 DataSourceType protocol = null;
644 FileLoader fileLoader = new FileLoader(!headless);
646 String groovyscript = null; // script to execute after all loading is
647 // completed one way or another
648 // extract groovy argument and execute if necessary
649 groovyscript = aparser.getValue("groovy", true);
650 file = aparser.getValue("open", true);
652 if (file == null && desktop == null)
654 System.out.println("No files to open!");
659 // Finally, deal with the remaining input data.
664 desktop.setProgressBar(
666 .getString("status.processing_commandline_args"),
667 progress = System.currentTimeMillis());
669 System.out.println("CMD [-open " + file + "] executed successfully!");
671 if (!Platform.isJS())
673 * ignore in JavaScript -- can't just file existence - could load it?
678 if (!HttpUtils.startsWithHttpOrHttps(file))
680 if (!(new File(file)).exists())
682 System.out.println("Can't find " + file);
691 protocol = AppletFormatAdapter.checkProtocol(file);
695 format = new IdentifyFile().identify(file, protocol);
696 } catch (FileFormatException e1)
701 AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
705 System.out.println("error");
709 setCurrentAlignFrame(af);
710 data = aparser.getValue("colour", true);
713 data.replaceAll("%20", " ");
715 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
716 af.getViewport(), af.getViewport().getAlignment(), data);
721 "CMD [-color " + data + "] executed successfully!");
726 // Must maintain ability to use the groups flag
727 data = aparser.getValue("groups", true);
730 af.parseFeaturesFile(data,
731 AppletFormatAdapter.checkProtocol(data));
732 // System.out.println("Added " + data);
734 "CMD groups[-" + data + "] executed successfully!");
736 data = aparser.getValue("features", true);
739 af.parseFeaturesFile(data,
740 AppletFormatAdapter.checkProtocol(data));
741 // System.out.println("Added " + data);
743 "CMD [-features " + data + "] executed successfully!");
746 data = aparser.getValue("annotations", true);
749 af.loadJalviewDataFile(data, null, null, null);
750 // System.out.println("Added " + data);
752 "CMD [-annotations " + data + "] executed successfully!");
754 // set or clear the sortbytree flag.
755 if (aparser.contains("sortbytree"))
757 af.getViewport().setSortByTree(true);
758 if (af.getViewport().getSortByTree())
760 System.out.println("CMD [-sortbytree] executed successfully!");
763 if (aparser.contains("no-annotation"))
765 af.getViewport().setShowAnnotation(false);
766 if (!af.getViewport().isShowAnnotation())
768 System.out.println("CMD no-annotation executed successfully!");
771 if (aparser.contains("nosortbytree"))
773 af.getViewport().setSortByTree(false);
774 if (!af.getViewport().getSortByTree())
777 .println("CMD [-nosortbytree] executed successfully!");
780 data = aparser.getValue("tree", true);
786 "CMD [-tree " + data + "] executed successfully!");
787 NewickFile nf = new NewickFile(data,
788 AppletFormatAdapter.checkProtocol(data));
790 .setCurrentTree(af.showNewickTree(nf, data).getTree());
791 } catch (IOException ex)
793 System.err.println("Couldn't add tree " + data);
794 ex.printStackTrace(System.err);
797 // TODO - load PDB structure(s) to alignment JAL-629
798 // (associate with identical sequence in alignment, or a specified
800 if (groovyscript != null)
802 // Execute the groovy script after we've done all the rendering stuff
803 // and before any images or figures are generated.
804 System.out.println("Executing script " + groovyscript);
805 executeGroovyScript(groovyscript, af);
806 System.out.println("CMD groovy[" + groovyscript
807 + "] executed successfully!");
810 String imageName = "unnamed.png";
811 while (aparser.getSize() > 1)
813 String outputFormat = aparser.nextValue();
814 file = aparser.nextValue();
816 if (outputFormat.equalsIgnoreCase("png"))
818 af.createPNG(new File(file));
819 imageName = (new File(file)).getName();
820 System.out.println("Creating PNG image: " + file);
823 else if (outputFormat.equalsIgnoreCase("svg"))
825 File imageFile = new File(file);
826 imageName = imageFile.getName();
827 af.createSVG(imageFile);
828 System.out.println("Creating SVG image: " + file);
831 else if (outputFormat.equalsIgnoreCase("html"))
833 File imageFile = new File(file);
834 imageName = imageFile.getName();
835 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
836 htmlSVG.exportHTML(file);
838 System.out.println("Creating HTML image: " + file);
841 else if (outputFormat.equalsIgnoreCase("biojsmsa"))
845 System.err.println("The output html file must not be null");
850 BioJsHTMLOutput.refreshVersionInfo(
851 BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
852 } catch (URISyntaxException e)
856 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
857 bjs.exportHTML(file);
859 .println("Creating BioJS MSA Viwer HTML file: " + file);
862 else if (outputFormat.equalsIgnoreCase("imgMap"))
864 af.createImageMap(new File(file), imageName);
865 System.out.println("Creating image map: " + file);
868 else if (outputFormat.equalsIgnoreCase("eps"))
870 File outputFile = new File(file);
872 "Creating EPS file: " + outputFile.getAbsolutePath());
873 af.createEPS(outputFile);
876 FileFormatI outFormat = null;
879 outFormat = FileFormats.getInstance().forName(outputFormat);
880 } catch (Exception formatP)
882 System.out.println("Couldn't parse " + outFormat
883 + " as a valid Jalview format string.");
885 if (outFormat != null)
887 if (!outFormat.isWritable())
890 "This version of Jalview does not support alignment export as "
895 af.saveAlignment(file, outFormat);
896 if (af.isSaveAlignmentSuccessful())
898 System.out.println("Written alignment in "
899 + outFormat.getName() + " format to " + file);
903 System.out.println("Error writing file " + file + " in "
904 + outFormat.getName() + " format!!");
911 while (aparser.getSize() > 0)
913 System.out.println("Unknown arg: " + aparser.nextValue());
918 AlignFrame startUpAlframe = null;
919 // We'll only open the default file if the desktop is visible.
921 // ////////////////////
923 if (!Platform.isJS() && !headless && file == null
924 && Cache.getDefault("SHOW_STARTUP_FILE", true))
931 file = Cache.getDefault("STARTUP_FILE",
932 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
933 + "/examples/exampleFile_2_7.jvp");
934 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
936 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
938 file.replace("http:", "https:");
939 // hardwire upgrade of the startup file
940 file.replace("_2_3", "_2_7");
941 file.replace("2_7.jar", "2_7.jvp");
942 // and remove the stale setting
943 Cache.removeProperty("STARTUP_FILE");
946 protocol = AppletFormatAdapter.checkProtocol(file);
948 if (file.endsWith(".jar"))
950 format = FileFormat.Jalview;
956 format = new IdentifyFile().identify(file, protocol);
957 } catch (FileFormatException e)
963 startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
965 // don't ask to save when quitting if only the startup file has been
967 Console.debug("Resetting up-to-date flag for startup file");
968 startUpAlframe.getViewport().setSavedUpToDate(true);
969 // extract groovy arguments before anything else.
972 // Once all other stuff is done, execute any groovy scripts (in order)
973 if (groovyscript != null)
975 if (Cache.groovyJarsPresent())
977 System.out.println("Executing script " + groovyscript);
978 executeGroovyScript(groovyscript, startUpAlframe);
983 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
987 // and finally, turn off batch mode indicator - if the desktop still exists
992 desktop.setProgressBar(null, progress);
994 desktop.setInBatchMode(false);
998 private static void setLookAndFeel()
1000 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
1002 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
1003 // try Quaqua/Vaqua.
1004 String lafProp = System.getProperty("laf");
1005 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
1006 String laf = "none";
1007 if (lafProp != null)
1011 else if (lafSetting != null)
1015 boolean lafSet = false;
1018 case "crossplatform":
1019 lafSet = setCrossPlatformLookAndFeel();
1022 Console.error("Could not set requested laf=" + laf);
1026 lafSet = setSystemLookAndFeel();
1029 Console.error("Could not set requested laf=" + laf);
1033 lafSet = setGtkLookAndFeel();
1036 Console.error("Could not set requested laf=" + laf);
1040 lafSet = setMetalLookAndFeel();
1043 Console.error("Could not set requested laf=" + laf);
1047 lafSet = setNimbusLookAndFeel();
1050 Console.error("Could not set requested laf=" + laf);
1054 lafSet = setFlatLookAndFeel();
1057 Console.error("Could not set requested laf=" + laf);
1061 lafSet = setMacLookAndFeel();
1064 Console.error("Could not set requested laf=" + laf);
1070 Console.error("Requested laf=" + laf + " not implemented");
1074 setSystemLookAndFeel();
1075 if (Platform.isLinux())
1077 setLinuxLookAndFeel();
1079 if (Platform.isMac())
1081 setMacLookAndFeel();
1086 private static boolean setCrossPlatformLookAndFeel()
1088 boolean set = false;
1091 UIManager.setLookAndFeel(
1092 UIManager.getCrossPlatformLookAndFeelClassName());
1094 } catch (Exception ex)
1096 Console.error("Unexpected Look and Feel Exception");
1097 Console.error(ex.getMessage());
1098 Console.debug(Cache.getStackTraceString(ex));
1103 private static boolean setSystemLookAndFeel()
1105 boolean set = false;
1108 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1110 } catch (Exception ex)
1112 Console.error("Unexpected Look and Feel Exception");
1113 Console.error(ex.getMessage());
1114 Console.debug(Cache.getStackTraceString(ex));
1119 private static boolean setSpecificLookAndFeel(String name,
1120 String className, boolean nameStartsWith)
1122 boolean set = false;
1125 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1127 if (info.getName() != null && nameStartsWith
1128 ? info.getName().toLowerCase(Locale.ROOT)
1129 .startsWith(name.toLowerCase(Locale.ROOT))
1130 : info.getName().toLowerCase(Locale.ROOT)
1131 .equals(name.toLowerCase(Locale.ROOT)))
1133 className = info.getClassName();
1137 UIManager.setLookAndFeel(className);
1139 } catch (Exception ex)
1141 Console.error("Unexpected Look and Feel Exception");
1142 Console.error(ex.getMessage());
1143 Console.debug(Cache.getStackTraceString(ex));
1148 private static boolean setGtkLookAndFeel()
1150 return setSpecificLookAndFeel("gtk",
1151 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1154 private static boolean setMetalLookAndFeel()
1156 return setSpecificLookAndFeel("metal",
1157 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1160 private static boolean setNimbusLookAndFeel()
1162 return setSpecificLookAndFeel("nimbus",
1163 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1166 private static boolean setFlatLookAndFeel()
1168 boolean set = false;
1169 if (SystemInfo.isMacOS)
1173 UIManager.setLookAndFeel(
1174 "com.formdev.flatlaf.themes.FlatMacLightLaf");
1176 Console.debug("Using FlatMacLightLaf");
1177 } catch (ClassNotFoundException | InstantiationException
1178 | IllegalAccessException | UnsupportedLookAndFeelException e)
1180 Console.debug("Exception loading FlatLightLaf", e);
1182 System.setProperty("apple.laf.useScreenMenuBar", "true");
1183 System.setProperty("apple.awt.application.name",
1184 ChannelProperties.getProperty("app_name"));
1185 System.setProperty("apple.awt.application.appearance", "system");
1186 if (SystemInfo.isMacFullWindowContentSupported
1187 && Desktop.desktop != null)
1189 Console.debug("Setting transparent title bar");
1190 Desktop.desktop.getRootPane()
1191 .putClientProperty("apple.awt.fullWindowContent", true);
1192 Desktop.desktop.getRootPane()
1193 .putClientProperty("apple.awt.transparentTitleBar", true);
1194 Desktop.desktop.getRootPane()
1195 .putClientProperty("apple.awt.fullscreenable", true);
1197 SwingUtilities.invokeLater(() -> {
1198 FlatMacLightLaf.setup();
1200 Console.debug("Using FlatMacLightLaf");
1207 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1209 Console.debug("Using FlatLightLaf");
1210 } catch (ClassNotFoundException | InstantiationException
1211 | IllegalAccessException | UnsupportedLookAndFeelException e)
1213 Console.debug("Exception loading FlatLightLaf", e);
1215 // Windows specific properties here
1216 SwingUtilities.invokeLater(() -> {
1217 FlatLightLaf.setup();
1219 Console.debug("Using FlatLightLaf");
1222 else if (SystemInfo.isLinux)
1226 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1228 Console.debug("Using FlatLightLaf");
1229 } catch (ClassNotFoundException | InstantiationException
1230 | IllegalAccessException | UnsupportedLookAndFeelException e)
1232 Console.debug("Exception loading FlatLightLaf", e);
1234 // enable custom window decorations
1235 JFrame.setDefaultLookAndFeelDecorated(true);
1236 JDialog.setDefaultLookAndFeelDecorated(true);
1237 SwingUtilities.invokeLater(() -> {
1238 FlatLightLaf.setup();
1240 Console.debug("Using FlatLightLaf");
1248 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1250 Console.debug("Using FlatLightLaf");
1251 } catch (ClassNotFoundException | InstantiationException
1252 | IllegalAccessException | UnsupportedLookAndFeelException e)
1254 Console.debug("Exception loading FlatLightLaf", e);
1260 UIManager.put("TabbedPane.tabType", "card");
1261 UIManager.put("TabbedPane.showTabSeparators", true);
1262 UIManager.put("TabbedPane.showContentSeparator", true);
1263 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1264 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1265 UIManager.put("TabbedPane.hasFullBorder", true);
1266 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1267 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1268 UIManager.put("TabbedPane.smoothScrolling", true);
1269 UIManager.put("TabbedPane.tabWidthMode", "compact");
1270 UIManager.put("TabbedPane.selectedBackground", Color.white);
1273 Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
1277 private static boolean setMacLookAndFeel()
1279 boolean set = false;
1280 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1281 ChannelProperties.getProperty("app_name"));
1282 System.setProperty("apple.laf.useScreenMenuBar", "true");
1284 * broken native LAFs on (ARM?) macbooks
1285 set = setQuaquaLookAndFeel();
1286 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1287 .toLowerCase(Locale.ROOT).contains("quaqua"))
1289 set = setVaquaLookAndFeel();
1292 set = setFlatLookAndFeel();
1296 private static boolean setLinuxLookAndFeel()
1298 boolean set = false;
1299 set = setFlatLookAndFeel();
1301 set = setMetalLookAndFeel();
1302 // avoid GtkLookAndFeel -- not good results especially on HiDPI
1304 set = setNimbusLookAndFeel();
1308 private static void showUsage()
1311 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1312 + "-nodisplay\tRun Jalview without User Interface.\n"
1313 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1314 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1315 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1316 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1317 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1318 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1319 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1320 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1321 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1322 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1323 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1324 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1325 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1326 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1327 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1328 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1329 + "-html FILE\tCreate HTML file from alignment.\n"
1330 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1331 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1332 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1333 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1334 + "-noquestionnaire\tTurn off questionnaire check.\n"
1335 + "-nonews\tTurn off check for Jalview news.\n"
1336 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1337 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1339 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1340 // after all other properties files have been read\n\t
1341 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1342 // passed in correctly)"
1343 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1344 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1345 + "-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"
1346 + "-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"
1347 + "-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"
1348 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1351 private static void startUsageStats(final Desktop desktop)
1354 * start a User Config prompt asking if we can log usage statistics.
1356 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
1357 "USAGESTATS", "Jalview Usage Statistics",
1358 "Do you want to help make Jalview better by enabling "
1359 + "the collection of usage statistics with Google Analytics ?"
1360 + "\n\n(you can enable or disable usage tracking in the preferences)",
1367 "Initialising googletracker for usage stats.");
1368 Cache.initGoogleTracker();
1369 Console.debug("Tracking enabled.");
1376 Console.debug("Not enabling Google Tracking.");
1379 desktop.addDialogThread(prompter);
1383 * Locate the given string as a file and pass it to the groovy interpreter.
1385 * @param groovyscript
1386 * the script to execute
1387 * @param jalviewContext
1388 * the Jalview Desktop object passed in to the groovy binding as the
1391 private void executeGroovyScript(String groovyscript, AlignFrame af)
1394 * for scripts contained in files
1401 if (groovyscript.trim().equals("STDIN"))
1403 // read from stdin into a tempfile and execute it
1406 tfile = File.createTempFile("jalview", "groovy");
1407 PrintWriter outfile = new PrintWriter(
1408 new OutputStreamWriter(new FileOutputStream(tfile)));
1409 BufferedReader br = new BufferedReader(
1410 new InputStreamReader(System.in));
1412 while ((line = br.readLine()) != null)
1414 outfile.write(line + "\n");
1420 } catch (Exception ex)
1422 System.err.println("Failed to read from STDIN into tempfile "
1423 + ((tfile == null) ? "(tempfile wasn't created)"
1424 : tfile.toString()));
1425 ex.printStackTrace();
1430 sfile = tfile.toURI().toURL();
1431 } catch (Exception x)
1434 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1436 x.printStackTrace();
1444 sfile = new URI(groovyscript).toURL();
1445 } catch (Exception x)
1447 tfile = new File(groovyscript);
1448 if (!tfile.exists())
1450 System.err.println("File '" + groovyscript + "' does not exist.");
1453 if (!tfile.canRead())
1455 System.err.println("File '" + groovyscript + "' cannot be read.");
1458 if (tfile.length() < 1)
1460 System.err.println("File '" + groovyscript + "' is empty.");
1465 sfile = tfile.getAbsoluteFile().toURI().toURL();
1466 } catch (Exception ex)
1468 System.err.println("Failed to create a file URL for "
1469 + tfile.getAbsoluteFile());
1476 Map<String, java.lang.Object> vbinding = new HashMap<>();
1477 vbinding.put("Jalview", this);
1480 vbinding.put("currentAlFrame", af);
1482 Binding gbinding = new Binding(vbinding);
1483 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1484 gse.run(sfile.toString(), gbinding);
1485 if ("STDIN".equals(groovyscript))
1487 // delete temp file that we made -
1488 // only if it was successfully executed
1491 } catch (Exception e)
1493 System.err.println("Exception Whilst trying to execute file " + sfile
1494 + " as a groovy script.");
1495 e.printStackTrace(System.err);
1500 public static boolean isHeadlessMode()
1502 String isheadless = System.getProperty("java.awt.headless");
1503 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1510 public AlignFrame[] getAlignFrames()
1512 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1513 : Desktop.getAlignFrames();
1518 * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
1522 // System.exit will run the shutdownHook first
1526 public static AlignFrame getCurrentAlignFrame()
1528 return Jalview.currentAlignFrame;
1531 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1533 Jalview.currentAlignFrame = currentAlignFrame;