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.JOptionPane;
49 import javax.swing.SwingUtilities;
50 import javax.swing.UIManager;
51 import javax.swing.UIManager.LookAndFeelInfo;
52 import javax.swing.UnsupportedLookAndFeelException;
54 import com.formdev.flatlaf.FlatLightLaf;
55 import com.formdev.flatlaf.util.SystemInfo;
56 import com.threerings.getdown.util.LaunchUtil;
58 //import edu.stanford.ejalbert.launching.IBrowserLaunching;
59 import groovy.lang.Binding;
60 import groovy.util.GroovyScriptEngine;
61 import jalview.bin.ArgParser.Arg;
62 import jalview.ext.so.SequenceOntology;
63 import jalview.gui.AlignFrame;
64 import jalview.gui.Desktop;
65 import jalview.gui.PromptUserConfig;
66 import jalview.gui.QuitHandler;
67 import jalview.gui.QuitHandler.QResponse;
68 import jalview.io.AppletFormatAdapter;
69 import jalview.io.BioJsHTMLOutput;
70 import jalview.io.DataSourceType;
71 import jalview.io.FileFormat;
72 import jalview.io.FileFormatException;
73 import jalview.io.FileFormatI;
74 import jalview.io.FileFormats;
75 import jalview.io.FileLoader;
76 import jalview.io.HtmlSvgOutput;
77 import jalview.io.IdentifyFile;
78 import jalview.io.NewickFile;
79 import jalview.io.gff.SequenceOntologyFactory;
80 import jalview.schemes.ColourSchemeI;
81 import jalview.schemes.ColourSchemeProperty;
82 import jalview.util.ChannelProperties;
83 import jalview.util.HttpUtils;
84 import jalview.util.LaunchUtils;
85 import jalview.util.MessageManager;
86 import jalview.util.Platform;
87 import jalview.ws.jws2.Jws2Discoverer;
90 * Main class for Jalview Application <br>
92 * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
95 * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
96 * jalview.bin.Jalview jalview.bin.Jalview
98 * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
99 * embellish '*' to e.g. '*.jar')
102 * @version $Revision$
108 Platform.getURLCommandArguments();
109 Platform.addJ2SDirectDatabaseCall("https://www.jalview.org");
110 Platform.addJ2SDirectDatabaseCall("http://www.jalview.org");
111 Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk");
112 Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk");
116 * singleton instance of this class
118 private static Jalview instance;
120 private Desktop desktop;
122 public static AlignFrame currentAlignFrame;
126 if (!Platform.isJS())
133 // grab all the rights we can for the JVM
134 Policy.setPolicy(new Policy()
137 public PermissionCollection getPermissions(CodeSource codesource)
139 Permissions perms = new Permissions();
140 perms.add(new AllPermission());
145 public void refresh()
153 * keep track of feature fetching tasks.
161 * TODO: generalise to track all jalview events to orchestrate batch processing
165 private int queued = 0;
167 private int running = 0;
169 public FeatureFetcher()
174 public void addFetcher(final AlignFrame af,
175 final Vector<String> dasSources)
177 final long id = System.currentTimeMillis();
179 final FeatureFetcher us = this;
180 new Thread(new Runnable()
192 af.setProgressBar(MessageManager
193 .getString("status.das_features_being_retrived"), id);
194 af.featureSettings_actionPerformed(null);
195 af.setProgressBar(null, id);
204 public synchronized boolean allFinished()
206 return queued == 0 && running == 0;
211 public static Jalview getInstance()
217 * main class for Jalview application
220 * open <em>filename</em>
222 public static void main(String[] args)
224 // setLogging(); // BH - for event debugging in JavaScript
225 instance = new Jalview();
226 instance.doMain(args);
229 private static void logClass(String name)
231 // BH - for event debugging in JavaScript
232 ConsoleHandler consoleHandler = new ConsoleHandler();
233 consoleHandler.setLevel(Level.ALL);
234 Logger logger = Logger.getLogger(name);
235 logger.setLevel(Level.ALL);
236 logger.addHandler(consoleHandler);
239 @SuppressWarnings("unused")
240 private static void setLogging()
248 System.out.println("not in js");
251 // BH - for event debugging in JavaScript (Java mode only)
252 if (!Platform.isJS())
259 Logger.getLogger("").setLevel(Level.ALL);
260 logClass("java.awt.EventDispatchThread");
261 logClass("java.awt.EventQueue");
262 logClass("java.awt.Component");
263 logClass("java.awt.focus.Component");
264 logClass("java.awt.focus.DefaultKeyboardFocusManager");
272 void doMain(String[] args)
275 if (!Platform.isJS())
277 System.setSecurityManager(null);
279 Runtime.getRuntime().addShutdownHook(new Thread()
283 Console.debug("Running shutdown hook");
284 if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT)
286 // Got to here by a SIGTERM signal.
287 // Note we will not actually cancel the quit from here -- it's too
288 // late -- but we can wait for saving files.
289 Console.debug("Checking for saving files");
290 QuitHandler.getQuitResponse(false);
294 Console.debug("Nothing more to do");
296 Console.debug("Exiting, bye!");
297 // shutdownHook cannot be cancelled, JVM will now halt
303 .println("Java version: " + System.getProperty("java.version"));
304 System.out.println("Java Home: " + System.getProperty("java.home"));
305 System.out.println(System.getProperty("os.arch") + " "
306 + System.getProperty("os.name") + " "
307 + System.getProperty("os.version"));
309 String val = System.getProperty("sys.install4jVersion");
312 System.out.println("Install4j version: " + val);
314 val = System.getProperty("installer_template_version");
317 System.out.println("Install4j template version: " + val);
319 val = System.getProperty("launcher_version");
322 System.out.println("Launcher version: " + val);
325 // report Jalview version
326 Cache.loadBuildProperties(true);
329 ArgsParser aparser = new ArgsParser(args);
331 boolean headless = false;
335 Console.initLogger();
336 } catch (NoClassDefFoundError error)
338 error.printStackTrace();
339 System.out.println("\nEssential logging libraries not found."
340 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
344 String usrPropsFile = aparser.getValue("props");
345 Cache.loadProperties(usrPropsFile); // must do this
347 if (usrPropsFile != null)
350 "CMD [-props " + usrPropsFile + "] executed successfully!");
353 // set log level from cache properties
354 Console.setLogLevel(Cache.getDefault(Cache.JALVIEWLOGLEVEL, "INFO"));
357 ArgParser argparser = new ArgParser(args); // do this after
358 // Console.initLogger, but TODO
359 // want --props before then
362 if (argparser.isSet(Arg.HEADLESS))
363 headless = argparser.getBool(Arg.HEADLESS);
364 boolean commandsSuccess = Commands.processArgs(argparser, headless);
367 Console.info("Successfully completed commands");
373 Console.warn("Error when running commands");
378 if (!Platform.isJS())
385 if (argparser.isSet(Arg.HEADLESS))
387 headless = argparser.getBool(Arg.HEADLESS);
390 if (aparser.contains("help") || aparser.contains("h"))
395 if (headless || aparser.contains("nodisplay")
396 || aparser.contains("nogui") || aparser.contains("headless"))
398 System.setProperty("java.awt.headless", "true");
403 // allow https handshakes to download intermediate certs if necessary
404 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
406 final String jabawsUrl = aparser.getValue("jabaws");
407 if (jabawsUrl != null)
411 Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
413 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
414 } catch (MalformedURLException e)
417 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
422 String defs = aparser.getValue("setprop");
425 int p = defs.indexOf('=');
428 System.err.println("Ignoring invalid setprop argument : " + defs);
432 System.out.println("Executing setprop argument: " + defs);
435 Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
437 // DISABLED FOR SECURITY REASONS
438 // TODO: add a property to allow properties to be overriden by cli args
439 // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
441 defs = aparser.getValue("setprop");
443 if (System.getProperty("java.awt.headless") != null
444 && System.getProperty("java.awt.headless").equals("true"))
448 System.setProperty("http.agent",
449 "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
456 * configure 'full' SO model if preferences say to, else use the default (full SO)
457 * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
459 boolean soDefault = !Platform.isJS();
460 if (Cache.getDefault("USE_FULL_SO", soDefault))
462 SequenceOntologyFactory.setInstance(new SequenceOntology());
467 Desktop.nosplash = aparser.contains("nosplash");
468 desktop = new Desktop();
469 desktop.setInBatchMode(true); // indicate we are starting up
473 JalviewTaskbar.setTaskbar(this);
474 } catch (Exception e)
476 Console.info("Cannot set Taskbar");
477 Console.error(e.getMessage());
478 // e.printStackTrace();
479 } catch (Throwable t)
481 Console.info("Cannot set Taskbar");
482 Console.error(t.getMessage());
483 // t.printStackTrace();
486 // set Proxy settings before all the internet calls
487 Cache.setProxyPropertiesFromPreferences();
489 desktop.setVisible(true);
491 if (!Platform.isJS())
500 * Check to see that the JVM version being run is suitable for the Java
501 * version this Jalview was compiled for. Popup a warning if not.
503 if (!LaunchUtils.checkJavaVersion())
505 Console.warn("The Java version being used (Java "
506 + LaunchUtils.getJavaVersion()
507 + ") may lead to problems. This installation of Jalview should be used with Java "
508 + LaunchUtils.getJavaCompileVersion() + ".");
511 .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
514 MessageManager.getString("label.continue") };
515 JOptionPane.showOptionDialog(null,
516 MessageManager.formatMessage(
517 "warning.wrong_jvm_version_message",
518 LaunchUtils.getJavaVersion(),
519 LaunchUtils.getJavaCompileVersion()),
521 .getString("warning.wrong_jvm_version_title"),
522 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
523 null, options, options[0]);
527 if (!aparser.contains("nowebservicediscovery"))
529 desktop.startServiceDiscovery();
531 if (!aparser.contains("nousagestats"))
533 startUsageStats(desktop);
537 System.err.println("CMD [-nousagestats] executed successfully!");
540 if (!aparser.contains("noquestionnaire"))
542 String url = aparser.getValue("questionnaire");
545 // Start the desktop questionnaire prompter with the specified
547 Console.debug("Starting questionnaire url at " + url);
548 desktop.checkForQuestionnaire(url);
549 System.out.println("CMD questionnaire[-" + url
550 + "] executed successfully!");
554 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
556 // Start the desktop questionnaire prompter with the specified
559 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
561 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
563 "Starting questionnaire with default url: " + defurl);
564 desktop.checkForQuestionnaire(defurl);
571 .println("CMD [-noquestionnaire] executed successfully!");
574 if (!aparser.contains("nonews")
575 || Cache.getProperty("NONEWS") == null)
577 desktop.checkForNews();
580 if (!aparser.contains("nohtmltemplates")
581 || Cache.getProperty("NOHTMLTEMPLATES") == null)
583 BioJsHTMLOutput.updateBioJS();
588 // Check if JVM and compile version might cause problems and log if it
590 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
592 Console.warn("The Java version being used (Java "
593 + LaunchUtils.getJavaVersion()
594 + ") may lead to problems. This installation of Jalview should be used with Java "
595 + LaunchUtils.getJavaCompileVersion() + ".");
598 // Move any new getdown-launcher-new.jar into place over old
599 // getdown-launcher.jar
600 String appdirString = System.getProperty("getdownappdir");
601 if (appdirString != null && appdirString.length() > 0)
603 final File appdir = new File(appdirString);
609 LaunchUtil.upgradeGetdown(
610 new File(appdir, "getdown-launcher-old.jar"),
611 new File(appdir, "getdown-launcher.jar"),
612 new File(appdir, "getdown-launcher-new.jar"));
617 String file = null, data = null;
619 FileFormatI format = null;
621 DataSourceType protocol = null;
623 FileLoader fileLoader = new FileLoader(!headless);
625 String groovyscript = null; // script to execute after all loading is
626 // completed one way or another
627 // extract groovy argument and execute if necessary
628 groovyscript = aparser.getValue("groovy", true);
629 file = aparser.getValue("open", true);
631 if (file == null && desktop == null)
633 System.out.println("No files to open!");
638 // Finally, deal with the remaining input data.
643 desktop.setProgressBar(
645 .getString("status.processing_commandline_args"),
646 progress = System.currentTimeMillis());
648 System.out.println("CMD [-open " + file + "] executed successfully!");
650 if (!Platform.isJS())
652 * ignore in JavaScript -- can't just file existence - could load it?
657 if (!HttpUtils.startsWithHttpOrHttps(file))
659 if (!(new File(file)).exists())
661 System.out.println("Can't find " + file);
670 protocol = AppletFormatAdapter.checkProtocol(file);
674 format = new IdentifyFile().identify(file, protocol);
675 } catch (FileFormatException e1)
680 AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
684 System.out.println("error");
688 setCurrentAlignFrame(af);
689 data = aparser.getValue("colour", true);
692 data.replaceAll("%20", " ");
694 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
695 af.getViewport(), af.getViewport().getAlignment(), data);
700 "CMD [-color " + data + "] executed successfully!");
705 // Must maintain ability to use the groups flag
706 data = aparser.getValue("groups", true);
709 af.parseFeaturesFile(data,
710 AppletFormatAdapter.checkProtocol(data));
711 // System.out.println("Added " + data);
713 "CMD groups[-" + data + "] executed successfully!");
715 data = aparser.getValue("features", true);
718 af.parseFeaturesFile(data,
719 AppletFormatAdapter.checkProtocol(data));
720 // System.out.println("Added " + data);
722 "CMD [-features " + data + "] executed successfully!");
725 data = aparser.getValue("annotations", true);
728 af.loadJalviewDataFile(data, null, null, null);
729 // System.out.println("Added " + data);
731 "CMD [-annotations " + data + "] executed successfully!");
733 // set or clear the sortbytree flag.
734 if (aparser.contains("sortbytree"))
736 af.getViewport().setSortByTree(true);
737 if (af.getViewport().getSortByTree())
739 System.out.println("CMD [-sortbytree] executed successfully!");
742 if (aparser.contains("no-annotation"))
744 af.getViewport().setShowAnnotation(false);
745 if (!af.getViewport().isShowAnnotation())
747 System.out.println("CMD no-annotation executed successfully!");
750 if (aparser.contains("nosortbytree"))
752 af.getViewport().setSortByTree(false);
753 if (!af.getViewport().getSortByTree())
756 .println("CMD [-nosortbytree] executed successfully!");
759 data = aparser.getValue("tree", true);
765 "CMD [-tree " + data + "] executed successfully!");
766 NewickFile nf = new NewickFile(data,
767 AppletFormatAdapter.checkProtocol(data));
769 .setCurrentTree(af.showNewickTree(nf, data).getTree());
770 } catch (IOException ex)
772 System.err.println("Couldn't add tree " + data);
773 ex.printStackTrace(System.err);
776 // TODO - load PDB structure(s) to alignment JAL-629
777 // (associate with identical sequence in alignment, or a specified
779 if (groovyscript != null)
781 // Execute the groovy script after we've done all the rendering stuff
782 // and before any images or figures are generated.
783 System.out.println("Executing script " + groovyscript);
784 executeGroovyScript(groovyscript, af);
785 System.out.println("CMD groovy[" + groovyscript
786 + "] executed successfully!");
789 String imageName = "unnamed.png";
790 while (aparser.getSize() > 1)
792 String outputFormat = aparser.nextValue();
793 file = aparser.nextValue();
795 if (outputFormat.equalsIgnoreCase("png"))
797 af.createPNG(new File(file));
798 imageName = (new File(file)).getName();
799 System.out.println("Creating PNG image: " + file);
802 else if (outputFormat.equalsIgnoreCase("svg"))
804 File imageFile = new File(file);
805 imageName = imageFile.getName();
806 af.createSVG(imageFile);
807 System.out.println("Creating SVG image: " + file);
810 else if (outputFormat.equalsIgnoreCase("html"))
812 File imageFile = new File(file);
813 imageName = imageFile.getName();
814 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
815 htmlSVG.exportHTML(file);
817 System.out.println("Creating HTML image: " + file);
820 else if (outputFormat.equalsIgnoreCase("biojsmsa"))
824 System.err.println("The output html file must not be null");
829 BioJsHTMLOutput.refreshVersionInfo(
830 BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
831 } catch (URISyntaxException e)
835 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
836 bjs.exportHTML(file);
838 .println("Creating BioJS MSA Viwer HTML file: " + file);
841 else if (outputFormat.equalsIgnoreCase("imgMap"))
843 af.createImageMap(new File(file), imageName);
844 System.out.println("Creating image map: " + file);
847 else if (outputFormat.equalsIgnoreCase("eps"))
849 File outputFile = new File(file);
851 "Creating EPS file: " + outputFile.getAbsolutePath());
852 af.createEPS(outputFile);
855 FileFormatI outFormat = null;
858 outFormat = FileFormats.getInstance().forName(outputFormat);
859 } catch (Exception formatP)
861 System.out.println("Couldn't parse " + outFormat
862 + " as a valid Jalview format string.");
864 if (outFormat != null)
866 if (!outFormat.isWritable())
869 "This version of Jalview does not support alignment export as "
874 af.saveAlignment(file, outFormat);
875 if (af.isSaveAlignmentSuccessful())
877 System.out.println("Written alignment in "
878 + outFormat.getName() + " format to " + file);
882 System.out.println("Error writing file " + file + " in "
883 + outFormat.getName() + " format!!");
890 while (aparser.getSize() > 0)
892 System.out.println("Unknown arg: " + aparser.nextValue());
897 AlignFrame startUpAlframe = null;
898 // We'll only open the default file if the desktop is visible.
900 // ////////////////////
902 if (!Platform.isJS() && !headless && file == null
903 && Cache.getDefault("SHOW_STARTUP_FILE", true))
910 file = Cache.getDefault("STARTUP_FILE",
911 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
912 + "/examples/exampleFile_2_7.jvp");
913 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
915 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
917 file.replace("http:", "https:");
918 // hardwire upgrade of the startup file
919 file.replace("_2_3", "_2_7");
920 file.replace("2_7.jar", "2_7.jvp");
921 // and remove the stale setting
922 Cache.removeProperty("STARTUP_FILE");
925 protocol = AppletFormatAdapter.checkProtocol(file);
927 if (file.endsWith(".jar"))
929 format = FileFormat.Jalview;
935 format = new IdentifyFile().identify(file, protocol);
936 } catch (FileFormatException e)
942 startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
944 // extract groovy arguments before anything else.
947 // Once all other stuff is done, execute any groovy scripts (in order)
948 if (groovyscript != null)
950 if (Cache.groovyJarsPresent())
952 System.out.println("Executing script " + groovyscript);
953 executeGroovyScript(groovyscript, startUpAlframe);
958 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
962 // and finally, turn off batch mode indicator - if the desktop still exists
967 desktop.setProgressBar(null, progress);
969 desktop.setInBatchMode(false);
973 private static void setLookAndFeel()
975 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
977 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
979 String lafProp = System.getProperty("laf");
980 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
986 else if (lafSetting != null)
990 boolean lafSet = false;
993 case "crossplatform":
994 lafSet = setCrossPlatformLookAndFeel();
997 Console.error("Could not set requested laf=" + laf);
1001 lafSet = setSystemLookAndFeel();
1004 Console.error("Could not set requested laf=" + laf);
1008 lafSet = setGtkLookAndFeel();
1011 Console.error("Could not set requested laf=" + laf);
1015 lafSet = setMetalLookAndFeel();
1018 Console.error("Could not set requested laf=" + laf);
1022 lafSet = setNimbusLookAndFeel();
1025 Console.error("Could not set requested laf=" + laf);
1029 lafSet = setFlatLookAndFeel();
1032 Console.error("Could not set requested laf=" + laf);
1036 lafSet = setQuaquaLookAndFeel();
1039 Console.error("Could not set requested laf=" + laf);
1043 lafSet = setVaquaLookAndFeel();
1046 Console.error("Could not set requested laf=" + laf);
1050 lafSet = setMacLookAndFeel();
1053 Console.error("Could not set requested laf=" + laf);
1059 Console.error("Requested laf=" + laf + " not implemented");
1063 setSystemLookAndFeel();
1064 if (Platform.isLinux())
1066 setLinuxLookAndFeel();
1068 if (Platform.isMac())
1070 setMacLookAndFeel();
1075 private static boolean setCrossPlatformLookAndFeel()
1077 boolean set = false;
1080 UIManager.setLookAndFeel(
1081 UIManager.getCrossPlatformLookAndFeelClassName());
1083 } catch (Exception ex)
1085 Console.error("Unexpected Look and Feel Exception");
1086 Console.error(ex.getMessage());
1087 Console.debug(Cache.getStackTraceString(ex));
1092 private static boolean setSystemLookAndFeel()
1094 boolean set = false;
1097 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1099 } catch (Exception ex)
1101 Console.error("Unexpected Look and Feel Exception");
1102 Console.error(ex.getMessage());
1103 Console.debug(Cache.getStackTraceString(ex));
1108 private static boolean setSpecificLookAndFeel(String name,
1109 String className, boolean nameStartsWith)
1111 boolean set = false;
1114 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1116 if (info.getName() != null && nameStartsWith
1117 ? info.getName().toLowerCase(Locale.ROOT)
1118 .startsWith(name.toLowerCase(Locale.ROOT))
1119 : info.getName().toLowerCase(Locale.ROOT)
1120 .equals(name.toLowerCase(Locale.ROOT)))
1122 className = info.getClassName();
1126 UIManager.setLookAndFeel(className);
1128 } catch (Exception ex)
1130 Console.error("Unexpected Look and Feel Exception");
1131 Console.error(ex.getMessage());
1132 Console.debug(Cache.getStackTraceString(ex));
1137 private static boolean setGtkLookAndFeel()
1139 return setSpecificLookAndFeel("gtk",
1140 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1143 private static boolean setMetalLookAndFeel()
1145 return setSpecificLookAndFeel("metal",
1146 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1149 private static boolean setNimbusLookAndFeel()
1151 return setSpecificLookAndFeel("nimbus",
1152 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1155 private static boolean setFlatLookAndFeel()
1157 boolean set = false;
1158 if (Platform.isMac()) {
1161 UIManager.setLookAndFeel("com.formdev.flatlaf.themes.FlatMacLightLaf");
1163 } catch (ClassNotFoundException | InstantiationException
1164 | IllegalAccessException | UnsupportedLookAndFeelException e)
1166 Console.debug("Exception loading FlatMacLightLaf", e);
1172 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1174 } catch (ClassNotFoundException | InstantiationException
1175 | IllegalAccessException | UnsupportedLookAndFeelException e)
1177 Console.debug("Exception loading FlatLightLaf", e);
1182 if (Platform.isMac())
1184 System.setProperty("apple.laf.useScreenMenuBar", "true");
1185 System.setProperty("apple.awt.application.name",
1186 ChannelProperties.getProperty("app_name"));
1187 System.setProperty("apple.awt.application.appearance", "system");
1188 if (SystemInfo.isMacFullWindowContentSupported
1189 && Desktop.desktop != null)
1191 Desktop.desktop.getRootPane()
1192 .putClientProperty("apple.awt.fullWindowContent", true);
1193 Desktop.desktop.getRootPane()
1194 .putClientProperty("apple.awt.transparentTitleBar", true);
1197 SwingUtilities.invokeLater(() -> {
1198 FlatLightLaf.setup();
1202 UIManager.put("TabbedPane.showTabSeparators", true);
1203 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1204 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1205 // UIManager.put("TabbedPane.hasFullBorder", true);
1206 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1207 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1208 UIManager.put("TabbedPane.smoothScrolling", true);
1209 UIManager.put("TabbedPane.tabWidthMode", "compact");
1210 UIManager.put("TabbedPane.selectedBackground", Color.white);
1213 Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
1217 private static boolean setQuaquaLookAndFeel()
1219 return setSpecificLookAndFeel("quaqua",
1220 ch.randelshofer.quaqua.QuaquaManager.getLookAndFeel().getClass()
1225 private static boolean setVaquaLookAndFeel()
1227 return setSpecificLookAndFeel("vaqua",
1228 "org.violetlib.aqua.AquaLookAndFeel", false);
1231 private static boolean setMacLookAndFeel()
1233 boolean set = false;
1234 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1235 ChannelProperties.getProperty("app_name"));
1236 System.setProperty("apple.laf.useScreenMenuBar", "true");
1238 * broken native LAFs on (ARM?) macbooks
1239 set = setQuaquaLookAndFeel();
1240 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1241 .toLowerCase(Locale.ROOT).contains("quaqua"))
1243 set = setVaquaLookAndFeel();
1246 set = setFlatLookAndFeel();
1250 private static boolean setLinuxLookAndFeel()
1252 boolean set = false;
1253 set = setFlatLookAndFeel();
1255 set = setMetalLookAndFeel();
1256 // avoid GtkLookAndFeel -- not good results especially on HiDPI
1258 set = setNimbusLookAndFeel();
1262 private static void showUsage()
1265 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1266 + "-nodisplay\tRun Jalview without User Interface.\n"
1267 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1268 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1269 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1270 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1271 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1272 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1273 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1274 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1275 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1276 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1277 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1278 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1279 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1280 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1281 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1282 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1283 + "-html FILE\tCreate HTML file from alignment.\n"
1284 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1285 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1286 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1287 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1288 + "-noquestionnaire\tTurn off questionnaire check.\n"
1289 + "-nonews\tTurn off check for Jalview news.\n"
1290 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1291 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1293 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1294 // after all other properties files have been read\n\t
1295 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1296 // passed in correctly)"
1297 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1298 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1299 + "-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"
1300 + "-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"
1301 + "-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"
1302 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1305 private static void startUsageStats(final Desktop desktop)
1308 * start a User Config prompt asking if we can log usage statistics.
1310 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
1311 "USAGESTATS", "Jalview Usage Statistics",
1312 "Do you want to help make Jalview better by enabling "
1313 + "the collection of usage statistics with Google Analytics ?"
1314 + "\n\n(you can enable or disable usage tracking in the preferences)",
1321 "Initialising googletracker for usage stats.");
1322 Cache.initGoogleTracker();
1323 Console.debug("Tracking enabled.");
1330 Console.debug("Not enabling Google Tracking.");
1333 desktop.addDialogThread(prompter);
1337 * Locate the given string as a file and pass it to the groovy interpreter.
1339 * @param groovyscript
1340 * the script to execute
1341 * @param jalviewContext
1342 * the Jalview Desktop object passed in to the groovy binding as the
1345 private void executeGroovyScript(String groovyscript, AlignFrame af)
1348 * for scripts contained in files
1355 if (groovyscript.trim().equals("STDIN"))
1357 // read from stdin into a tempfile and execute it
1360 tfile = File.createTempFile("jalview", "groovy");
1361 PrintWriter outfile = new PrintWriter(
1362 new OutputStreamWriter(new FileOutputStream(tfile)));
1363 BufferedReader br = new BufferedReader(
1364 new InputStreamReader(System.in));
1366 while ((line = br.readLine()) != null)
1368 outfile.write(line + "\n");
1374 } catch (Exception ex)
1376 System.err.println("Failed to read from STDIN into tempfile "
1377 + ((tfile == null) ? "(tempfile wasn't created)"
1378 : tfile.toString()));
1379 ex.printStackTrace();
1384 sfile = tfile.toURI().toURL();
1385 } catch (Exception x)
1388 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1390 x.printStackTrace();
1398 sfile = new URI(groovyscript).toURL();
1399 } catch (Exception x)
1401 tfile = new File(groovyscript);
1402 if (!tfile.exists())
1404 System.err.println("File '" + groovyscript + "' does not exist.");
1407 if (!tfile.canRead())
1409 System.err.println("File '" + groovyscript + "' cannot be read.");
1412 if (tfile.length() < 1)
1414 System.err.println("File '" + groovyscript + "' is empty.");
1419 sfile = tfile.getAbsoluteFile().toURI().toURL();
1420 } catch (Exception ex)
1422 System.err.println("Failed to create a file URL for "
1423 + tfile.getAbsoluteFile());
1430 Map<String, java.lang.Object> vbinding = new HashMap<>();
1431 vbinding.put("Jalview", this);
1434 vbinding.put("currentAlFrame", af);
1436 Binding gbinding = new Binding(vbinding);
1437 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1438 gse.run(sfile.toString(), gbinding);
1439 if ("STDIN".equals(groovyscript))
1441 // delete temp file that we made -
1442 // only if it was successfully executed
1445 } catch (Exception e)
1447 System.err.println("Exception Whilst trying to execute file " + sfile
1448 + " as a groovy script.");
1449 e.printStackTrace(System.err);
1454 public static boolean isHeadlessMode()
1456 String isheadless = System.getProperty("java.awt.headless");
1457 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1464 public AlignFrame[] getAlignFrames()
1466 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1467 : Desktop.getAlignFrames();
1472 * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
1476 // System.exit will run the shutdownHook first
1480 public static AlignFrame getCurrentAlignFrame()
1482 return Jalview.currentAlignFrame;
1485 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1487 Jalview.currentAlignFrame = currentAlignFrame;