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 boolean defaultStartupFile = Cache.getDefault("STARTUP_FILE",
885 file = Cache.getDefault("STARTUP_FILE",
886 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
887 + "/examples/exampleFile_2_7.jvp");
888 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
890 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
892 file.replace("http:", "https:");
893 // hardwire upgrade of the startup file
894 file.replace("_2_3", "_2_7");
895 file.replace("2_7.jar", "2_7.jvp");
896 // and remove the stale setting
897 Cache.removeProperty("STARTUP_FILE");
898 defaultStartupFile = true;
901 protocol = AppletFormatAdapter.checkProtocol(file);
903 if (file.endsWith(".jar"))
905 format = FileFormat.Jalview;
911 format = new IdentifyFile().identify(file, protocol);
912 } catch (FileFormatException e)
918 startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
920 if (defaultStartupFile)
922 Console.debug("Resetting up-to-date flag for startup file");
923 startUpAlframe.getViewport().setSavedUpToDate(true);
925 // extract groovy arguments before anything else.
928 // Once all other stuff is done, execute any groovy scripts (in order)
929 if (groovyscript != null)
931 if (Cache.groovyJarsPresent())
933 System.out.println("Executing script " + groovyscript);
934 executeGroovyScript(groovyscript, startUpAlframe);
939 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
943 // and finally, turn off batch mode indicator - if the desktop still exists
948 desktop.setProgressBar(null, progress);
950 desktop.setInBatchMode(false);
954 private static void setLookAndFeel()
956 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
958 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
960 String lafProp = System.getProperty("laf");
961 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
967 else if (lafSetting != null)
971 boolean lafSet = false;
974 case "crossplatform":
975 lafSet = setCrossPlatformLookAndFeel();
978 Console.error("Could not set requested laf=" + laf);
982 lafSet = setSystemLookAndFeel();
985 Console.error("Could not set requested laf=" + laf);
989 lafSet = setGtkLookAndFeel();
992 Console.error("Could not set requested laf=" + laf);
996 lafSet = setMetalLookAndFeel();
999 Console.error("Could not set requested laf=" + laf);
1003 lafSet = setNimbusLookAndFeel();
1006 Console.error("Could not set requested laf=" + laf);
1010 lafSet = setFlatLookAndFeel();
1013 Console.error("Could not set requested laf=" + laf);
1017 lafSet = setMacLookAndFeel();
1020 Console.error("Could not set requested laf=" + laf);
1026 Console.error("Requested laf=" + laf + " not implemented");
1030 setSystemLookAndFeel();
1031 if (Platform.isLinux())
1033 setLinuxLookAndFeel();
1035 if (Platform.isMac())
1037 setMacLookAndFeel();
1042 private static boolean setCrossPlatformLookAndFeel()
1044 boolean set = false;
1047 UIManager.setLookAndFeel(
1048 UIManager.getCrossPlatformLookAndFeelClassName());
1050 } catch (Exception ex)
1052 Console.error("Unexpected Look and Feel Exception");
1053 Console.error(ex.getMessage());
1054 Console.debug(Cache.getStackTraceString(ex));
1059 private static boolean setSystemLookAndFeel()
1061 boolean set = false;
1064 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1066 } catch (Exception ex)
1068 Console.error("Unexpected Look and Feel Exception");
1069 Console.error(ex.getMessage());
1070 Console.debug(Cache.getStackTraceString(ex));
1075 private static boolean setSpecificLookAndFeel(String name,
1076 String className, boolean nameStartsWith)
1078 boolean set = false;
1081 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1083 if (info.getName() != null && nameStartsWith
1084 ? info.getName().toLowerCase(Locale.ROOT)
1085 .startsWith(name.toLowerCase(Locale.ROOT))
1086 : info.getName().toLowerCase(Locale.ROOT)
1087 .equals(name.toLowerCase(Locale.ROOT)))
1089 className = info.getClassName();
1093 UIManager.setLookAndFeel(className);
1095 } catch (Exception ex)
1097 Console.error("Unexpected Look and Feel Exception");
1098 Console.error(ex.getMessage());
1099 Console.debug(Cache.getStackTraceString(ex));
1104 private static boolean setGtkLookAndFeel()
1106 return setSpecificLookAndFeel("gtk",
1107 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1110 private static boolean setMetalLookAndFeel()
1112 return setSpecificLookAndFeel("metal",
1113 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1116 private static boolean setNimbusLookAndFeel()
1118 return setSpecificLookAndFeel("nimbus",
1119 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1122 private static boolean setFlatLookAndFeel()
1124 boolean set = false;
1125 if (SystemInfo.isMacOS)
1129 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatMacLightLaf");
1131 Console.debug("Using FlatMacLightLaf");
1132 } catch (ClassNotFoundException | InstantiationException
1133 | IllegalAccessException | UnsupportedLookAndFeelException e)
1135 Console.debug("Exception loading FlatLightLaf", e);
1137 System.setProperty("apple.laf.useScreenMenuBar", "true");
1138 System.setProperty("apple.awt.application.name",
1139 ChannelProperties.getProperty("app_name"));
1140 System.setProperty("apple.awt.application.appearance", "system");
1141 if (SystemInfo.isMacFullWindowContentSupported
1142 && Desktop.desktop != null)
1144 Console.debug("Setting transparent title bar");
1145 Desktop.desktop.getRootPane()
1146 .putClientProperty("apple.awt.fullWindowContent", true);
1147 Desktop.desktop.getRootPane()
1148 .putClientProperty("apple.awt.transparentTitleBar", true);
1149 Desktop.desktop.getRootPane()
1150 .putClientProperty("apple.awt.fullscreenable", true);
1152 SwingUtilities.invokeLater(() -> {
1153 FlatMacLightLaf.setup();
1155 Console.debug("Using FlatMacLightLaf");
1158 else if (SystemInfo.isWindows)
1162 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1164 Console.debug("Using FlatLightLaf");
1165 } catch (ClassNotFoundException | InstantiationException
1166 | IllegalAccessException | UnsupportedLookAndFeelException e)
1168 Console.debug("Exception loading FlatLightLaf", e);
1170 // Windows specific properties here
1171 SwingUtilities.invokeLater(() -> {
1172 FlatLightLaf.setup();
1174 Console.debug("Using FlatLightLaf");
1177 else if (SystemInfo.isLinux)
1181 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1183 Console.debug("Using FlatLightLaf");
1184 } catch (ClassNotFoundException | InstantiationException
1185 | IllegalAccessException | UnsupportedLookAndFeelException e)
1187 Console.debug("Exception loading FlatLightLaf", e);
1189 // enable custom window decorations
1190 JFrame.setDefaultLookAndFeelDecorated(true);
1191 JDialog.setDefaultLookAndFeelDecorated(true);
1192 SwingUtilities.invokeLater(() -> {
1193 FlatLightLaf.setup();
1195 Console.debug("Using FlatLightLaf");
1203 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1205 Console.debug("Using FlatLightLaf");
1206 } catch (ClassNotFoundException | InstantiationException
1207 | IllegalAccessException | UnsupportedLookAndFeelException e)
1209 Console.debug("Exception loading FlatLightLaf", e);
1215 UIManager.put("TabbedPane.tabType", "card");
1216 UIManager.put("TabbedPane.showTabSeparators", true);
1217 UIManager.put("TabbedPane.showContentSeparator", true);
1218 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1219 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1220 UIManager.put("TabbedPane.hasFullBorder", true);
1221 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1222 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1223 UIManager.put("TabbedPane.smoothScrolling", true);
1224 UIManager.put("TabbedPane.tabWidthMode", "compact");
1225 UIManager.put("TabbedPane.selectedBackground", Color.white);
1228 Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
1232 private static boolean setMacLookAndFeel()
1234 boolean set = false;
1235 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1236 ChannelProperties.getProperty("app_name"));
1237 System.setProperty("apple.laf.useScreenMenuBar", "true");
1239 * broken native LAFs on (ARM?) macbooks
1240 set = setQuaquaLookAndFeel();
1241 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1242 .toLowerCase(Locale.ROOT).contains("quaqua"))
1244 set = setVaquaLookAndFeel();
1247 set = setFlatLookAndFeel();
1251 private static boolean setLinuxLookAndFeel()
1253 boolean set = false;
1254 set = setFlatLookAndFeel();
1256 set = setMetalLookAndFeel();
1257 // avoid GtkLookAndFeel -- not good results especially on HiDPI
1259 set = setNimbusLookAndFeel();
1263 private static void showUsage()
1266 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1267 + "-nodisplay\tRun Jalview without User Interface.\n"
1268 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1269 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1270 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1271 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1272 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1273 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1274 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1275 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1276 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1277 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1278 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1279 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1280 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1281 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1282 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1283 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1284 + "-html FILE\tCreate HTML file from alignment.\n"
1285 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1286 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1287 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1288 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1289 + "-noquestionnaire\tTurn off questionnaire check.\n"
1290 + "-nonews\tTurn off check for Jalview news.\n"
1291 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1292 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1294 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1295 // after all other properties files have been read\n\t
1296 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1297 // passed in correctly)"
1298 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1299 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1300 + "-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"
1301 + "-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"
1302 + "-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"
1303 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1306 private static void startUsageStats(final Desktop desktop)
1309 * start a User Config prompt asking if we can log usage statistics.
1311 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
1312 "USAGESTATS", "Jalview Usage Statistics",
1313 "Do you want to help make Jalview better by enabling "
1314 + "the collection of usage statistics with Google Analytics ?"
1315 + "\n\n(you can enable or disable usage tracking in the preferences)",
1322 "Initialising googletracker for usage stats.");
1323 Cache.initGoogleTracker();
1324 Console.debug("Tracking enabled.");
1331 Console.debug("Not enabling Google Tracking.");
1334 desktop.addDialogThread(prompter);
1338 * Locate the given string as a file and pass it to the groovy interpreter.
1340 * @param groovyscript
1341 * the script to execute
1342 * @param jalviewContext
1343 * the Jalview Desktop object passed in to the groovy binding as the
1346 private void executeGroovyScript(String groovyscript, AlignFrame af)
1349 * for scripts contained in files
1356 if (groovyscript.trim().equals("STDIN"))
1358 // read from stdin into a tempfile and execute it
1361 tfile = File.createTempFile("jalview", "groovy");
1362 PrintWriter outfile = new PrintWriter(
1363 new OutputStreamWriter(new FileOutputStream(tfile)));
1364 BufferedReader br = new BufferedReader(
1365 new InputStreamReader(System.in));
1367 while ((line = br.readLine()) != null)
1369 outfile.write(line + "\n");
1375 } catch (Exception ex)
1377 System.err.println("Failed to read from STDIN into tempfile "
1378 + ((tfile == null) ? "(tempfile wasn't created)"
1379 : tfile.toString()));
1380 ex.printStackTrace();
1385 sfile = tfile.toURI().toURL();
1386 } catch (Exception x)
1389 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1391 x.printStackTrace();
1399 sfile = new URI(groovyscript).toURL();
1400 } catch (Exception x)
1402 tfile = new File(groovyscript);
1403 if (!tfile.exists())
1405 System.err.println("File '" + groovyscript + "' does not exist.");
1408 if (!tfile.canRead())
1410 System.err.println("File '" + groovyscript + "' cannot be read.");
1413 if (tfile.length() < 1)
1415 System.err.println("File '" + groovyscript + "' is empty.");
1420 sfile = tfile.getAbsoluteFile().toURI().toURL();
1421 } catch (Exception ex)
1423 System.err.println("Failed to create a file URL for "
1424 + tfile.getAbsoluteFile());
1431 Map<String, java.lang.Object> vbinding = new HashMap<>();
1432 vbinding.put("Jalview", this);
1435 vbinding.put("currentAlFrame", af);
1437 Binding gbinding = new Binding(vbinding);
1438 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1439 gse.run(sfile.toString(), gbinding);
1440 if ("STDIN".equals(groovyscript))
1442 // delete temp file that we made -
1443 // only if it was successfully executed
1446 } catch (Exception e)
1448 System.err.println("Exception Whilst trying to execute file " + sfile
1449 + " as a groovy script.");
1450 e.printStackTrace(System.err);
1455 public static boolean isHeadlessMode()
1457 String isheadless = System.getProperty("java.awt.headless");
1458 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1465 public AlignFrame[] getAlignFrames()
1467 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1468 : Desktop.getAlignFrames();
1473 * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
1477 // System.exit will run the shutdownHook first
1481 public static AlignFrame getCurrentAlignFrame()
1483 return Jalview.currentAlignFrame;
1486 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1488 Jalview.currentAlignFrame = currentAlignFrame;