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.ext.so.SequenceOntology;
62 import jalview.gui.AlignFrame;
63 import jalview.gui.Desktop;
64 import jalview.gui.PromptUserConfig;
65 import jalview.gui.QuitHandler;
66 import jalview.gui.QuitHandler.QResponse;
67 import jalview.io.AppletFormatAdapter;
68 import jalview.io.BioJsHTMLOutput;
69 import jalview.io.DataSourceType;
70 import jalview.io.FileFormat;
71 import jalview.io.FileFormatException;
72 import jalview.io.FileFormatI;
73 import jalview.io.FileFormats;
74 import jalview.io.FileLoader;
75 import jalview.io.HtmlSvgOutput;
76 import jalview.io.IdentifyFile;
77 import jalview.io.NewickFile;
78 import jalview.io.gff.SequenceOntologyFactory;
79 import jalview.schemes.ColourSchemeI;
80 import jalview.schemes.ColourSchemeProperty;
81 import jalview.util.ChannelProperties;
82 import jalview.util.HttpUtils;
83 import jalview.util.LaunchUtils;
84 import jalview.util.MessageManager;
85 import jalview.util.Platform;
86 import jalview.ws.jws2.Jws2Discoverer;
89 * Main class for Jalview Application <br>
91 * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
94 * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
95 * jalview.bin.Jalview jalview.bin.Jalview
97 * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
98 * embellish '*' to e.g. '*.jar')
101 * @version $Revision$
107 Platform.getURLCommandArguments();
108 Platform.addJ2SDirectDatabaseCall("https://www.jalview.org");
109 Platform.addJ2SDirectDatabaseCall("http://www.jalview.org");
110 Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk");
111 Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk");
115 * singleton instance of this class
117 private static Jalview instance;
119 private Desktop desktop;
121 public static AlignFrame currentAlignFrame;
125 if (!Platform.isJS())
132 // grab all the rights we can for the JVM
133 Policy.setPolicy(new Policy()
136 public PermissionCollection getPermissions(CodeSource codesource)
138 Permissions perms = new Permissions();
139 perms.add(new AllPermission());
144 public void refresh()
152 * keep track of feature fetching tasks.
160 * TODO: generalise to track all jalview events to orchestrate batch processing
164 private int queued = 0;
166 private int running = 0;
168 public FeatureFetcher()
173 public void addFetcher(final AlignFrame af,
174 final Vector<String> dasSources)
176 final long id = System.currentTimeMillis();
178 final FeatureFetcher us = this;
179 new Thread(new Runnable()
191 af.setProgressBar(MessageManager
192 .getString("status.das_features_being_retrived"), id);
193 af.featureSettings_actionPerformed(null);
194 af.setProgressBar(null, id);
203 public synchronized boolean allFinished()
205 return queued == 0 && running == 0;
210 public static Jalview getInstance()
216 * main class for Jalview application
219 * open <em>filename</em>
221 public static void main(String[] args)
223 // setLogging(); // BH - for event debugging in JavaScript
224 instance = new Jalview();
225 instance.doMain(args);
228 private static void logClass(String name)
230 // BH - for event debugging in JavaScript
231 ConsoleHandler consoleHandler = new ConsoleHandler();
232 consoleHandler.setLevel(Level.ALL);
233 Logger logger = Logger.getLogger(name);
234 logger.setLevel(Level.ALL);
235 logger.addHandler(consoleHandler);
238 @SuppressWarnings("unused")
239 private static void setLogging()
247 System.out.println("not in js");
250 // BH - for event debugging in JavaScript (Java mode only)
251 if (!Platform.isJS())
258 Logger.getLogger("").setLevel(Level.ALL);
259 logClass("java.awt.EventDispatchThread");
260 logClass("java.awt.EventQueue");
261 logClass("java.awt.Component");
262 logClass("java.awt.focus.Component");
263 logClass("java.awt.focus.DefaultKeyboardFocusManager");
271 void doMain(String[] args)
274 if (!Platform.isJS())
276 System.setSecurityManager(null);
278 Runtime.getRuntime().addShutdownHook(new Thread()
282 Console.debug("Running shutdown hook");
283 if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT)
285 // Got to here by a SIGTERM signal.
286 // Note we will not actually cancel the quit from here -- it's too
287 // late -- but we can wait for saving files.
288 Console.debug("Checking for saving files");
289 QuitHandler.getQuitResponse(false);
293 Console.debug("Nothing more to do");
295 Console.debug("Exiting, bye!");
296 // shutdownHook cannot be cancelled, JVM will now halt
302 .println("Java version: " + System.getProperty("java.version"));
303 System.out.println("Java Home: " + System.getProperty("java.home"));
304 System.out.println(System.getProperty("os.arch") + " "
305 + System.getProperty("os.name") + " "
306 + System.getProperty("os.version"));
308 String val = System.getProperty("sys.install4jVersion");
311 System.out.println("Install4j version: " + val);
313 val = System.getProperty("installer_template_version");
316 System.out.println("Install4j template version: " + val);
318 val = System.getProperty("launcher_version");
321 System.out.println("Launcher version: " + val);
324 // report Jalview version
325 Cache.loadBuildProperties(true);
327 ArgsParser aparser = new ArgsParser(args);
329 boolean headless = false;
331 String usrPropsFile = aparser.getValue("props");
332 Cache.loadProperties(usrPropsFile); // must do this
334 if (usrPropsFile != null)
337 "CMD [-props " + usrPropsFile + "] executed successfully!");
340 if (!Platform.isJS())
347 if (aparser.contains("help") || aparser.contains("h"))
352 if (aparser.contains("nodisplay") || aparser.contains("nogui")
353 || aparser.contains("headless"))
355 System.setProperty("java.awt.headless", "true");
360 // allow https handshakes to download intermediate certs if necessary
361 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
363 final String jabawsUrl = aparser.getValue("jabaws");
364 if (jabawsUrl != null)
368 Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
370 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
371 } catch (MalformedURLException e)
374 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
379 String defs = aparser.getValue("setprop");
382 int p = defs.indexOf('=');
385 System.err.println("Ignoring invalid setprop argument : " + defs);
389 System.out.println("Executing setprop argument: " + defs);
392 Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
394 // DISABLED FOR SECURITY REASONS
395 // TODO: add a property to allow properties to be overriden by cli args
396 // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
398 defs = aparser.getValue("setprop");
400 if (System.getProperty("java.awt.headless") != null
401 && System.getProperty("java.awt.headless").equals("true"))
405 System.setProperty("http.agent",
406 "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
410 Console.initLogger();
413 NoClassDefFoundError error)
415 error.printStackTrace();
416 System.out.println("\nEssential logging libraries not found."
417 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
426 * configure 'full' SO model if preferences say to, else use the default (full SO)
427 * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
429 boolean soDefault = !Platform.isJS();
430 if (Cache.getDefault("USE_FULL_SO", soDefault))
432 SequenceOntologyFactory.setInstance(new SequenceOntology());
437 Desktop.nosplash = aparser.contains("nosplash");
438 desktop = new Desktop();
439 desktop.setInBatchMode(true); // indicate we are starting up
443 JalviewTaskbar.setTaskbar(this);
444 } catch (Exception e)
446 Console.info("Cannot set Taskbar");
447 Console.error(e.getMessage());
448 // e.printStackTrace();
449 } catch (Throwable t)
451 Console.info("Cannot set Taskbar");
452 Console.error(t.getMessage());
453 // t.printStackTrace();
456 // set Proxy settings before all the internet calls
457 Cache.setProxyPropertiesFromPreferences();
459 desktop.setVisible(true);
461 if (!Platform.isJS())
470 * Check to see that the JVM version being run is suitable for the Java
471 * version this Jalview was compiled for. Popup a warning if not.
473 if (!LaunchUtils.checkJavaVersion())
475 Console.warn("The Java version being used (Java "
476 + LaunchUtils.getJavaVersion()
477 + ") may lead to problems. This installation of Jalview should be used with Java "
478 + LaunchUtils.getJavaCompileVersion() + ".");
481 .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
484 MessageManager.getString("label.continue") };
485 JOptionPane.showOptionDialog(null,
486 MessageManager.formatMessage(
487 "warning.wrong_jvm_version_message",
488 LaunchUtils.getJavaVersion(),
489 LaunchUtils.getJavaCompileVersion()),
491 .getString("warning.wrong_jvm_version_title"),
492 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
493 null, options, options[0]);
497 if (!aparser.contains("nowebservicediscovery"))
499 desktop.startServiceDiscovery();
501 if (!aparser.contains("nousagestats"))
503 startUsageStats(desktop);
507 System.err.println("CMD [-nousagestats] executed successfully!");
510 if (!aparser.contains("noquestionnaire"))
512 String url = aparser.getValue("questionnaire");
515 // Start the desktop questionnaire prompter with the specified
517 Console.debug("Starting questionnaire url at " + url);
518 desktop.checkForQuestionnaire(url);
519 System.out.println("CMD questionnaire[-" + url
520 + "] executed successfully!");
524 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
526 // Start the desktop questionnaire prompter with the specified
529 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
531 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
533 "Starting questionnaire with default url: " + defurl);
534 desktop.checkForQuestionnaire(defurl);
541 .println("CMD [-noquestionnaire] executed successfully!");
544 if (!aparser.contains("nonews")
545 || Cache.getProperty("NONEWS") == null)
547 desktop.checkForNews();
550 if (!aparser.contains("nohtmltemplates")
551 || Cache.getProperty("NOHTMLTEMPLATES") == null)
553 BioJsHTMLOutput.updateBioJS();
558 // Check if JVM and compile version might cause problems and log if it
560 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
562 Console.warn("The Java version being used (Java "
563 + LaunchUtils.getJavaVersion()
564 + ") may lead to problems. This installation of Jalview should be used with Java "
565 + LaunchUtils.getJavaCompileVersion() + ".");
568 // Move any new getdown-launcher-new.jar into place over old
569 // getdown-launcher.jar
570 String appdirString = System.getProperty("getdownappdir");
571 if (appdirString != null && appdirString.length() > 0)
573 final File appdir = new File(appdirString);
579 LaunchUtil.upgradeGetdown(
580 new File(appdir, "getdown-launcher-old.jar"),
581 new File(appdir, "getdown-launcher.jar"),
582 new File(appdir, "getdown-launcher-new.jar"));
587 String file = null, data = null;
589 FileFormatI format = null;
591 DataSourceType protocol = null;
593 FileLoader fileLoader = new FileLoader(!headless);
595 String groovyscript = null; // script to execute after all loading is
596 // completed one way or another
597 // extract groovy argument and execute if necessary
598 groovyscript = aparser.getValue("groovy", true);
599 file = aparser.getValue("open", true);
601 if (file == null && desktop == null)
603 System.out.println("No files to open!");
608 // Finally, deal with the remaining input data.
613 desktop.setProgressBar(
615 .getString("status.processing_commandline_args"),
616 progress = System.currentTimeMillis());
618 System.out.println("CMD [-open " + file + "] executed successfully!");
620 if (!Platform.isJS())
622 * ignore in JavaScript -- can't just file existence - could load it?
627 if (!HttpUtils.startsWithHttpOrHttps(file))
629 if (!(new File(file)).exists())
631 System.out.println("Can't find " + file);
640 protocol = AppletFormatAdapter.checkProtocol(file);
644 format = new IdentifyFile().identify(file, protocol);
645 } catch (FileFormatException e1)
650 AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
654 System.out.println("error");
658 setCurrentAlignFrame(af);
659 data = aparser.getValue("colour", true);
662 data.replaceAll("%20", " ");
664 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
665 af.getViewport(), af.getViewport().getAlignment(), data);
670 "CMD [-color " + data + "] executed successfully!");
675 // Must maintain ability to use the groups flag
676 data = aparser.getValue("groups", true);
679 af.parseFeaturesFile(data,
680 AppletFormatAdapter.checkProtocol(data));
681 // System.out.println("Added " + data);
683 "CMD groups[-" + data + "] executed successfully!");
685 data = aparser.getValue("features", true);
688 af.parseFeaturesFile(data,
689 AppletFormatAdapter.checkProtocol(data));
690 // System.out.println("Added " + data);
692 "CMD [-features " + data + "] executed successfully!");
695 data = aparser.getValue("annotations", true);
698 af.loadJalviewDataFile(data, null, null, null);
699 // System.out.println("Added " + data);
701 "CMD [-annotations " + data + "] executed successfully!");
703 // set or clear the sortbytree flag.
704 if (aparser.contains("sortbytree"))
706 af.getViewport().setSortByTree(true);
707 if (af.getViewport().getSortByTree())
709 System.out.println("CMD [-sortbytree] executed successfully!");
712 if (aparser.contains("no-annotation"))
714 af.getViewport().setShowAnnotation(false);
715 if (!af.getViewport().isShowAnnotation())
717 System.out.println("CMD no-annotation executed successfully!");
720 if (aparser.contains("nosortbytree"))
722 af.getViewport().setSortByTree(false);
723 if (!af.getViewport().getSortByTree())
726 .println("CMD [-nosortbytree] executed successfully!");
729 data = aparser.getValue("tree", true);
735 "CMD [-tree " + data + "] executed successfully!");
736 NewickFile nf = new NewickFile(data,
737 AppletFormatAdapter.checkProtocol(data));
739 .setCurrentTree(af.showNewickTree(nf, data).getTree());
740 } catch (IOException ex)
742 System.err.println("Couldn't add tree " + data);
743 ex.printStackTrace(System.err);
746 // TODO - load PDB structure(s) to alignment JAL-629
747 // (associate with identical sequence in alignment, or a specified
749 if (groovyscript != null)
751 // Execute the groovy script after we've done all the rendering stuff
752 // and before any images or figures are generated.
753 System.out.println("Executing script " + groovyscript);
754 executeGroovyScript(groovyscript, af);
755 System.out.println("CMD groovy[" + groovyscript
756 + "] executed successfully!");
759 String imageName = "unnamed.png";
760 while (aparser.getSize() > 1)
762 String outputFormat = aparser.nextValue();
763 file = aparser.nextValue();
765 if (outputFormat.equalsIgnoreCase("png"))
767 af.createPNG(new File(file));
768 imageName = (new File(file)).getName();
769 System.out.println("Creating PNG image: " + file);
772 else if (outputFormat.equalsIgnoreCase("svg"))
774 File imageFile = new File(file);
775 imageName = imageFile.getName();
776 af.createSVG(imageFile);
777 System.out.println("Creating SVG image: " + file);
780 else if (outputFormat.equalsIgnoreCase("html"))
782 File imageFile = new File(file);
783 imageName = imageFile.getName();
784 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
785 htmlSVG.exportHTML(file);
787 System.out.println("Creating HTML image: " + file);
790 else if (outputFormat.equalsIgnoreCase("biojsmsa"))
794 System.err.println("The output html file must not be null");
799 BioJsHTMLOutput.refreshVersionInfo(
800 BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
801 } catch (URISyntaxException e)
805 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
806 bjs.exportHTML(file);
808 .println("Creating BioJS MSA Viwer HTML file: " + file);
811 else if (outputFormat.equalsIgnoreCase("imgMap"))
813 af.createImageMap(new File(file), imageName);
814 System.out.println("Creating image map: " + file);
817 else if (outputFormat.equalsIgnoreCase("eps"))
819 File outputFile = new File(file);
821 "Creating EPS file: " + outputFile.getAbsolutePath());
822 af.createEPS(outputFile);
825 FileFormatI outFormat = null;
828 outFormat = FileFormats.getInstance().forName(outputFormat);
829 } catch (Exception formatP)
831 System.out.println("Couldn't parse " + outFormat
832 + " as a valid Jalview format string.");
834 if (outFormat != null)
836 if (!outFormat.isWritable())
839 "This version of Jalview does not support alignment export as "
844 af.saveAlignment(file, outFormat);
845 if (af.isSaveAlignmentSuccessful())
847 System.out.println("Written alignment in "
848 + outFormat.getName() + " format to " + file);
852 System.out.println("Error writing file " + file + " in "
853 + outFormat.getName() + " format!!");
860 while (aparser.getSize() > 0)
862 System.out.println("Unknown arg: " + aparser.nextValue());
867 AlignFrame startUpAlframe = null;
868 // We'll only open the default file if the desktop is visible.
870 // ////////////////////
872 if (!Platform.isJS() && !headless && file == null
873 && Cache.getDefault("SHOW_STARTUP_FILE", true))
880 boolean defaultStartupFile = Cache.getDefault("STARTUP_FILE",
882 file = Cache.getDefault("STARTUP_FILE",
883 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
884 + "/examples/exampleFile_2_7.jvp");
885 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
887 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
889 file.replace("http:", "https:");
890 // hardwire upgrade of the startup file
891 file.replace("_2_3", "_2_7");
892 file.replace("2_7.jar", "2_7.jvp");
893 // and remove the stale setting
894 Cache.removeProperty("STARTUP_FILE");
895 defaultStartupFile = true;
898 protocol = AppletFormatAdapter.checkProtocol(file);
900 if (file.endsWith(".jar"))
902 format = FileFormat.Jalview;
908 format = new IdentifyFile().identify(file, protocol);
909 } catch (FileFormatException e)
915 startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
917 if (defaultStartupFile)
919 Console.debug("Resetting up-to-date flag for startup file");
920 startUpAlframe.getViewport().setSavedUpToDate(true);
922 // extract groovy arguments before anything else.
925 // Once all other stuff is done, execute any groovy scripts (in order)
926 if (groovyscript != null)
928 if (Cache.groovyJarsPresent())
930 System.out.println("Executing script " + groovyscript);
931 executeGroovyScript(groovyscript, startUpAlframe);
936 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
940 // and finally, turn off batch mode indicator - if the desktop still exists
945 desktop.setProgressBar(null, progress);
947 desktop.setInBatchMode(false);
951 private static void setLookAndFeel()
953 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
955 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
957 String lafProp = System.getProperty("laf");
958 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
964 else if (lafSetting != null)
968 boolean lafSet = false;
971 case "crossplatform":
972 lafSet = setCrossPlatformLookAndFeel();
975 Console.error("Could not set requested laf=" + laf);
979 lafSet = setSystemLookAndFeel();
982 Console.error("Could not set requested laf=" + laf);
986 lafSet = setGtkLookAndFeel();
989 Console.error("Could not set requested laf=" + laf);
993 lafSet = setMetalLookAndFeel();
996 Console.error("Could not set requested laf=" + laf);
1000 lafSet = setNimbusLookAndFeel();
1003 Console.error("Could not set requested laf=" + laf);
1007 lafSet = setFlatLookAndFeel();
1010 Console.error("Could not set requested laf=" + laf);
1014 lafSet = setQuaquaLookAndFeel();
1017 Console.error("Could not set requested laf=" + laf);
1021 lafSet = setVaquaLookAndFeel();
1024 Console.error("Could not set requested laf=" + laf);
1028 lafSet = setMacLookAndFeel();
1031 Console.error("Could not set requested laf=" + laf);
1037 Console.error("Requested laf=" + laf + " not implemented");
1041 setSystemLookAndFeel();
1042 if (Platform.isLinux())
1044 setLinuxLookAndFeel();
1046 if (Platform.isMac())
1048 setMacLookAndFeel();
1053 private static boolean setCrossPlatformLookAndFeel()
1055 boolean set = false;
1058 UIManager.setLookAndFeel(
1059 UIManager.getCrossPlatformLookAndFeelClassName());
1061 } catch (Exception ex)
1063 Console.error("Unexpected Look and Feel Exception");
1064 Console.error(ex.getMessage());
1065 Console.debug(Cache.getStackTraceString(ex));
1070 private static boolean setSystemLookAndFeel()
1072 boolean set = false;
1075 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1077 } catch (Exception ex)
1079 Console.error("Unexpected Look and Feel Exception");
1080 Console.error(ex.getMessage());
1081 Console.debug(Cache.getStackTraceString(ex));
1086 private static boolean setSpecificLookAndFeel(String name,
1087 String className, boolean nameStartsWith)
1089 boolean set = false;
1092 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1094 if (info.getName() != null && nameStartsWith
1095 ? info.getName().toLowerCase(Locale.ROOT)
1096 .startsWith(name.toLowerCase(Locale.ROOT))
1097 : info.getName().toLowerCase(Locale.ROOT)
1098 .equals(name.toLowerCase(Locale.ROOT)))
1100 className = info.getClassName();
1104 UIManager.setLookAndFeel(className);
1106 } catch (Exception ex)
1108 Console.error("Unexpected Look and Feel Exception");
1109 Console.error(ex.getMessage());
1110 Console.debug(Cache.getStackTraceString(ex));
1115 private static boolean setGtkLookAndFeel()
1117 return setSpecificLookAndFeel("gtk",
1118 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1121 private static boolean setMetalLookAndFeel()
1123 return setSpecificLookAndFeel("metal",
1124 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1127 private static boolean setNimbusLookAndFeel()
1129 return setSpecificLookAndFeel("nimbus",
1130 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1133 private static boolean setFlatLookAndFeel()
1135 boolean set = false;
1136 if (Platform.isMac())
1140 UIManager.setLookAndFeel(
1141 "com.formdev.flatlaf.themes.FlatMacLightLaf");
1143 Console.debug("*** Loaded FlatMacLightLaf");
1144 } catch (ClassNotFoundException | InstantiationException
1145 | IllegalAccessException | UnsupportedLookAndFeelException e)
1147 Console.debug("Exception loading FlatMacLightLaf", e);
1154 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1156 Console.debug("*** Loaded FlatLightLaf");
1157 } catch (ClassNotFoundException | InstantiationException
1158 | IllegalAccessException | UnsupportedLookAndFeelException e)
1160 Console.debug("Exception loading FlatLightLaf", e);
1165 if (Platform.isMac())
1167 System.setProperty("apple.laf.useScreenMenuBar", "true");
1168 System.setProperty("apple.awt.application.name",
1169 ChannelProperties.getProperty("app_name"));
1170 System.setProperty("apple.awt.application.appearance", "system");
1171 if (SystemInfo.isMacFullWindowContentSupported
1172 && Desktop.desktop != null)
1174 Console.debug("Setting transparent title bar");
1175 Desktop.desktop.getRootPane()
1176 .putClientProperty("apple.awt.fullWindowContent", true);
1177 Desktop.desktop.getRootPane()
1178 .putClientProperty("apple.awt.transparentTitleBar", true);
1181 SwingUtilities.invokeLater(() -> {
1182 FlatLightLaf.setup();
1186 UIManager.put("TabbedPane.showTabSeparators", true);
1187 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1188 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1189 // UIManager.put("TabbedPane.hasFullBorder", true);
1190 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1191 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1192 UIManager.put("TabbedPane.smoothScrolling", true);
1193 UIManager.put("TabbedPane.tabWidthMode", "compact");
1194 UIManager.put("TabbedPane.selectedBackground", Color.white);
1197 Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
1201 private static boolean setQuaquaLookAndFeel()
1203 return setSpecificLookAndFeel("quaqua",
1204 ch.randelshofer.quaqua.QuaquaManager.getLookAndFeel().getClass()
1209 private static boolean setVaquaLookAndFeel()
1211 return setSpecificLookAndFeel("vaqua",
1212 "org.violetlib.aqua.AquaLookAndFeel", false);
1215 private static boolean setMacLookAndFeel()
1217 boolean set = false;
1218 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1219 ChannelProperties.getProperty("app_name"));
1220 System.setProperty("apple.laf.useScreenMenuBar", "true");
1222 * broken native LAFs on (ARM?) macbooks
1223 set = setQuaquaLookAndFeel();
1224 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1225 .toLowerCase(Locale.ROOT).contains("quaqua"))
1227 set = setVaquaLookAndFeel();
1230 set = setFlatLookAndFeel();
1234 private static boolean setLinuxLookAndFeel()
1236 boolean set = false;
1237 set = setFlatLookAndFeel();
1239 set = setMetalLookAndFeel();
1240 // avoid GtkLookAndFeel -- not good results especially on HiDPI
1242 set = setNimbusLookAndFeel();
1246 private static void showUsage()
1249 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1250 + "-nodisplay\tRun Jalview without User Interface.\n"
1251 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1252 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1253 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1254 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1255 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1256 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1257 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1258 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1259 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1260 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1261 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1262 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1263 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1264 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1265 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1266 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1267 + "-html FILE\tCreate HTML file from alignment.\n"
1268 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1269 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1270 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1271 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1272 + "-noquestionnaire\tTurn off questionnaire check.\n"
1273 + "-nonews\tTurn off check for Jalview news.\n"
1274 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1275 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1277 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1278 // after all other properties files have been read\n\t
1279 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1280 // passed in correctly)"
1281 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1282 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1283 + "-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"
1284 + "-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"
1285 + "-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"
1286 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1289 private static void startUsageStats(final Desktop desktop)
1292 * start a User Config prompt asking if we can log usage statistics.
1294 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
1295 "USAGESTATS", "Jalview Usage Statistics",
1296 "Do you want to help make Jalview better by enabling "
1297 + "the collection of usage statistics with Google Analytics ?"
1298 + "\n\n(you can enable or disable usage tracking in the preferences)",
1305 "Initialising googletracker for usage stats.");
1306 Cache.initGoogleTracker();
1307 Console.debug("Tracking enabled.");
1314 Console.debug("Not enabling Google Tracking.");
1317 desktop.addDialogThread(prompter);
1321 * Locate the given string as a file and pass it to the groovy interpreter.
1323 * @param groovyscript
1324 * the script to execute
1325 * @param jalviewContext
1326 * the Jalview Desktop object passed in to the groovy binding as the
1329 private void executeGroovyScript(String groovyscript, AlignFrame af)
1332 * for scripts contained in files
1339 if (groovyscript.trim().equals("STDIN"))
1341 // read from stdin into a tempfile and execute it
1344 tfile = File.createTempFile("jalview", "groovy");
1345 PrintWriter outfile = new PrintWriter(
1346 new OutputStreamWriter(new FileOutputStream(tfile)));
1347 BufferedReader br = new BufferedReader(
1348 new InputStreamReader(System.in));
1350 while ((line = br.readLine()) != null)
1352 outfile.write(line + "\n");
1358 } catch (Exception ex)
1360 System.err.println("Failed to read from STDIN into tempfile "
1361 + ((tfile == null) ? "(tempfile wasn't created)"
1362 : tfile.toString()));
1363 ex.printStackTrace();
1368 sfile = tfile.toURI().toURL();
1369 } catch (Exception x)
1372 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1374 x.printStackTrace();
1382 sfile = new URI(groovyscript).toURL();
1383 } catch (Exception x)
1385 tfile = new File(groovyscript);
1386 if (!tfile.exists())
1388 System.err.println("File '" + groovyscript + "' does not exist.");
1391 if (!tfile.canRead())
1393 System.err.println("File '" + groovyscript + "' cannot be read.");
1396 if (tfile.length() < 1)
1398 System.err.println("File '" + groovyscript + "' is empty.");
1403 sfile = tfile.getAbsoluteFile().toURI().toURL();
1404 } catch (Exception ex)
1406 System.err.println("Failed to create a file URL for "
1407 + tfile.getAbsoluteFile());
1414 Map<String, java.lang.Object> vbinding = new HashMap<>();
1415 vbinding.put("Jalview", this);
1418 vbinding.put("currentAlFrame", af);
1420 Binding gbinding = new Binding(vbinding);
1421 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1422 gse.run(sfile.toString(), gbinding);
1423 if ("STDIN".equals(groovyscript))
1425 // delete temp file that we made -
1426 // only if it was successfully executed
1429 } catch (Exception e)
1431 System.err.println("Exception Whilst trying to execute file " + sfile
1432 + " as a groovy script.");
1433 e.printStackTrace(System.err);
1438 public static boolean isHeadlessMode()
1440 String isheadless = System.getProperty("java.awt.headless");
1441 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1448 public AlignFrame[] getAlignFrames()
1450 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1451 : Desktop.getAlignFrames();
1456 * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
1460 // System.exit will run the shutdownHook first
1464 public static AlignFrame getCurrentAlignFrame()
1466 return Jalview.currentAlignFrame;
1469 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1471 Jalview.currentAlignFrame = currentAlignFrame;