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;
53 import com.formdev.flatlaf.FlatLightLaf;
54 import com.formdev.flatlaf.util.SystemInfo;
55 import com.threerings.getdown.util.LaunchUtil;
57 //import edu.stanford.ejalbert.launching.IBrowserLaunching;
58 import groovy.lang.Binding;
59 import groovy.util.GroovyScriptEngine;
60 import jalview.ext.so.SequenceOntology;
61 import jalview.gui.AlignFrame;
62 import jalview.gui.Desktop;
63 import jalview.gui.PromptUserConfig;
64 import jalview.io.AppletFormatAdapter;
65 import jalview.io.BioJsHTMLOutput;
66 import jalview.io.DataSourceType;
67 import jalview.io.FileFormat;
68 import jalview.io.FileFormatException;
69 import jalview.io.FileFormatI;
70 import jalview.io.FileFormats;
71 import jalview.io.FileLoader;
72 import jalview.io.HtmlSvgOutput;
73 import jalview.io.IdentifyFile;
74 import jalview.io.NewickFile;
75 import jalview.io.gff.SequenceOntologyFactory;
76 import jalview.schemes.ColourSchemeI;
77 import jalview.schemes.ColourSchemeProperty;
78 import jalview.util.ChannelProperties;
79 import jalview.util.HttpUtils;
80 import jalview.util.LaunchUtils;
81 import jalview.util.MessageManager;
82 import jalview.util.Platform;
83 import jalview.ws.jws2.Jws2Discoverer;
86 * Main class for Jalview Application <br>
88 * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
91 * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
92 * jalview.bin.Jalview jalview.bin.Jalview
94 * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
95 * embellish '*' to e.g. '*.jar')
104 Platform.getURLCommandArguments();
105 Platform.addJ2SDirectDatabaseCall("https://www.jalview.org");
106 Platform.addJ2SDirectDatabaseCall("http://www.jalview.org");
107 Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk");
108 Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk");
112 * singleton instance of this class
114 private static Jalview instance;
116 private Desktop desktop;
118 public static AlignFrame currentAlignFrame;
122 if (!Platform.isJS())
129 // grab all the rights we can for the JVM
130 Policy.setPolicy(new Policy()
133 public PermissionCollection getPermissions(CodeSource codesource)
135 Permissions perms = new Permissions();
136 perms.add(new AllPermission());
141 public void refresh()
149 * keep track of feature fetching tasks.
157 * TODO: generalise to track all jalview events to orchestrate batch processing
161 private int queued = 0;
163 private int running = 0;
165 public FeatureFetcher()
170 public void addFetcher(final AlignFrame af,
171 final Vector<String> dasSources)
173 final long id = System.currentTimeMillis();
175 final FeatureFetcher us = this;
176 new Thread(new Runnable()
188 af.setProgressBar(MessageManager
189 .getString("status.das_features_being_retrived"), id);
190 af.featureSettings_actionPerformed(null);
191 af.setProgressBar(null, id);
200 public synchronized boolean allFinished()
202 return queued == 0 && running == 0;
207 public static Jalview getInstance()
213 * main class for Jalview application
216 * open <em>filename</em>
218 public static void main(String[] args)
220 // setLogging(); // BH - for event debugging in JavaScript
221 instance = new Jalview();
222 instance.doMain(args);
225 private static void logClass(String name)
227 // BH - for event debugging in JavaScript
228 ConsoleHandler consoleHandler = new ConsoleHandler();
229 consoleHandler.setLevel(Level.ALL);
230 Logger logger = Logger.getLogger(name);
231 logger.setLevel(Level.ALL);
232 logger.addHandler(consoleHandler);
235 @SuppressWarnings("unused")
236 private static void setLogging()
244 System.out.println("not in js");
247 // BH - for event debugging in JavaScript (Java mode only)
248 if (!Platform.isJS())
255 Logger.getLogger("").setLevel(Level.ALL);
256 logClass("java.awt.EventDispatchThread");
257 logClass("java.awt.EventQueue");
258 logClass("java.awt.Component");
259 logClass("java.awt.focus.Component");
260 logClass("java.awt.focus.DefaultKeyboardFocusManager");
268 void doMain(String[] args)
271 if (!Platform.isJS())
273 System.setSecurityManager(null);
277 .println("Java version: " + System.getProperty("java.version"));
278 System.out.println("Java Home: " + System.getProperty("java.home"));
279 System.out.println(System.getProperty("os.arch") + " "
280 + System.getProperty("os.name") + " "
281 + System.getProperty("os.version"));
282 String val = System.getProperty("sys.install4jVersion");
285 System.out.println("Install4j version: " + val);
287 val = System.getProperty("installer_template_version");
290 System.out.println("Install4j template version: " + val);
292 val = System.getProperty("launcher_version");
295 System.out.println("Launcher version: " + val);
298 // report Jalview version
299 Cache.loadBuildProperties(true);
301 ArgsParser aparser = new ArgsParser(args);
302 boolean headless = false;
304 String usrPropsFile = aparser.getValue("props");
305 Cache.loadProperties(usrPropsFile); // must do this before
306 if (usrPropsFile != null)
309 "CMD [-props " + usrPropsFile + "] executed successfully!");
312 if (!Platform.isJS())
319 if (aparser.contains("help") || aparser.contains("h"))
324 if (aparser.contains("nodisplay") || aparser.contains("nogui")
325 || aparser.contains("headless"))
327 System.setProperty("java.awt.headless", "true");
332 // allow https handshakes to download intermediate certs if necessary
333 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
335 final String jabawsUrl = aparser.getValue("jabaws");
336 if (jabawsUrl != null)
340 Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
342 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
343 } catch (MalformedURLException e)
346 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
351 String defs = aparser.getValue("setprop");
354 int p = defs.indexOf('=');
357 System.err.println("Ignoring invalid setprop argument : " + defs);
361 System.out.println("Executing setprop argument: " + defs);
364 Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
366 // DISABLED FOR SECURITY REASONS
367 // TODO: add a property to allow properties to be overriden by cli args
368 // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
370 defs = aparser.getValue("setprop");
372 if (System.getProperty("java.awt.headless") != null
373 && System.getProperty("java.awt.headless").equals("true"))
377 System.setProperty("http.agent",
378 "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
382 Console.initLogger();
383 } catch (NoClassDefFoundError error)
385 error.printStackTrace();
386 System.out.println("\nEssential logging libraries not found."
387 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
396 * configure 'full' SO model if preferences say to, else use the default (full SO)
397 * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
399 boolean soDefault = !Platform.isJS();
400 if (Cache.getDefault("USE_FULL_SO", soDefault))
402 SequenceOntologyFactory.setInstance(new SequenceOntology());
407 Desktop.nosplash = aparser.contains("nosplash");
408 desktop = new Desktop();
409 desktop.setInBatchMode(true); // indicate we are starting up
413 JalviewTaskbar.setTaskbar(this);
414 } catch (Exception e)
416 Console.info("Cannot set Taskbar");
417 Console.error(e.getMessage());
418 // e.printStackTrace();
419 } catch (Throwable t)
421 Console.info("Cannot set Taskbar");
422 Console.error(t.getMessage());
423 // t.printStackTrace();
426 // set Proxy settings before all the internet calls
427 Cache.setProxyPropertiesFromPreferences();
429 desktop.setVisible(true);
431 if (!Platform.isJS())
440 * Check to see that the JVM version being run is suitable for the Java
441 * version this Jalview was compiled for. Popup a warning if not.
443 if (!LaunchUtils.checkJavaVersion())
445 Console.warn("The Java version being used (Java "
446 + LaunchUtils.getJavaVersion()
447 + ") may lead to problems. This installation of Jalview should be used with Java "
448 + LaunchUtils.getJavaCompileVersion() + ".");
451 .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
454 MessageManager.getString("label.continue") };
455 JOptionPane.showOptionDialog(null,
456 MessageManager.formatMessage(
457 "warning.wrong_jvm_version_message",
458 LaunchUtils.getJavaVersion(),
459 LaunchUtils.getJavaCompileVersion()),
461 .getString("warning.wrong_jvm_version_title"),
462 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
463 null, options, options[0]);
467 if (!aparser.contains("nowebservicediscovery"))
469 desktop.startServiceDiscovery();
471 if (!aparser.contains("nousagestats"))
473 startUsageStats(desktop);
477 System.err.println("CMD [-nousagestats] executed successfully!");
480 if (!aparser.contains("noquestionnaire"))
482 String url = aparser.getValue("questionnaire");
485 // Start the desktop questionnaire prompter with the specified
487 Console.debug("Starting questionnaire url at " + url);
488 desktop.checkForQuestionnaire(url);
489 System.out.println("CMD questionnaire[-" + url
490 + "] executed successfully!");
494 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
496 // Start the desktop questionnaire prompter with the specified
499 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
501 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
503 "Starting questionnaire with default url: " + defurl);
504 desktop.checkForQuestionnaire(defurl);
511 .println("CMD [-noquestionnaire] executed successfully!");
514 if (!aparser.contains("nonews")
515 || Cache.getProperty("NONEWS") == null)
517 desktop.checkForNews();
520 if (!aparser.contains("nohtmltemplates")
521 || Cache.getProperty("NOHTMLTEMPLATES") == null)
523 BioJsHTMLOutput.updateBioJS();
528 // Check if JVM and compile version might cause problems and log if it
530 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
532 Console.warn("The Java version being used (Java "
533 + LaunchUtils.getJavaVersion()
534 + ") may lead to problems. This installation of Jalview should be used with Java "
535 + LaunchUtils.getJavaCompileVersion() + ".");
538 // Move any new getdown-launcher-new.jar into place over old
539 // getdown-launcher.jar
540 String appdirString = System.getProperty("getdownappdir");
541 if (appdirString != null && appdirString.length() > 0)
543 final File appdir = new File(appdirString);
549 LaunchUtil.upgradeGetdown(
550 new File(appdir, "getdown-launcher-old.jar"),
551 new File(appdir, "getdown-launcher.jar"),
552 new File(appdir, "getdown-launcher-new.jar"));
557 String file = null, data = null;
558 FileFormatI format = null;
559 DataSourceType protocol = null;
560 FileLoader fileLoader = new FileLoader(!headless);
562 String groovyscript = null; // script to execute after all loading is
563 // completed one way or another
564 // extract groovy argument and execute if necessary
565 groovyscript = aparser.getValue("groovy", true);
566 file = aparser.getValue("open", true);
568 if (file == null && desktop == null)
570 System.out.println("No files to open!");
574 // Finally, deal with the remaining input data.
579 desktop.setProgressBar(
581 .getString("status.processing_commandline_args"),
582 progress = System.currentTimeMillis());
584 System.out.println("CMD [-open " + file + "] executed successfully!");
586 if (!Platform.isJS())
588 * ignore in JavaScript -- can't just file existence - could load it?
593 if (!HttpUtils.startsWithHttpOrHttps(file))
595 if (!(new File(file)).exists())
597 System.out.println("Can't find " + file);
606 protocol = AppletFormatAdapter.checkProtocol(file);
610 format = new IdentifyFile().identify(file, protocol);
611 } catch (FileFormatException e1)
616 AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
620 System.out.println("error");
624 setCurrentAlignFrame(af);
625 data = aparser.getValue("colour", true);
628 data.replaceAll("%20", " ");
630 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
631 af.getViewport(), af.getViewport().getAlignment(), data);
636 "CMD [-color " + data + "] executed successfully!");
641 // Must maintain ability to use the groups flag
642 data = aparser.getValue("groups", true);
645 af.parseFeaturesFile(data,
646 AppletFormatAdapter.checkProtocol(data));
647 // System.out.println("Added " + data);
649 "CMD groups[-" + data + "] executed successfully!");
651 data = aparser.getValue("features", true);
654 af.parseFeaturesFile(data,
655 AppletFormatAdapter.checkProtocol(data));
656 // System.out.println("Added " + data);
658 "CMD [-features " + data + "] executed successfully!");
661 data = aparser.getValue("annotations", true);
664 af.loadJalviewDataFile(data, null, null, null);
665 // System.out.println("Added " + data);
667 "CMD [-annotations " + data + "] executed successfully!");
669 // set or clear the sortbytree flag.
670 if (aparser.contains("sortbytree"))
672 af.getViewport().setSortByTree(true);
673 if (af.getViewport().getSortByTree())
675 System.out.println("CMD [-sortbytree] executed successfully!");
678 if (aparser.contains("no-annotation"))
680 af.getViewport().setShowAnnotation(false);
681 if (!af.getViewport().isShowAnnotation())
683 System.out.println("CMD no-annotation executed successfully!");
686 if (aparser.contains("nosortbytree"))
688 af.getViewport().setSortByTree(false);
689 if (!af.getViewport().getSortByTree())
692 .println("CMD [-nosortbytree] executed successfully!");
695 data = aparser.getValue("tree", true);
701 "CMD [-tree " + data + "] executed successfully!");
702 NewickFile nf = new NewickFile(data,
703 AppletFormatAdapter.checkProtocol(data));
705 .setCurrentTree(af.showNewickTree(nf, data).getTree());
706 } catch (IOException ex)
708 System.err.println("Couldn't add tree " + data);
709 ex.printStackTrace(System.err);
712 // TODO - load PDB structure(s) to alignment JAL-629
713 // (associate with identical sequence in alignment, or a specified
715 if (groovyscript != null)
717 // Execute the groovy script after we've done all the rendering stuff
718 // and before any images or figures are generated.
719 System.out.println("Executing script " + groovyscript);
720 executeGroovyScript(groovyscript, af);
721 System.out.println("CMD groovy[" + groovyscript
722 + "] executed successfully!");
725 String imageName = "unnamed.png";
726 while (aparser.getSize() > 1)
728 String outputFormat = aparser.nextValue();
729 file = aparser.nextValue();
731 if (outputFormat.equalsIgnoreCase("png"))
733 af.createPNG(new File(file));
734 imageName = (new File(file)).getName();
735 System.out.println("Creating PNG image: " + file);
738 else if (outputFormat.equalsIgnoreCase("svg"))
740 File imageFile = new File(file);
741 imageName = imageFile.getName();
742 af.createSVG(imageFile);
743 System.out.println("Creating SVG image: " + file);
746 else if (outputFormat.equalsIgnoreCase("html"))
748 File imageFile = new File(file);
749 imageName = imageFile.getName();
750 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
751 htmlSVG.exportHTML(file);
753 System.out.println("Creating HTML image: " + file);
756 else if (outputFormat.equalsIgnoreCase("biojsmsa"))
760 System.err.println("The output html file must not be null");
765 BioJsHTMLOutput.refreshVersionInfo(
766 BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
767 } catch (URISyntaxException e)
771 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
772 bjs.exportHTML(file);
774 .println("Creating BioJS MSA Viwer HTML file: " + file);
777 else if (outputFormat.equalsIgnoreCase("imgMap"))
779 af.createImageMap(new File(file), imageName);
780 System.out.println("Creating image map: " + file);
783 else if (outputFormat.equalsIgnoreCase("eps"))
785 File outputFile = new File(file);
787 "Creating EPS file: " + outputFile.getAbsolutePath());
788 af.createEPS(outputFile);
791 FileFormatI outFormat = null;
794 outFormat = FileFormats.getInstance().forName(outputFormat);
795 } catch (Exception formatP)
797 System.out.println("Couldn't parse " + outFormat
798 + " as a valid Jalview format string.");
800 if (outFormat != null)
802 if (!outFormat.isWritable())
805 "This version of Jalview does not support alignment export as "
810 af.saveAlignment(file, outFormat);
811 if (af.isSaveAlignmentSuccessful())
813 System.out.println("Written alignment in "
814 + outFormat.getName() + " format to " + file);
818 System.out.println("Error writing file " + file + " in "
819 + outFormat.getName() + " format!!");
826 while (aparser.getSize() > 0)
828 System.out.println("Unknown arg: " + aparser.nextValue());
832 AlignFrame startUpAlframe = null;
833 // We'll only open the default file if the desktop is visible.
835 // ////////////////////
837 if (!Platform.isJS() && !headless && file == null
838 && Cache.getDefault("SHOW_STARTUP_FILE", true))
845 file = Cache.getDefault("STARTUP_FILE",
846 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
847 + "/examples/exampleFile_2_7.jvp");
848 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
850 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
852 file.replace("http:", "https:");
853 // hardwire upgrade of the startup file
854 file.replace("_2_3", "_2_7");
855 file.replace("2_7.jar", "2_7.jvp");
856 // and remove the stale setting
857 Cache.removeProperty("STARTUP_FILE");
860 protocol = AppletFormatAdapter.checkProtocol(file);
862 if (file.endsWith(".jar"))
864 format = FileFormat.Jalview;
870 format = new IdentifyFile().identify(file, protocol);
871 } catch (FileFormatException e)
877 startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
879 // extract groovy arguments before anything else.
882 // Once all other stuff is done, execute any groovy scripts (in order)
883 if (groovyscript != null)
885 if (Cache.groovyJarsPresent())
887 System.out.println("Executing script " + groovyscript);
888 executeGroovyScript(groovyscript, startUpAlframe);
893 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
897 // and finally, turn off batch mode indicator - if the desktop still exists
902 desktop.setProgressBar(null, progress);
904 desktop.setInBatchMode(false);
908 private static void setLookAndFeel()
910 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
912 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
914 String lafProp = System.getProperty("laf");
915 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
921 else if (lafSetting != null)
925 boolean lafSet = false;
928 case "crossplatform":
929 lafSet = setCrossPlatformLookAndFeel();
932 Console.error("Could not set requested laf=" + laf);
936 lafSet = setSystemLookAndFeel();
939 Console.error("Could not set requested laf=" + laf);
943 lafSet = setGtkLookAndFeel();
946 Console.error("Could not set requested laf=" + laf);
950 lafSet = setMetalLookAndFeel();
953 Console.error("Could not set requested laf=" + laf);
957 lafSet = setNimbusLookAndFeel();
960 Console.error("Could not set requested laf=" + laf);
964 lafSet = setFlatLookAndFeel();
967 Console.error("Could not set requested laf=" + laf);
971 lafSet = setQuaquaLookAndFeel();
974 Console.error("Could not set requested laf=" + laf);
978 lafSet = setVaquaLookAndFeel();
981 Console.error("Could not set requested laf=" + laf);
985 lafSet = setMacLookAndFeel();
988 Console.error("Could not set requested laf=" + laf);
994 Console.error("Requested laf=" + laf + " not implemented");
998 setSystemLookAndFeel();
999 if (Platform.isLinux())
1001 setMetalLookAndFeel();
1003 if (Platform.isMac())
1005 setMacLookAndFeel();
1010 private static boolean setCrossPlatformLookAndFeel()
1012 boolean set = false;
1015 UIManager.setLookAndFeel(
1016 UIManager.getCrossPlatformLookAndFeelClassName());
1018 } catch (Exception ex)
1020 Console.error("Unexpected Look and Feel Exception");
1021 Console.error(ex.getMessage());
1022 Console.debug(Cache.getStackTraceString(ex));
1027 private static boolean setSystemLookAndFeel()
1029 boolean set = false;
1032 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1034 } catch (Exception ex)
1036 Console.error("Unexpected Look and Feel Exception");
1037 Console.error(ex.getMessage());
1038 Console.debug(Cache.getStackTraceString(ex));
1043 private static boolean setSpecificLookAndFeel(String name,
1044 String className, boolean nameStartsWith)
1046 boolean set = false;
1049 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1051 if (info.getName() != null && nameStartsWith
1052 ? info.getName().toLowerCase(Locale.ROOT)
1053 .startsWith(name.toLowerCase(Locale.ROOT))
1054 : info.getName().toLowerCase(Locale.ROOT)
1055 .equals(name.toLowerCase(Locale.ROOT)))
1057 className = info.getClassName();
1061 UIManager.setLookAndFeel(className);
1063 } catch (Exception ex)
1065 Console.error("Unexpected Look and Feel Exception");
1066 Console.error(ex.getMessage());
1067 Console.debug(Cache.getStackTraceString(ex));
1072 private static boolean setGtkLookAndFeel()
1074 return setSpecificLookAndFeel("gtk",
1075 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1078 private static boolean setMetalLookAndFeel()
1080 return setSpecificLookAndFeel("metal",
1081 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1084 private static boolean setNimbusLookAndFeel()
1086 return setSpecificLookAndFeel("nimbus",
1087 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1090 private static boolean setFlatLookAndFeel()
1092 boolean set = setSpecificLookAndFeel("flatlaf light",
1093 "com.formdev.flatlaf.FlatLightLaf", false);
1096 if (Platform.isMac())
1098 System.setProperty("apple.laf.useScreenMenuBar", "true");
1099 System.setProperty("apple.awt.application.name",
1100 ChannelProperties.getProperty("app_name"));
1101 System.setProperty("apple.awt.application.appearance", "system");
1102 if (SystemInfo.isMacFullWindowContentSupported
1103 && Desktop.desktop != null)
1105 Desktop.desktop.getRootPane()
1106 .putClientProperty("apple.awt.fullWindowContent", true);
1107 Desktop.desktop.getRootPane()
1108 .putClientProperty("apple.awt.transparentTitleBar", true);
1111 SwingUtilities.invokeLater(() -> {
1112 FlatLightLaf.setup();
1116 UIManager.put("TabbedPane.showTabSeparators", true);
1117 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1118 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1119 // UIManager.put("TabbedPane.hasFullBorder", true);
1120 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1121 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1122 UIManager.put("TabbedPane.smoothScrolling", true);
1123 UIManager.put("TabbedPane.tabWidthMode", "compact");
1124 UIManager.put("TabbedPane.selectedBackground", Color.white);
1129 private static boolean setQuaquaLookAndFeel()
1131 return setSpecificLookAndFeel("quaqua",
1132 ch.randelshofer.quaqua.QuaquaManager.getLookAndFeel().getClass()
1137 private static boolean setVaquaLookAndFeel()
1139 return setSpecificLookAndFeel("vaqua",
1140 "org.violetlib.aqua.AquaLookAndFeel", false);
1143 private static boolean setMacLookAndFeel()
1145 boolean set = false;
1146 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1147 ChannelProperties.getProperty("app_name"));
1148 System.setProperty("apple.laf.useScreenMenuBar", "true");
1150 * broken native LAFs on (ARM?) macbooks
1151 set = setQuaquaLookAndFeel();
1152 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1153 .toLowerCase(Locale.ROOT).contains("quaqua"))
1155 set = setVaquaLookAndFeel();
1158 set = setFlatLookAndFeel();
1162 private static void showUsage()
1165 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1166 + "-nodisplay\tRun Jalview without User Interface.\n"
1167 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1168 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1169 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1170 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1171 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1172 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1173 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1174 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1175 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1176 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1177 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1178 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1179 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1180 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1181 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1182 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1183 + "-html FILE\tCreate HTML file from alignment.\n"
1184 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1185 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1186 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1187 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1188 + "-noquestionnaire\tTurn off questionnaire check.\n"
1189 + "-nonews\tTurn off check for Jalview news.\n"
1190 + "-nousagestats\tTurn off analytics tracking for this session.\n"
1191 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1193 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1194 // after all other properties files have been read\n\t
1195 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1196 // passed in correctly)"
1197 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1198 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1199 + "-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"
1200 + "-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"
1201 + "-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"
1202 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1205 private static void startUsageStats(final Desktop desktop)
1208 * start a User Config prompt asking if we can log usage statistics.
1210 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
1211 "USAGESTATS", "Jalview Usage Statistics",
1212 "Do you want to help make Jalview better by enabling "
1213 + "the collection of usage statistics with Plausible analytics?"
1214 + "\n\n(you can enable or disable usage tracking in the preferences)",
1220 Console.debug("Initialising analytics for usage stats.");
1221 Cache.initAnalytics();
1222 Console.debug("Tracking enabled.");
1229 Console.debug("Not enabling analytics.");
1232 desktop.addDialogThread(prompter);
1236 * Locate the given string as a file and pass it to the groovy interpreter.
1238 * @param groovyscript
1239 * the script to execute
1240 * @param jalviewContext
1241 * the Jalview Desktop object passed in to the groovy binding as the
1244 private void executeGroovyScript(String groovyscript, AlignFrame af)
1247 * for scripts contained in files
1254 if (groovyscript.trim().equals("STDIN"))
1256 // read from stdin into a tempfile and execute it
1259 tfile = File.createTempFile("jalview", "groovy");
1260 PrintWriter outfile = new PrintWriter(
1261 new OutputStreamWriter(new FileOutputStream(tfile)));
1262 BufferedReader br = new BufferedReader(
1263 new InputStreamReader(System.in));
1265 while ((line = br.readLine()) != null)
1267 outfile.write(line + "\n");
1273 } catch (Exception ex)
1275 System.err.println("Failed to read from STDIN into tempfile "
1276 + ((tfile == null) ? "(tempfile wasn't created)"
1277 : tfile.toString()));
1278 ex.printStackTrace();
1283 sfile = tfile.toURI().toURL();
1284 } catch (Exception x)
1287 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1289 x.printStackTrace();
1297 sfile = new URI(groovyscript).toURL();
1298 } catch (Exception x)
1300 tfile = new File(groovyscript);
1301 if (!tfile.exists())
1303 System.err.println("File '" + groovyscript + "' does not exist.");
1306 if (!tfile.canRead())
1308 System.err.println("File '" + groovyscript + "' cannot be read.");
1311 if (tfile.length() < 1)
1313 System.err.println("File '" + groovyscript + "' is empty.");
1318 sfile = tfile.getAbsoluteFile().toURI().toURL();
1319 } catch (Exception ex)
1321 System.err.println("Failed to create a file URL for "
1322 + tfile.getAbsoluteFile());
1329 Map<String, java.lang.Object> vbinding = new HashMap<>();
1330 vbinding.put("Jalview", this);
1333 vbinding.put("currentAlFrame", af);
1335 Binding gbinding = new Binding(vbinding);
1336 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1337 gse.run(sfile.toString(), gbinding);
1338 if ("STDIN".equals(groovyscript))
1340 // delete temp file that we made -
1341 // only if it was successfully executed
1344 } catch (Exception e)
1346 System.err.println("Exception Whilst trying to execute file " + sfile
1347 + " as a groovy script.");
1348 e.printStackTrace(System.err);
1353 public static boolean isHeadlessMode()
1355 String isheadless = System.getProperty("java.awt.headless");
1356 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1363 public AlignFrame[] getAlignFrames()
1365 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1366 : Desktop.getAlignFrames();
1371 * Quit method delegates to Desktop.quit - unless running in headless mode
1372 * when it just ends the JVM
1376 if (desktop != null)
1386 public static AlignFrame getCurrentAlignFrame()
1388 return Jalview.currentAlignFrame;
1391 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1393 Jalview.currentAlignFrame = currentAlignFrame;