2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import java.awt.Color;
24 import java.io.BufferedReader;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.io.OutputStreamWriter;
30 import java.io.PrintWriter;
31 import java.net.MalformedURLException;
33 import java.net.URISyntaxException;
35 import java.security.AllPermission;
36 import java.security.CodeSource;
37 import java.security.PermissionCollection;
38 import java.security.Permissions;
39 import java.security.Policy;
40 import java.util.HashMap;
41 import java.util.Locale;
43 import java.util.Vector;
44 import java.util.logging.ConsoleHandler;
45 import java.util.logging.Level;
46 import java.util.logging.Logger;
48 import javax.swing.JDialog;
49 import javax.swing.JFrame;
50 import javax.swing.JOptionPane;
51 import javax.swing.SwingUtilities;
52 import javax.swing.UIManager;
53 import javax.swing.UIManager.LookAndFeelInfo;
54 import javax.swing.UnsupportedLookAndFeelException;
56 import com.formdev.flatlaf.FlatLightLaf;
57 import com.formdev.flatlaf.themes.FlatMacLightLaf;
58 import com.formdev.flatlaf.util.SystemInfo;
59 import com.threerings.getdown.util.LaunchUtil;
61 //import edu.stanford.ejalbert.launching.IBrowserLaunching;
62 import groovy.lang.Binding;
63 import groovy.util.GroovyScriptEngine;
64 import jalview.ext.so.SequenceOntology;
65 import jalview.gui.AlignFrame;
66 import jalview.gui.Desktop;
67 import jalview.gui.PromptUserConfig;
68 import jalview.gui.QuitHandler;
69 import jalview.gui.QuitHandler.QResponse;
70 import jalview.io.AppletFormatAdapter;
71 import jalview.io.BioJsHTMLOutput;
72 import jalview.io.DataSourceType;
73 import jalview.io.FileFormat;
74 import jalview.io.FileFormatException;
75 import jalview.io.FileFormatI;
76 import jalview.io.FileFormats;
77 import jalview.io.FileLoader;
78 import jalview.io.HtmlSvgOutput;
79 import jalview.io.IdentifyFile;
80 import jalview.io.NewickFile;
81 import jalview.io.gff.SequenceOntologyFactory;
82 import jalview.schemes.ColourSchemeI;
83 import jalview.schemes.ColourSchemeProperty;
84 import jalview.util.ChannelProperties;
85 import jalview.util.HttpUtils;
86 import jalview.util.LaunchUtils;
87 import jalview.util.MessageManager;
88 import jalview.util.Platform;
89 import jalview.ws.jws2.Jws2Discoverer;
92 * Main class for Jalview Application <br>
94 * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
97 * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
98 * jalview.bin.Jalview jalview.bin.Jalview
100 * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
101 * embellish '*' to e.g. '*.jar')
104 * @version $Revision$
110 Platform.getURLCommandArguments();
111 Platform.addJ2SDirectDatabaseCall("https://www.jalview.org");
112 Platform.addJ2SDirectDatabaseCall("http://www.jalview.org");
113 Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk");
114 Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk");
118 * singleton instance of this class
120 private static Jalview instance;
122 private Desktop desktop;
124 public static AlignFrame currentAlignFrame;
128 if (!Platform.isJS())
135 // grab all the rights we can for the JVM
136 Policy.setPolicy(new Policy()
139 public PermissionCollection getPermissions(CodeSource codesource)
141 Permissions perms = new Permissions();
142 perms.add(new AllPermission());
147 public void refresh()
155 * keep track of feature fetching tasks.
163 * TODO: generalise to track all jalview events to orchestrate batch processing
167 private int queued = 0;
169 private int running = 0;
171 public FeatureFetcher()
176 public void addFetcher(final AlignFrame af,
177 final Vector<String> dasSources)
179 final long id = System.currentTimeMillis();
181 final FeatureFetcher us = this;
182 new Thread(new Runnable()
194 af.setProgressBar(MessageManager
195 .getString("status.das_features_being_retrived"), id);
196 af.featureSettings_actionPerformed(null);
197 af.setProgressBar(null, id);
206 public synchronized boolean allFinished()
208 return queued == 0 && running == 0;
213 public static Jalview getInstance()
219 * main class for Jalview application
222 * open <em>filename</em>
224 public static void main(String[] args)
226 // setLogging(); // BH - for event debugging in JavaScript
227 instance = new Jalview();
228 instance.doMain(args);
231 private static void logClass(String name)
233 // BH - for event debugging in JavaScript
234 ConsoleHandler consoleHandler = new ConsoleHandler();
235 consoleHandler.setLevel(Level.ALL);
236 Logger logger = Logger.getLogger(name);
237 logger.setLevel(Level.ALL);
238 logger.addHandler(consoleHandler);
241 @SuppressWarnings("unused")
242 private static void setLogging()
250 System.out.println("not in js");
253 // BH - for event debugging in JavaScript (Java mode only)
254 if (!Platform.isJS())
261 Logger.getLogger("").setLevel(Level.ALL);
262 logClass("java.awt.EventDispatchThread");
263 logClass("java.awt.EventQueue");
264 logClass("java.awt.Component");
265 logClass("java.awt.focus.Component");
266 logClass("java.awt.focus.DefaultKeyboardFocusManager");
274 void doMain(String[] args)
277 if (!Platform.isJS())
279 System.setSecurityManager(null);
281 Runtime.getRuntime().addShutdownHook(new Thread()
285 Console.debug("Running shutdown hook");
286 if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT)
288 // Got to here by a SIGTERM signal.
289 // Note we will not actually cancel the quit from here -- it's too
290 // late -- but we can wait for saving files.
291 Console.debug("Checking for saving files");
292 QuitHandler.getQuitResponse(false);
296 Console.debug("Nothing more to do");
298 Console.debug("Exiting, bye!");
299 // shutdownHook cannot be cancelled, JVM will now halt
305 .println("Java version: " + System.getProperty("java.version"));
306 System.out.println("Java Home: " + System.getProperty("java.home"));
307 System.out.println(System.getProperty("os.arch") + " "
308 + System.getProperty("os.name") + " "
309 + System.getProperty("os.version"));
311 String val = System.getProperty("sys.install4jVersion");
314 System.out.println("Install4j version: " + val);
316 val = System.getProperty("installer_template_version");
319 System.out.println("Install4j template version: " + val);
321 val = System.getProperty("launcher_version");
324 System.out.println("Launcher version: " + val);
327 // report Jalview version
328 Cache.loadBuildProperties(true);
330 ArgsParser aparser = new ArgsParser(args);
332 boolean headless = false;
334 String usrPropsFile = aparser.getValue("props");
335 Cache.loadProperties(usrPropsFile); // must do this
337 if (usrPropsFile != null)
340 "CMD [-props " + usrPropsFile + "] executed successfully!");
343 if (!Platform.isJS())
350 if (aparser.contains("help") || aparser.contains("h"))
355 if (aparser.contains("nodisplay") || aparser.contains("nogui")
356 || aparser.contains("headless"))
358 System.setProperty("java.awt.headless", "true");
363 // allow https handshakes to download intermediate certs if necessary
364 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
366 final String jabawsUrl = aparser.getValue("jabaws");
367 if (jabawsUrl != null)
371 Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
373 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
374 } catch (MalformedURLException e)
377 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
382 String defs = aparser.getValue("setprop");
385 int p = defs.indexOf('=');
388 System.err.println("Ignoring invalid setprop argument : " + defs);
392 System.out.println("Executing setprop argument: " + defs);
395 Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
397 // DISABLED FOR SECURITY REASONS
398 // TODO: add a property to allow properties to be overriden by cli args
399 // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
401 defs = aparser.getValue("setprop");
403 if (System.getProperty("java.awt.headless") != null
404 && System.getProperty("java.awt.headless").equals("true"))
408 System.setProperty("http.agent",
409 "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
413 Console.initLogger();
416 NoClassDefFoundError error)
418 error.printStackTrace();
419 System.out.println("\nEssential logging libraries not found."
420 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
429 * configure 'full' SO model if preferences say to, else use the default (full SO)
430 * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
432 boolean soDefault = !Platform.isJS();
433 if (Cache.getDefault("USE_FULL_SO", soDefault))
435 SequenceOntologyFactory.setInstance(new SequenceOntology());
440 Desktop.nosplash = aparser.contains("nosplash");
441 desktop = new Desktop();
442 desktop.setInBatchMode(true); // indicate we are starting up
446 JalviewTaskbar.setTaskbar(this);
447 } catch (Exception e)
449 Console.info("Cannot set Taskbar");
450 Console.error(e.getMessage());
451 // e.printStackTrace();
452 } catch (Throwable t)
454 Console.info("Cannot set Taskbar");
455 Console.error(t.getMessage());
456 // t.printStackTrace();
459 // set Proxy settings before all the internet calls
460 Cache.setProxyPropertiesFromPreferences();
462 desktop.setVisible(true);
464 if (!Platform.isJS())
473 * Check to see that the JVM version being run is suitable for the Java
474 * version this Jalview was compiled for. Popup a warning if not.
476 if (!LaunchUtils.checkJavaVersion())
478 Console.warn("The Java version being used (Java "
479 + LaunchUtils.getJavaVersion()
480 + ") may lead to problems. This installation of Jalview should be used with Java "
481 + LaunchUtils.getJavaCompileVersion() + ".");
484 .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
487 MessageManager.getString("label.continue") };
488 JOptionPane.showOptionDialog(null,
489 MessageManager.formatMessage(
490 "warning.wrong_jvm_version_message",
491 LaunchUtils.getJavaVersion(),
492 LaunchUtils.getJavaCompileVersion()),
494 .getString("warning.wrong_jvm_version_title"),
495 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
496 null, options, options[0]);
500 if (!aparser.contains("nowebservicediscovery"))
502 desktop.startServiceDiscovery();
504 if (!aparser.contains("nousagestats"))
506 startUsageStats(desktop);
510 System.err.println("CMD [-nousagestats] executed successfully!");
513 if (!aparser.contains("noquestionnaire"))
515 String url = aparser.getValue("questionnaire");
518 // Start the desktop questionnaire prompter with the specified
520 Console.debug("Starting questionnaire url at " + url);
521 desktop.checkForQuestionnaire(url);
522 System.out.println("CMD questionnaire[-" + url
523 + "] executed successfully!");
527 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
529 // Start the desktop questionnaire prompter with the specified
532 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
534 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
536 "Starting questionnaire with default url: " + defurl);
537 desktop.checkForQuestionnaire(defurl);
544 .println("CMD [-noquestionnaire] executed successfully!");
547 if (!aparser.contains("nonews")
548 || Cache.getProperty("NONEWS") == null)
550 desktop.checkForNews();
553 if (!aparser.contains("nohtmltemplates")
554 || Cache.getProperty("NOHTMLTEMPLATES") == null)
556 BioJsHTMLOutput.updateBioJS();
561 // Check if JVM and compile version might cause problems and log if it
563 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
565 Console.warn("The Java version being used (Java "
566 + LaunchUtils.getJavaVersion()
567 + ") may lead to problems. This installation of Jalview should be used with Java "
568 + LaunchUtils.getJavaCompileVersion() + ".");
571 // Move any new getdown-launcher-new.jar into place over old
572 // getdown-launcher.jar
573 String appdirString = System.getProperty("getdownappdir");
574 if (appdirString != null && appdirString.length() > 0)
576 final File appdir = new File(appdirString);
582 LaunchUtil.upgradeGetdown(
583 new File(appdir, "getdown-launcher-old.jar"),
584 new File(appdir, "getdown-launcher.jar"),
585 new File(appdir, "getdown-launcher-new.jar"));
590 String file = null, data = null;
592 FileFormatI format = null;
594 DataSourceType protocol = null;
596 FileLoader fileLoader = new FileLoader(!headless);
598 String groovyscript = null; // script to execute after all loading is
599 // completed one way or another
600 // extract groovy argument and execute if necessary
601 groovyscript = aparser.getValue("groovy", true);
602 file = aparser.getValue("open", true);
604 if (file == null && desktop == null)
606 System.out.println("No files to open!");
611 // Finally, deal with the remaining input data.
616 desktop.setProgressBar(
618 .getString("status.processing_commandline_args"),
619 progress = System.currentTimeMillis());
621 System.out.println("CMD [-open " + file + "] executed successfully!");
623 if (!Platform.isJS())
625 * ignore in JavaScript -- can't just file existence - could load it?
630 if (!HttpUtils.startsWithHttpOrHttps(file))
632 if (!(new File(file)).exists())
634 System.out.println("Can't find " + file);
643 protocol = AppletFormatAdapter.checkProtocol(file);
647 format = new IdentifyFile().identify(file, protocol);
648 } catch (FileFormatException e1)
653 AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
657 System.out.println("error");
661 setCurrentAlignFrame(af);
662 data = aparser.getValue("colour", true);
665 data.replaceAll("%20", " ");
667 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
668 af.getViewport(), af.getViewport().getAlignment(), data);
673 "CMD [-color " + data + "] executed successfully!");
678 // Must maintain ability to use the groups flag
679 data = aparser.getValue("groups", true);
682 af.parseFeaturesFile(data,
683 AppletFormatAdapter.checkProtocol(data));
684 // System.out.println("Added " + data);
686 "CMD groups[-" + data + "] executed successfully!");
688 data = aparser.getValue("features", true);
691 af.parseFeaturesFile(data,
692 AppletFormatAdapter.checkProtocol(data));
693 // System.out.println("Added " + data);
695 "CMD [-features " + data + "] executed successfully!");
698 data = aparser.getValue("annotations", true);
701 af.loadJalviewDataFile(data, null, null, null);
702 // System.out.println("Added " + data);
704 "CMD [-annotations " + data + "] executed successfully!");
706 // set or clear the sortbytree flag.
707 if (aparser.contains("sortbytree"))
709 af.getViewport().setSortByTree(true);
710 if (af.getViewport().getSortByTree())
712 System.out.println("CMD [-sortbytree] executed successfully!");
715 if (aparser.contains("no-annotation"))
717 af.getViewport().setShowAnnotation(false);
718 if (!af.getViewport().isShowAnnotation())
720 System.out.println("CMD no-annotation executed successfully!");
723 if (aparser.contains("nosortbytree"))
725 af.getViewport().setSortByTree(false);
726 if (!af.getViewport().getSortByTree())
729 .println("CMD [-nosortbytree] executed successfully!");
732 data = aparser.getValue("tree", true);
738 "CMD [-tree " + data + "] executed successfully!");
739 NewickFile nf = new NewickFile(data,
740 AppletFormatAdapter.checkProtocol(data));
742 .setCurrentTree(af.showNewickTree(nf, data).getTree());
743 } catch (IOException ex)
745 System.err.println("Couldn't add tree " + data);
746 ex.printStackTrace(System.err);
749 // TODO - load PDB structure(s) to alignment JAL-629
750 // (associate with identical sequence in alignment, or a specified
752 if (groovyscript != null)
754 // Execute the groovy script after we've done all the rendering stuff
755 // and before any images or figures are generated.
756 System.out.println("Executing script " + groovyscript);
757 executeGroovyScript(groovyscript, af);
758 System.out.println("CMD groovy[" + groovyscript
759 + "] executed successfully!");
762 String imageName = "unnamed.png";
763 while (aparser.getSize() > 1)
765 String outputFormat = aparser.nextValue();
766 file = aparser.nextValue();
768 if (outputFormat.equalsIgnoreCase("png"))
770 af.createPNG(new File(file));
771 imageName = (new File(file)).getName();
772 System.out.println("Creating PNG image: " + file);
775 else if (outputFormat.equalsIgnoreCase("svg"))
777 File imageFile = new File(file);
778 imageName = imageFile.getName();
779 af.createSVG(imageFile);
780 System.out.println("Creating SVG image: " + file);
783 else if (outputFormat.equalsIgnoreCase("html"))
785 File imageFile = new File(file);
786 imageName = imageFile.getName();
787 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
788 htmlSVG.exportHTML(file);
790 System.out.println("Creating HTML image: " + file);
793 else if (outputFormat.equalsIgnoreCase("biojsmsa"))
797 System.err.println("The output html file must not be null");
802 BioJsHTMLOutput.refreshVersionInfo(
803 BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
804 } catch (URISyntaxException e)
808 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
809 bjs.exportHTML(file);
811 .println("Creating BioJS MSA Viwer HTML file: " + file);
814 else if (outputFormat.equalsIgnoreCase("imgMap"))
816 af.createImageMap(new File(file), imageName);
817 System.out.println("Creating image map: " + file);
820 else if (outputFormat.equalsIgnoreCase("eps"))
822 File outputFile = new File(file);
824 "Creating EPS file: " + outputFile.getAbsolutePath());
825 af.createEPS(outputFile);
828 FileFormatI outFormat = null;
831 outFormat = FileFormats.getInstance().forName(outputFormat);
832 } catch (Exception formatP)
834 System.out.println("Couldn't parse " + outFormat
835 + " as a valid Jalview format string.");
837 if (outFormat != null)
839 if (!outFormat.isWritable())
842 "This version of Jalview does not support alignment export as "
847 af.saveAlignment(file, outFormat);
848 if (af.isSaveAlignmentSuccessful())
850 System.out.println("Written alignment in "
851 + outFormat.getName() + " format to " + file);
855 System.out.println("Error writing file " + file + " in "
856 + outFormat.getName() + " format!!");
863 while (aparser.getSize() > 0)
865 System.out.println("Unknown arg: " + aparser.nextValue());
870 AlignFrame startUpAlframe = null;
871 // We'll only open the default file if the desktop is visible.
873 // ////////////////////
875 if (!Platform.isJS() && !headless && file == null
876 && Cache.getDefault("SHOW_STARTUP_FILE", true))
883 file = Cache.getDefault("STARTUP_FILE",
884 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
885 + "/examples/exampleFile_2_7.jvp");
886 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
888 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
890 file.replace("http:", "https:");
891 // hardwire upgrade of the startup file
892 file.replace("_2_3", "_2_7");
893 file.replace("2_7.jar", "2_7.jvp");
894 // and remove the stale setting
895 Cache.removeProperty("STARTUP_FILE");
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 // don't ask to save when quitting if only the startup file has been
919 Console.debug("Resetting up-to-date flag for startup file");
920 startUpAlframe.getViewport().setSavedUpToDate(true);
921 // extract groovy arguments before anything else.
924 // Once all other stuff is done, execute any groovy scripts (in order)
925 if (groovyscript != null)
927 if (Cache.groovyJarsPresent())
929 System.out.println("Executing script " + groovyscript);
930 executeGroovyScript(groovyscript, startUpAlframe);
935 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
939 // and finally, turn off batch mode indicator - if the desktop still exists
944 desktop.setProgressBar(null, progress);
946 desktop.setInBatchMode(false);
950 private static void setLookAndFeel()
952 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
954 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
956 String lafProp = System.getProperty("laf");
957 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
963 else if (lafSetting != null)
967 boolean lafSet = false;
970 case "crossplatform":
971 lafSet = setCrossPlatformLookAndFeel();
974 Console.error("Could not set requested laf=" + laf);
978 lafSet = setSystemLookAndFeel();
981 Console.error("Could not set requested laf=" + laf);
985 lafSet = setGtkLookAndFeel();
988 Console.error("Could not set requested laf=" + laf);
992 lafSet = setMetalLookAndFeel();
995 Console.error("Could not set requested laf=" + laf);
999 lafSet = setNimbusLookAndFeel();
1002 Console.error("Could not set requested laf=" + laf);
1006 lafSet = setFlatLookAndFeel();
1009 Console.error("Could not set requested laf=" + laf);
1013 lafSet = setMacLookAndFeel();
1016 Console.error("Could not set requested laf=" + laf);
1022 Console.error("Requested laf=" + laf + " not implemented");
1026 setSystemLookAndFeel();
1027 if (Platform.isLinux())
1029 setLinuxLookAndFeel();
1031 if (Platform.isMac())
1033 setMacLookAndFeel();
1038 private static boolean setCrossPlatformLookAndFeel()
1040 boolean set = false;
1043 UIManager.setLookAndFeel(
1044 UIManager.getCrossPlatformLookAndFeelClassName());
1046 } catch (Exception ex)
1048 Console.error("Unexpected Look and Feel Exception");
1049 Console.error(ex.getMessage());
1050 Console.debug(Cache.getStackTraceString(ex));
1055 private static boolean setSystemLookAndFeel()
1057 boolean set = false;
1060 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1062 } catch (Exception ex)
1064 Console.error("Unexpected Look and Feel Exception");
1065 Console.error(ex.getMessage());
1066 Console.debug(Cache.getStackTraceString(ex));
1071 private static boolean setSpecificLookAndFeel(String name,
1072 String className, boolean nameStartsWith)
1074 boolean set = false;
1077 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1079 if (info.getName() != null && nameStartsWith
1080 ? info.getName().toLowerCase(Locale.ROOT)
1081 .startsWith(name.toLowerCase(Locale.ROOT))
1082 : info.getName().toLowerCase(Locale.ROOT)
1083 .equals(name.toLowerCase(Locale.ROOT)))
1085 className = info.getClassName();
1089 UIManager.setLookAndFeel(className);
1091 } catch (Exception ex)
1093 Console.error("Unexpected Look and Feel Exception");
1094 Console.error(ex.getMessage());
1095 Console.debug(Cache.getStackTraceString(ex));
1100 private static boolean setGtkLookAndFeel()
1102 return setSpecificLookAndFeel("gtk",
1103 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1106 private static boolean setMetalLookAndFeel()
1108 return setSpecificLookAndFeel("metal",
1109 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1112 private static boolean setNimbusLookAndFeel()
1114 return setSpecificLookAndFeel("nimbus",
1115 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1118 private static boolean setFlatLookAndFeel()
1120 boolean set = false;
1121 if (SystemInfo.isMacOS)
1125 UIManager.setLookAndFeel(
1126 "com.formdev.flatlaf.themes.FlatMacLightLaf");
1128 Console.debug("Using FlatMacLightLaf");
1129 } catch (ClassNotFoundException | InstantiationException
1130 | IllegalAccessException | UnsupportedLookAndFeelException e)
1132 Console.debug("Exception loading FlatLightLaf", e);
1134 System.setProperty("apple.laf.useScreenMenuBar", "true");
1135 System.setProperty("apple.awt.application.name",
1136 ChannelProperties.getProperty("app_name"));
1137 System.setProperty("apple.awt.application.appearance", "system");
1138 if (SystemInfo.isMacFullWindowContentSupported
1139 && Desktop.desktop != null)
1141 Console.debug("Setting transparent title bar");
1142 Desktop.desktop.getRootPane()
1143 .putClientProperty("apple.awt.fullWindowContent", true);
1144 Desktop.desktop.getRootPane()
1145 .putClientProperty("apple.awt.transparentTitleBar", true);
1146 Desktop.desktop.getRootPane()
1147 .putClientProperty("apple.awt.fullscreenable", true);
1149 SwingUtilities.invokeLater(() -> {
1150 FlatMacLightLaf.setup();
1152 Console.debug("Using FlatMacLightLaf");
1159 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1161 Console.debug("Using FlatLightLaf");
1162 } catch (ClassNotFoundException | InstantiationException
1163 | IllegalAccessException | UnsupportedLookAndFeelException e)
1165 Console.debug("Exception loading FlatLightLaf", e);
1167 // Windows specific properties here
1168 SwingUtilities.invokeLater(() -> {
1169 FlatLightLaf.setup();
1171 Console.debug("Using FlatLightLaf");
1174 else if (SystemInfo.isLinux)
1178 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1180 Console.debug("Using FlatLightLaf");
1181 } catch (ClassNotFoundException | InstantiationException
1182 | IllegalAccessException | UnsupportedLookAndFeelException e)
1184 Console.debug("Exception loading FlatLightLaf", e);
1186 // enable custom window decorations
1187 JFrame.setDefaultLookAndFeelDecorated(true);
1188 JDialog.setDefaultLookAndFeelDecorated(true);
1189 SwingUtilities.invokeLater(() -> {
1190 FlatLightLaf.setup();
1192 Console.debug("Using FlatLightLaf");
1200 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1202 Console.debug("Using FlatLightLaf");
1203 } catch (ClassNotFoundException | InstantiationException
1204 | IllegalAccessException | UnsupportedLookAndFeelException e)
1206 Console.debug("Exception loading FlatLightLaf", e);
1212 UIManager.put("TabbedPane.tabType", "card");
1213 UIManager.put("TabbedPane.showTabSeparators", true);
1214 UIManager.put("TabbedPane.showContentSeparator", true);
1215 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1216 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1217 UIManager.put("TabbedPane.hasFullBorder", true);
1218 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1219 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1220 UIManager.put("TabbedPane.smoothScrolling", true);
1221 UIManager.put("TabbedPane.tabWidthMode", "compact");
1222 UIManager.put("TabbedPane.selectedBackground", Color.white);
1225 Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
1229 private static boolean setMacLookAndFeel()
1231 boolean set = false;
1232 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1233 ChannelProperties.getProperty("app_name"));
1234 System.setProperty("apple.laf.useScreenMenuBar", "true");
1236 * broken native LAFs on (ARM?) macbooks
1237 set = setQuaquaLookAndFeel();
1238 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1239 .toLowerCase(Locale.ROOT).contains("quaqua"))
1241 set = setVaquaLookAndFeel();
1244 set = setFlatLookAndFeel();
1248 private static boolean setLinuxLookAndFeel()
1250 boolean set = false;
1251 set = setFlatLookAndFeel();
1253 set = setMetalLookAndFeel();
1254 // avoid GtkLookAndFeel -- not good results especially on HiDPI
1256 set = setNimbusLookAndFeel();
1260 private static void showUsage()
1263 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1264 + "-nodisplay\tRun Jalview without User Interface.\n"
1265 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1266 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1267 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1268 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1269 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1270 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1271 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1272 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1273 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1274 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1275 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1276 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1277 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1278 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1279 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1280 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1281 + "-html FILE\tCreate HTML file from alignment.\n"
1282 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1283 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1284 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1285 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1286 + "-noquestionnaire\tTurn off questionnaire check.\n"
1287 + "-nonews\tTurn off check for Jalview news.\n"
1288 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1289 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1291 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1292 // after all other properties files have been read\n\t
1293 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1294 // passed in correctly)"
1295 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1296 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1297 + "-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"
1298 + "-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"
1299 + "-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"
1300 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1303 private static void startUsageStats(final Desktop desktop)
1306 * start a User Config prompt asking if we can log usage statistics.
1308 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
1309 "USAGESTATS", "Jalview Usage Statistics",
1310 "Do you want to help make Jalview better by enabling "
1311 + "the collection of usage statistics with Google Analytics ?"
1312 + "\n\n(you can enable or disable usage tracking in the preferences)",
1319 "Initialising googletracker for usage stats.");
1320 Cache.initGoogleTracker();
1321 Console.debug("Tracking enabled.");
1328 Console.debug("Not enabling Google Tracking.");
1331 desktop.addDialogThread(prompter);
1335 * Locate the given string as a file and pass it to the groovy interpreter.
1337 * @param groovyscript
1338 * the script to execute
1339 * @param jalviewContext
1340 * the Jalview Desktop object passed in to the groovy binding as the
1343 private void executeGroovyScript(String groovyscript, AlignFrame af)
1346 * for scripts contained in files
1353 if (groovyscript.trim().equals("STDIN"))
1355 // read from stdin into a tempfile and execute it
1358 tfile = File.createTempFile("jalview", "groovy");
1359 PrintWriter outfile = new PrintWriter(
1360 new OutputStreamWriter(new FileOutputStream(tfile)));
1361 BufferedReader br = new BufferedReader(
1362 new InputStreamReader(System.in));
1364 while ((line = br.readLine()) != null)
1366 outfile.write(line + "\n");
1372 } catch (Exception ex)
1374 System.err.println("Failed to read from STDIN into tempfile "
1375 + ((tfile == null) ? "(tempfile wasn't created)"
1376 : tfile.toString()));
1377 ex.printStackTrace();
1382 sfile = tfile.toURI().toURL();
1383 } catch (Exception x)
1386 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1388 x.printStackTrace();
1396 sfile = new URI(groovyscript).toURL();
1397 } catch (Exception x)
1399 tfile = new File(groovyscript);
1400 if (!tfile.exists())
1402 System.err.println("File '" + groovyscript + "' does not exist.");
1405 if (!tfile.canRead())
1407 System.err.println("File '" + groovyscript + "' cannot be read.");
1410 if (tfile.length() < 1)
1412 System.err.println("File '" + groovyscript + "' is empty.");
1417 sfile = tfile.getAbsoluteFile().toURI().toURL();
1418 } catch (Exception ex)
1420 System.err.println("Failed to create a file URL for "
1421 + tfile.getAbsoluteFile());
1428 Map<String, java.lang.Object> vbinding = new HashMap<>();
1429 vbinding.put("Jalview", this);
1432 vbinding.put("currentAlFrame", af);
1434 Binding gbinding = new Binding(vbinding);
1435 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1436 gse.run(sfile.toString(), gbinding);
1437 if ("STDIN".equals(groovyscript))
1439 // delete temp file that we made -
1440 // only if it was successfully executed
1443 } catch (Exception e)
1445 System.err.println("Exception Whilst trying to execute file " + sfile
1446 + " as a groovy script.");
1447 e.printStackTrace(System.err);
1452 public static boolean isHeadlessMode()
1454 String isheadless = System.getProperty("java.awt.headless");
1455 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1462 public AlignFrame[] getAlignFrames()
1464 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1465 : Desktop.getAlignFrames();
1470 * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
1474 // System.exit will run the shutdownHook first
1478 public static AlignFrame getCurrentAlignFrame()
1480 return Jalview.currentAlignFrame;
1483 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1485 Jalview.currentAlignFrame = currentAlignFrame;