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.util.Locale;
25 import java.awt.GraphicsEnvironment;
26 import java.awt.Color;
28 import java.io.BufferedReader;
30 import java.io.FileOutputStream;
31 import java.io.IOException;
32 import java.io.InputStreamReader;
33 import java.io.OutputStreamWriter;
34 import java.io.PrintWriter;
35 import java.net.MalformedURLException;
37 import java.net.URISyntaxException;
39 import java.security.AllPermission;
40 import java.security.CodeSource;
41 import java.security.PermissionCollection;
42 import java.security.Permissions;
43 import java.security.Policy;
44 import java.util.HashMap;
45 import java.util.Locale;
47 import java.util.Vector;
48 import java.util.logging.ConsoleHandler;
49 import java.util.logging.Level;
50 import java.util.logging.Logger;
52 import javax.swing.JOptionPane;
53 import javax.swing.SwingUtilities;
54 import javax.swing.UIManager;
55 import javax.swing.UIManager.LookAndFeelInfo;
57 import com.formdev.flatlaf.FlatLightLaf;
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.api.AlignCalcWorkerI;
65 import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI;
66 import jalview.ext.so.SequenceOntology;
67 import jalview.gui.AlignFrame;
68 import jalview.gui.AlignViewport;
69 import jalview.gui.Desktop;
70 import jalview.gui.Preferences;
71 import jalview.gui.PromptUserConfig;
72 import jalview.io.AppletFormatAdapter;
73 import jalview.io.BioJsHTMLOutput;
74 import jalview.io.DataSourceType;
75 import jalview.io.FileFormat;
76 import jalview.io.FileFormatException;
77 import jalview.io.FileFormatI;
78 import jalview.io.FileFormats;
79 import jalview.io.FileLoader;
80 import jalview.io.HtmlSvgOutput;
81 import jalview.io.IdentifyFile;
82 import jalview.io.NewickFile;
83 import jalview.io.gff.SequenceOntologyFactory;
84 import jalview.schemes.ColourSchemeI;
85 import jalview.schemes.ColourSchemeProperty;
86 import jalview.util.ChannelProperties;
87 import jalview.util.HttpUtils;
88 import jalview.util.LaunchUtils;
89 import jalview.util.MessageManager;
90 import jalview.util.Platform;
91 import jalview.ws.jws2.Jws2Discoverer;
94 * Main class for Jalview Application <br>
96 * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
99 * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
100 * jalview.bin.Jalview jalview.bin.Jalview
102 * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
103 * embellish '*' to e.g. '*.jar')
106 * @version $Revision$
108 public class Jalview implements ApplicationSingletonI
110 // for testing those nasty messages you cannot ever find.
113 // System.setOut(new PrintStream(new ByteArrayOutputStream())
116 // public void println(Object o)
120 // System.err.println(o);
126 public static Jalview getInstance()
128 return (Jalview) ApplicationSingletonProvider
129 .getInstance(Jalview.class);
134 Platform.getURLCommandArguments();
135 Platform.addJ2SDirectDatabaseCall("https://www.jalview.org");
136 Platform.addJ2SDirectDatabaseCall("http://www.jalview.org");
137 Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk");
138 Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk");
142 private boolean headless;
144 private Desktop desktop;
146 public AlignFrame currentAlignFrame;
148 public String appletResourcePath;
150 public String j2sAppletID;
152 private boolean noCalculation, noMenuBar, noStatus;
154 private boolean noAnnotation;
156 public boolean getStartCalculations()
158 return !noCalculation;
161 public boolean getAllowMenuBar()
166 public boolean getShowStatus()
171 public boolean getShowAnnotation()
173 return !noAnnotation;
180 Platform.getURLCommandArguments();
188 // grab all the rights we can for the JVM
189 Policy.setPolicy(new Policy()
192 public PermissionCollection getPermissions(CodeSource codesource)
194 Permissions perms = new Permissions();
195 perms.add(new AllPermission());
200 public void refresh()
208 * keep track of feature fetching tasks.
216 * TODO: generalise to track all jalview events to orchestrate batch processing
220 private int queued = 0;
222 private int running = 0;
224 public FeatureFetcher()
229 public void addFetcher(final AlignFrame af,
230 final Vector<String> dasSources)
232 final long id = System.currentTimeMillis();
234 final FeatureFetcher us = this;
235 new Thread(new Runnable()
247 af.setProgressBar(MessageManager
248 .getString("status.das_features_being_retrived"), id);
249 af.featureSettings_actionPerformed(null);
250 af.setProgressBar(null, id);
259 public synchronized boolean allFinished()
261 return queued == 0 && running == 0;
266 private final static boolean doPlatformLogging = false;
269 * main class for Jalview application
272 * open <em>filename</em>
274 public static void main(String[] args)
276 if (doPlatformLogging)
278 Platform.startJavaLogging();
281 getInstance().doMain(args);
291 void doMain(String[] args)
294 boolean isJS = Platform.isJS();
297 System.setSecurityManager(null);
301 * @j2sNative J2S.db._DirectDatabaseCalls["compbio.dundee.ac.uk"]=null;
302 * @j2sNative J2S.db._DirectDatabaseCalls["jalview.org"]=null;
306 .println("Java version: " + System.getProperty("java.version"));
307 System.out.println("Java Home: " + System.getProperty("java.home"));
308 System.out.println(System.getProperty("os.arch") + " "
309 + System.getProperty("os.name") + " "
310 + 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.getInstance().loadBuildProperties(true);
330 ArgsParser aparser = new ArgsParser(args);
333 String usrPropsFile = aparser.getValue("props");
334 Cache.loadProperties(usrPropsFile); // must do this before
335 boolean allowServices = true;
339 j2sAppletID = Platform.getAppID(null);
340 Preferences.setAppletDefaults();
341 Cache.loadProperties(usrPropsFile); // again, because we
342 // might be changing defaults here?
343 appletResourcePath = (String) aparser.getAppletValue("resourcepath",
354 if (usrPropsFile != null)
357 "CMD [-props " + usrPropsFile + "] executed successfully!");
359 if (aparser.contains("help") || aparser.contains("h"))
364 // BH note: Only -nodisplay is official; others are deprecated?
365 if (aparser.contains("nodisplay") || aparser.contains("nogui")
366 || aparser.contains("headless")
367 || GraphicsEnvironment.isHeadless())
370 // BH Definitely not a good idea in JavaScript;
371 // probably should not be here for Java, either.
372 System.setProperty("java.awt.headless", "true");
378 // allow https handshakes to download intermediate certs if necessary
379 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
380 final String jabawsUrl = aparser.getValue(ArgsParser.JABAWS);
381 allowServices = !("none".equals(jabawsUrl));
382 if (allowServices && jabawsUrl != null)
386 Jws2Discoverer.getInstance().setPreferredUrl(jabawsUrl);
388 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
389 } catch (MalformedURLException e)
392 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
397 String defs = aparser.getValue(ArgsParser.SETPROP);
400 int p = defs.indexOf('=');
403 System.err.println("Ignoring invalid setprop argument : " + defs);
407 System.out.println("Executing setprop argument: " + defs);
410 Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
413 defs = aparser.getValue("setprop");
415 if (System.getProperty("java.awt.headless") != null
416 && System.getProperty("java.awt.headless").equals("true"))
420 System.setProperty("http.agent",
421 "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
424 Console.initLogger();
425 } catch (NoClassDefFoundError error)
427 error.printStackTrace();
428 System.out.println("\nEssential logging libraries not found."
429 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
438 * configure 'full' SO model if preferences say to, else use the default (full SO)
439 * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
441 boolean soDefault = !isJS;
442 if (Cache.getDefault("USE_FULL_SO", soDefault))
444 SequenceOntologyFactory.setSequenceOntology(new SequenceOntology());
449 Desktop.nosplash = aparser.contains("nosplash");
450 desktop = Desktop.getInstance();
451 desktop.setInBatchMode(true); // indicate we are starting up
455 JalviewTaskbar.setTaskbar(this);
456 } catch (Exception e)
458 Console.info("Cannot set Taskbar");
459 Console.error(e.getMessage());
460 // e.printStackTrace();
461 } catch (Throwable t)
463 Console.info("Cannot set Taskbar");
464 Console.error(t.getMessage());
465 // t.printStackTrace();
468 // set Proxy settings before all the internet calls
469 Cache.setProxyPropertiesFromPreferences();
471 desktop.setVisible(true);
475 Cache.setProperty("SHOW_JWS2_SERVICES", "false");
477 if (allowServices && !aparser.contains("nowebservicediscovery"))
479 desktop.startServiceDiscovery();
490 * Check to see that the JVM version being run is suitable for the Java
491 * version this Jalview was compiled for. Popup a warning if not.
493 if (!LaunchUtils.checkJavaVersion())
495 Console.warn("The Java version being used (Java "
496 + LaunchUtils.getJavaVersion()
497 + ") may lead to problems. This installation of Jalview should be used with Java "
498 + LaunchUtils.getJavaCompileVersion() + ".");
501 .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
504 MessageManager.getString("label.continue") };
505 JOptionPane.showOptionDialog(null,
506 MessageManager.formatMessage(
507 "warning.wrong_jvm_version_message",
508 LaunchUtils.getJavaVersion(),
509 LaunchUtils.getJavaCompileVersion()),
511 .getString("warning.wrong_jvm_version_title"),
512 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
513 null, options, options[0]);
516 if (!aparser.contains("nousagestats"))
518 startUsageStats(desktop);
522 System.err.println("CMD [-nousagestats] executed successfully!");
525 if (!aparser.contains("noquestionnaire"))
527 String url = aparser.getValue("questionnaire");
530 // Start the desktop questionnaire prompter with the specified
532 Console.debug("Starting questionnaire url at " + url);
533 desktop.checkForQuestionnaire(url);
534 System.out.println("CMD questionnaire[-" + url
535 + "] executed successfully!");
539 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
541 // Start the desktop questionnaire prompter with the specified
544 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
546 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
548 "Starting questionnaire with default url: " + defurl);
549 desktop.checkForQuestionnaire(defurl);
556 .println("CMD [-noquestionnaire] executed successfully!");
559 if (!aparser.contains("nonews")
560 || Cache.getProperty("NONEWS") == null)
562 desktop.checkForNews();
565 if (!aparser.contains("nohtmltemplates")
566 || Cache.getProperty("NOHTMLTEMPLATES") == null)
568 BioJsHTMLOutput.updateBioJS();
573 // Check if JVM and compile version might cause problems and log if it
575 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
577 Console.warn("The Java version being used (Java "
578 + LaunchUtils.getJavaVersion()
579 + ") may lead to problems. This installation of Jalview should be used with Java "
580 + LaunchUtils.getJavaCompileVersion() + ".");
582 parseArguments(aparser, true);
586 * Parse all command-line String[] arguments as well as all JavaScript-derived
587 * parameters from Info.
589 * We allow for this method to be run from JavaScript. Basically allowing
595 public void parseArguments(ArgsParser aparser, boolean isStartup)
598 String groovyscript = null; // script to execute after all loading is
599 boolean isJS = Platform.isJS();
603 // Move any new getdown-launcher-new.jar into place over old
604 // getdown-launcher.jar
605 String appdirString = System.getProperty("getdownappdir");
606 if (appdirString != null && appdirString.length() > 0)
608 final File appdir = new File(appdirString);
614 LaunchUtil.upgradeGetdown(
615 new File(appdir, "getdown-launcher-old.jar"),
616 new File(appdir, "getdown-launcher.jar"),
617 new File(appdir, "getdown-launcher-new.jar"));
622 // completed one way or another
623 // extract groovy argument and execute if necessary
624 groovyscript = aparser.getValue("groovy", true);
627 String file = aparser.getValue("open", true);
629 if (!isJS && file == null && desktop == null)
631 System.out.println("No files to open!");
634 setDisplayParameters(aparser);
636 // time to open a file.
638 DataSourceType protocol = null;
639 FileLoader fileLoader = new FileLoader(!headless);
640 FileFormatI format = null;
641 // Finally, deal with the remaining input data.
642 AlignFrame af = null;
644 JalviewJSApp jsApp = (isJS ? new JalviewJSApp(this, aparser) : null);
650 // JalviewJS allows sequence1 sequence2 ....
653 else if (!headless && Cache.getDefault("SHOW_STARTUP_FILE", true))
660 file = Cache.getDefault("STARTUP_FILE",
661 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
662 + "/examples/exampleFile_2_7.jvp");
663 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
665 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
667 file.replace("http:", "https:");
668 // hardwire upgrade of the startup file
669 file.replace("_2_3", "_2_7");
670 file.replace("2_7.jar", "2_7.jvp");
671 // and remove the stale setting
672 Cache.removeProperty("STARTUP_FILE");
675 protocol = AppletFormatAdapter.checkProtocol(file);
677 if (file.endsWith(".jar"))
679 format = FileFormat.Jalview;
685 format = new IdentifyFile().identify(file, protocol);
686 } catch (FileFormatException e)
692 af = fileLoader.LoadFileWaitTillLoaded(file, protocol, format);
699 desktop.setProgressBar(
701 .getString("status.processing_commandline_args"),
702 progress = System.currentTimeMillis());
704 System.out.println("CMD [-open " + file + "] executed successfully!");
706 if (!Platform.isJS())
708 * ignore in JavaScript -- can't just file existence - could load it?
713 if (!HttpUtils.startsWithHttpOrHttps(file))
715 if (!(new File(file)).exists())
717 System.out.println("Can't find " + file);
726 // JS Only argument to provide a format parameter to specify what format to use
727 String fileFormat = (isJS
728 ? (String) aparser.getAppletValue("format", null, true)
730 protocol = AppletFormatAdapter.checkProtocol(file);
734 format = (fileFormat != null
735 ? FileFormats.getInstance().forName(fileFormat)
739 format = new IdentifyFile().identify(file, protocol);
741 } catch (FileFormatException e1)
746 af = new FileLoader(!headless).LoadFileWaitTillLoaded(file, protocol,
750 System.out.println("jalview error - AlignFrame was not created");
755 // JalviewLite interface for JavaScript allows second file open
756 String file2 = aparser.getValue(ArgsParser.OPEN2, true);
759 protocol = AppletFormatAdapter.checkProtocol(file2);
762 format = new IdentifyFile().identify(file2, protocol);
763 } catch (FileFormatException e1)
767 AlignFrame af2 = new FileLoader(!headless)
768 .LoadFileWaitTillLoaded(file2, protocol, format);
771 System.out.println("error");
775 AlignViewport.openLinkedAlignmentAs(af,
776 af.getViewport().getAlignment(),
777 af2.getViewport().getAlignment(), "",
778 AlignViewport.SPLIT_FRAME);
780 "CMD [-open2 " + file2 + "] executed successfully!");
783 // af is loaded - so set it as current frame
784 setCurrentAlignFrame(af);
786 setFrameDependentProperties(aparser, af);
790 jsApp.initFromParams(af);
799 if (groovyscript != null)
801 // Execute the groovy script after we've done all the rendering
803 // and before any images or figures are generated.
804 System.out.println("Executing script " + groovyscript);
805 executeGroovyScript(groovyscript, af);
806 System.out.println("CMD groovy[" + groovyscript
807 + "] executed successfully!");
811 if (!isJS || !isStartup) {
812 createOutputFiles(aparser, format);
817 af.getViewport().getCalcManager().shutdown();
820 // extract groovy arguments before anything else.
821 // Once all other stuff is done, execute any groovy scripts (in order)
822 if (!isJS && groovyscript != null)
824 if (Cache.groovyJarsPresent())
826 // TODO: DECIDE IF THIS SECOND PASS AT GROOVY EXECUTION IS STILL REQUIRED !!
827 System.out.println("Executing script " + groovyscript);
828 executeGroovyScript(groovyscript, af);
829 System.out.println("CMD groovy[" + groovyscript
830 + "] executed successfully!");
836 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
841 // and finally, turn off batch mode indicator - if the desktop still exists
846 desktop.setProgressBar(null, progress);
848 desktop.setInBatchMode(false);
852 jsApp.callInitCallback();
857 * Set general display parameters irrespective of file loading or headlessness.
861 private void setDisplayParameters(ArgsParser aparser)
863 if (aparser.contains(ArgsParser.NOMENUBAR))
866 System.out.println("CMD [nomenu] executed successfully!");
869 if (aparser.contains(ArgsParser.NOSTATUS))
872 System.out.println("CMD [nostatus] executed successfully!");
875 if (aparser.contains(ArgsParser.NOANNOTATION)
876 || aparser.contains(ArgsParser.NOANNOTATION2))
879 System.out.println("CMD no-annotation executed successfully!");
881 if (aparser.contains(ArgsParser.NOCALCULATION))
883 noCalculation = true;
884 System.out.println("CMD [nocalculation] executed successfully!");
888 private void setFrameDependentProperties(ArgsParser aparser,
891 String data = aparser.getValue(ArgsParser.COLOUR, true);
894 data.replaceAll("%20", " ");
896 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
897 af.getViewport(), af.getViewport().getAlignment(), data);
902 "CMD [-color " + data + "] executed successfully!");
907 // Must maintain ability to use the groups flag
908 data = aparser.getValue(ArgsParser.GROUPS, true);
911 af.parseFeaturesFile(data,
912 AppletFormatAdapter.checkProtocol(data));
913 // System.out.println("Added " + data);
915 "CMD groups[-" + data + "] executed successfully!");
917 data = aparser.getValue(ArgsParser.FEATURES, true);
920 af.parseFeaturesFile(data,
921 AppletFormatAdapter.checkProtocol(data));
922 // System.out.println("Added " + data);
924 "CMD [-features " + data + "] executed successfully!");
926 data = aparser.getValue(ArgsParser.ANNOTATIONS, true);
929 af.loadJalviewDataFile(data, null, null, null);
930 // System.out.println("Added " + data);
932 "CMD [-annotations " + data + "] executed successfully!");
935 // JavaScript feature
937 if (aparser.contains(ArgsParser.SHOWOVERVIEW))
939 af.overviewMenuItem_actionPerformed(null);
940 System.out.println("CMD [showoverview] executed successfully!");
943 // set or clear the sortbytree flag.
944 if (aparser.contains(ArgsParser.SORTBYTREE))
946 af.getViewport().setSortByTree(true);
947 if (af.getViewport().getSortByTree())
949 System.out.println("CMD [-sortbytree] executed successfully!");
953 boolean doUpdateAnnotation = false;
955 * we do this earlier in JalviewJS because of a complication with
958 * For now, just fixing this in JalviewJS.
967 af.getViewport().setShowAnnotation(false);
968 if (!af.getViewport().isShowAnnotation())
970 doUpdateAnnotation = true;
976 if (aparser.contains(ArgsParser.NOSORTBYTREE))
978 af.getViewport().setSortByTree(false);
979 if (!af.getViewport().getSortByTree())
981 doUpdateAnnotation = true;
983 .println("CMD [-nosortbytree] executed successfully!");
986 if (doUpdateAnnotation)
988 af.setMenusForViewport();
989 af.alignPanel.updateLayout();
992 data = aparser.getValue(ArgsParser.TREE, true);
997 NewickFile nf = new NewickFile(data,
998 AppletFormatAdapter.checkProtocol(data));
1000 .setCurrentTree(af.showNewickTree(nf, data).getTree());
1002 "CMD [-tree " + data + "] executed successfully!");
1003 } catch (IOException ex)
1005 System.err.println("Couldn't add tree " + data);
1006 ex.printStackTrace(System.err);
1009 // TODO - load PDB structure(s) to alignment JAL-629
1010 // (associate with identical sequence in alignment, or a specified
1016 * Writes an output file for each format (if any) specified in the
1017 * command-line arguments. Supported formats are currently
1026 * A format parameter should be followed by a parameter specifying the output
1027 * file name. {@code imgMap} parameters should follow those for the
1028 * corresponding alignment image output.
1033 private void createOutputFiles(ArgsParser aparser, FileFormatI format)
1035 // logic essentially the same as 2.11.2/2.11.3 but uses a switch instead
1036 AlignFrame af = currentAlignFrame;
1037 while (aparser.getSize() >= 2)
1039 String outputFormat = aparser.nextValue();
1042 switch (outputFormat.toLowerCase(Locale.ROOT))
1045 imageFile = new File(aparser.nextValue());
1046 af.createPNG(imageFile);
1048 "Creating PNG image: " + imageFile.getAbsolutePath());
1051 imageFile = new File(aparser.nextValue());
1052 af.createSVG(imageFile);
1054 "Creating SVG image: " + imageFile.getAbsolutePath());
1057 imageFile = new File(aparser.nextValue());
1059 "Creating EPS file: " + imageFile.getAbsolutePath());
1060 af.createEPS(imageFile);
1063 fname = new File(aparser.nextValue()).getAbsolutePath();
1066 BioJsHTMLOutput.refreshVersionInfo(
1067 BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
1068 } catch (URISyntaxException e)
1070 e.printStackTrace();
1072 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
1073 bjs.exportHTML(fname);
1074 System.out.println("Creating BioJS MSA Viwer HTML file: " + fname);
1077 fname = new File(aparser.nextValue()).getAbsolutePath();
1078 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
1079 htmlSVG.exportHTML(fname);
1080 System.out.println("Creating HTML image: " + fname);
1083 imageFile = new File(aparser.nextValue());
1084 af.alignPanel.makePNGImageMap(imageFile, "unnamed.png");
1086 "Creating image map: " + imageFile.getAbsolutePath());
1089 // fall through - try to parse as an alignment data export format
1090 FileFormatI outFormat = null;
1093 outFormat = FileFormats.getInstance().forName(outputFormat);
1094 } catch (Exception formatP)
1097 if (outFormat == null)
1099 System.out.println("Couldn't parse " + outputFormat
1100 + " as a valid Jalview format string.");
1103 if (!outFormat.isWritable())
1106 "This version of Jalview does not support alignment export as "
1110 // record file as it was passed to Jalview so it is recognisable to the CLI
1113 fname = new File(file = aparser.nextValue()).getAbsolutePath();
1114 // JBPNote - yuck - really wish we did have a bean returned from this which gave
1115 // success/fail like before !
1116 af.saveAlignment(fname, outFormat);
1117 if (!af.isSaveAlignmentSuccessful())
1119 System.out.println("Written alignment in " + outputFormat
1120 + " format to " + file);
1125 System.out.println("Error writing file " + file + " in "
1126 + outputFormat + " format!!");
1130 // ??? Should report - 'ignoring' extra args here...
1131 while (aparser.getSize() > 0)
1133 System.out.println("Ignoring extra argument: " + aparser.nextValue());
1137 private static void setLookAndFeel()
1139 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
1141 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
1142 // try Quaqua/Vaqua.
1143 String lafProp = System.getProperty("laf");
1144 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
1145 String laf = "none";
1146 if (lafProp != null)
1150 else if (lafSetting != null)
1154 boolean lafSet = false;
1157 case "crossplatform":
1158 lafSet = setCrossPlatformLookAndFeel();
1161 Console.error("Could not set requested laf=" + laf);
1165 lafSet = setSystemLookAndFeel();
1168 Console.error("Could not set requested laf=" + laf);
1172 lafSet = setGtkLookAndFeel();
1175 Console.error("Could not set requested laf=" + laf);
1179 lafSet = setMetalLookAndFeel();
1182 Console.error("Could not set requested laf=" + laf);
1186 lafSet = setNimbusLookAndFeel();
1189 Console.error("Could not set requested laf=" + laf);
1193 lafSet = setFlatLookAndFeel();
1196 Console.error("Could not set requested laf=" + laf);
1200 lafSet = setQuaquaLookAndFeel();
1203 Console.error("Could not set requested laf=" + laf);
1207 lafSet = setVaquaLookAndFeel();
1210 Console.error("Could not set requested laf=" + laf);
1214 lafSet = setMacLookAndFeel();
1217 Console.error("Could not set requested laf=" + laf);
1223 Console.error("Requested laf=" + laf + " not implemented");
1227 setSystemLookAndFeel();
1228 if (Platform.isLinux())
1230 setMetalLookAndFeel();
1232 if (Platform.isMac())
1234 setMacLookAndFeel();
1239 private static boolean setCrossPlatformLookAndFeel()
1241 boolean set = false;
1244 UIManager.setLookAndFeel(
1245 UIManager.getCrossPlatformLookAndFeelClassName());
1247 } catch (Exception ex)
1249 Console.error("Unexpected Look and Feel Exception");
1250 Console.error(ex.getMessage());
1251 Console.debug(Cache.getStackTraceString(ex));
1256 private static boolean setSystemLookAndFeel()
1258 boolean set = false;
1261 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1263 } catch (Exception ex)
1265 Console.error("Unexpected Look and Feel Exception");
1266 Console.error(ex.getMessage());
1267 Console.debug(Cache.getStackTraceString(ex));
1272 private static boolean setSpecificLookAndFeel(String name,
1273 String className, boolean nameStartsWith)
1275 boolean set = false;
1278 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1280 if (info.getName() != null && nameStartsWith
1281 ? info.getName().toLowerCase(Locale.ROOT)
1282 .startsWith(name.toLowerCase(Locale.ROOT))
1283 : info.getName().toLowerCase(Locale.ROOT)
1284 .equals(name.toLowerCase(Locale.ROOT)))
1286 className = info.getClassName();
1290 UIManager.setLookAndFeel(className);
1292 } catch (Exception ex)
1294 Console.error("Unexpected Look and Feel Exception");
1295 Console.error(ex.getMessage());
1296 Console.debug(Cache.getStackTraceString(ex));
1301 private static boolean setGtkLookAndFeel()
1303 return setSpecificLookAndFeel("gtk",
1304 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1307 private static boolean setMetalLookAndFeel()
1309 return setSpecificLookAndFeel("metal",
1310 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1313 private static boolean setNimbusLookAndFeel()
1315 return setSpecificLookAndFeel("nimbus",
1316 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1319 private static boolean setFlatLookAndFeel()
1321 boolean set = setSpecificLookAndFeel("flatlaf light",
1322 "com.formdev.flatlaf.FlatLightLaf", false);
1325 if (Platform.isMac())
1327 System.setProperty("apple.laf.useScreenMenuBar", "true");
1328 System.setProperty("apple.awt.application.name",
1329 ChannelProperties.getProperty("app_name"));
1330 System.setProperty("apple.awt.application.appearance", "system");
1331 if (SystemInfo.isMacFullWindowContentSupported
1332 && Desktop.getInstance() != null)
1334 Desktop.getInstance().getRootPane()
1335 .putClientProperty("apple.awt.fullWindowContent", true);
1336 Desktop.getInstance().getRootPane()
1337 .putClientProperty("apple.awt.transparentTitleBar", true);
1340 SwingUtilities.invokeLater(() -> {
1341 FlatLightLaf.setup();
1345 UIManager.put("TabbedPane.showTabSeparators", true);
1346 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1347 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1348 // UIManager.put("TabbedPane.hasFullBorder", true);
1349 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1350 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1351 UIManager.put("TabbedPane.smoothScrolling", true);
1352 UIManager.put("TabbedPane.tabWidthMode", "compact");
1353 UIManager.put("TabbedPane.selectedBackground", Color.white);
1357 private static boolean setQuaquaLookAndFeel()
1359 return setSpecificLookAndFeel("quaqua",
1360 ch.randelshofer.quaqua.QuaquaManager.getLookAndFeel().getClass()
1365 private static boolean setVaquaLookAndFeel()
1367 return setSpecificLookAndFeel("vaqua",
1368 "org.violetlib.aqua.AquaLookAndFeel", false);
1371 private static boolean setMacLookAndFeel()
1373 boolean set = false;
1374 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1375 ChannelProperties.getProperty("app_name"));
1376 System.setProperty("apple.laf.useScreenMenuBar", "true");
1378 * broken native LAFs on (ARM?) macbooks
1379 set = setQuaquaLookAndFeel();
1380 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1381 .toLowerCase(Locale.ROOT).contains("quaqua"))
1383 set = setVaquaLookAndFeel();
1386 set = setFlatLookAndFeel();
1390 private static void showUsage()
1393 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1394 + "-nodisplay\tRun Jalview without User Interface.\n"
1395 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1396 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1397 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1398 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1399 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1400 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1401 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1402 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1403 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1404 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1405 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1406 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1407 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1408 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1409 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1410 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1411 + "-html FILE\tCreate HTML file from alignment.\n"
1412 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1413 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1414 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1415 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1416 + "-noquestionnaire\tTurn off questionnaire check.\n"
1417 + "-nonews\tTurn off check for Jalview news.\n"
1418 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1419 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1421 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1422 // after all other properties files have been read\n\t
1423 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1424 // passed in correctly)"
1425 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1426 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1427 + "-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"
1428 + "-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"
1429 + "-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"
1430 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1433 private static void startUsageStats(final Desktop desktop)
1436 * start a User Config prompt asking if we can log usage statistics.
1438 PromptUserConfig prompter = new PromptUserConfig(Desktop.getDesktopPane(),
1439 "USAGESTATS", "Jalview Usage Statistics",
1440 "Do you want to help make Jalview better by enabling "
1441 + "the collection of usage statistics with Google Analytics ?"
1442 + "\n\n(you can enable or disable usage tracking in the preferences)",
1449 "Initialising googletracker for usage stats.");
1450 Cache.initGoogleTracker();
1451 Console.debug("Tracking enabled.");
1458 Console.debug("Not enabling Google Tracking.");
1461 desktop.addDialogThread(prompter);
1465 * Locate the given string as a file and pass it to the groovy interpreter.
1467 * @param groovyscript
1468 * the script to execute
1469 * @param jalviewContext
1470 * the Jalview Desktop object passed in to the groovy binding as the
1473 private void executeGroovyScript(String groovyscript, AlignFrame af)
1476 * for scripts contained in files
1483 if (groovyscript.trim().equals("STDIN"))
1485 // read from stdin into a tempfile and execute it
1488 tfile = File.createTempFile("jalview", "groovy");
1489 PrintWriter outfile = new PrintWriter(
1490 new OutputStreamWriter(new FileOutputStream(tfile)));
1491 BufferedReader br = new BufferedReader(
1492 new InputStreamReader(System.in));
1494 while ((line = br.readLine()) != null)
1496 outfile.write(line + "\n");
1502 } catch (Exception ex)
1504 System.err.println("Failed to read from STDIN into tempfile "
1505 + ((tfile == null) ? "(tempfile wasn't created)"
1506 : tfile.toString()));
1507 ex.printStackTrace();
1512 sfile = tfile.toURI().toURL();
1513 } catch (Exception x)
1516 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1518 x.printStackTrace();
1526 sfile = new URI(groovyscript).toURL();
1527 } catch (Exception x)
1529 tfile = new File(groovyscript);
1530 if (!tfile.exists())
1532 System.err.println("File '" + groovyscript + "' does not exist.");
1535 if (!tfile.canRead())
1537 System.err.println("File '" + groovyscript + "' cannot be read.");
1540 if (tfile.length() < 1)
1542 System.err.println("File '" + groovyscript + "' is empty.");
1547 sfile = tfile.getAbsoluteFile().toURI().toURL();
1548 } catch (Exception ex)
1550 System.err.println("Failed to create a file URL for "
1551 + tfile.getAbsoluteFile());
1558 Map<String, java.lang.Object> vbinding = new HashMap<>();
1559 vbinding.put("Jalview", this);
1562 vbinding.put("currentAlFrame", af);
1564 Binding gbinding = new Binding(vbinding);
1565 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1566 gse.run(sfile.toString(), gbinding);
1567 if ("STDIN".equals(groovyscript))
1569 // delete temp file that we made -
1570 // only if it was successfully executed
1573 } catch (Exception e)
1575 System.err.println("Exception Whilst trying to execute file " + sfile
1576 + " as a groovy script.");
1577 e.printStackTrace(System.err);
1582 public static boolean isHeadlessMode()
1584 String isheadless = System.getProperty("java.awt.headless");
1585 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1592 public AlignFrame[] getAlignFrames()
1594 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1595 : Desktop.getAlignFrames();
1600 * Quit method delegates to Desktop.quit - unless running in headless mode when
1601 * it just ends the JVM
1605 if (desktop != null)
1615 public static AlignFrame getCurrentAlignFrame()
1617 return Jalview.getInstance().currentAlignFrame;
1620 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1622 Jalview.getInstance().currentAlignFrame = currentAlignFrame;
1625 public void notifyWorker(AlignCalcWorkerI worker, String status)
1627 // System.out.println("Jalview worker " + worker.getClass().getSimpleName()
1632 private static boolean isInteractive = true;
1634 public static boolean isInteractive()
1636 return isInteractive;
1639 public static void setInteractive(boolean tf)