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.OutputStream;
30 import java.io.OutputStreamWriter;
31 import java.io.PrintStream;
32 import java.io.PrintWriter;
33 import java.net.MalformedURLException;
35 import java.net.URISyntaxException;
37 import java.security.AllPermission;
38 import java.security.CodeSource;
39 import java.security.PermissionCollection;
40 import java.security.Permissions;
41 import java.security.Policy;
42 import java.util.ArrayList;
43 import java.util.HashMap;
44 import java.util.List;
45 import java.util.Locale;
47 import java.util.Properties;
48 import java.util.Vector;
49 import java.util.logging.ConsoleHandler;
50 import java.util.logging.Level;
51 import java.util.logging.Logger;
52 import java.util.stream.Collectors;
54 import javax.swing.JDialog;
55 import javax.swing.JFrame;
56 import javax.swing.JInternalFrame;
57 import javax.swing.JOptionPane;
58 import javax.swing.SwingUtilities;
59 import javax.swing.UIManager;
60 import javax.swing.UIManager.LookAndFeelInfo;
61 import javax.swing.UnsupportedLookAndFeelException;
63 import com.formdev.flatlaf.FlatLightLaf;
64 import com.formdev.flatlaf.themes.FlatMacLightLaf;
65 import com.formdev.flatlaf.util.SystemInfo;
66 import com.threerings.getdown.util.LaunchUtil;
68 //import edu.stanford.ejalbert.launching.IBrowserLaunching;
69 import groovy.lang.Binding;
70 import groovy.util.GroovyScriptEngine;
71 import jalview.bin.argparser.Arg;
72 import jalview.bin.argparser.Arg.Opt;
73 import jalview.bin.argparser.Arg.Type;
74 import jalview.bin.argparser.ArgParser;
75 import jalview.bin.argparser.BootstrapArgs;
76 import jalview.ext.so.SequenceOntology;
77 import jalview.gui.AlignFrame;
78 import jalview.gui.Desktop;
79 import jalview.gui.PromptUserConfig;
80 import jalview.gui.QuitHandler;
81 import jalview.gui.QuitHandler.QResponse;
82 import jalview.gui.StructureViewerBase;
83 import jalview.io.AppletFormatAdapter;
84 import jalview.io.BioJsHTMLOutput;
85 import jalview.io.DataSourceType;
86 import jalview.io.FileFormat;
87 import jalview.io.FileFormatException;
88 import jalview.io.FileFormatI;
89 import jalview.io.FileFormats;
90 import jalview.io.FileLoader;
91 import jalview.io.HtmlSvgOutput;
92 import jalview.io.IdentifyFile;
93 import jalview.io.NewickFile;
94 import jalview.io.gff.SequenceOntologyFactory;
95 import jalview.schemes.ColourSchemeI;
96 import jalview.schemes.ColourSchemeProperty;
97 import jalview.util.ChannelProperties;
98 import jalview.util.HttpUtils;
99 import jalview.util.LaunchUtils;
100 import jalview.util.MessageManager;
101 import jalview.util.Platform;
102 import jalview.ws.jws2.Jws2Discoverer;
105 * Main class for Jalview Application <br>
107 * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
108 * jalview.bin.Jalview
110 * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
111 * jalview.bin.Jalview jalview.bin.Jalview
113 * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
114 * embellish '*' to e.g. '*.jar')
117 * @version $Revision$
123 Platform.getURLCommandArguments();
124 Platform.addJ2SDirectDatabaseCall("https://www.jalview.org");
125 Platform.addJ2SDirectDatabaseCall("http://www.jalview.org");
126 Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk");
127 Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk");
131 * singleton instance of this class
133 private static Jalview instance;
135 private Desktop desktop;
137 protected Commands cmds;
139 public static AlignFrame currentAlignFrame;
141 public ArgParser argparser = null;
143 public BootstrapArgs bootstrapArgs = null;
145 private boolean QUIET = false;
147 public static boolean quiet()
149 return Jalview.getInstance() != null && Jalview.getInstance().QUIET;
154 if (!Platform.isJS())
161 // grab all the rights we can for the JVM
162 Policy.setPolicy(new Policy()
165 public PermissionCollection getPermissions(CodeSource codesource)
167 Permissions perms = new Permissions();
168 perms.add(new AllPermission());
173 public void refresh()
181 * keep track of feature fetching tasks.
189 * TODO: generalise to track all jalview events to orchestrate batch processing
193 private int queued = 0;
195 private int running = 0;
197 public FeatureFetcher()
202 public void addFetcher(final AlignFrame af,
203 final Vector<String> dasSources)
205 final long id = System.currentTimeMillis();
207 final FeatureFetcher us = this;
208 new Thread(new Runnable()
220 af.setProgressBar(MessageManager
221 .getString("status.das_features_being_retrived"), id);
222 af.featureSettings_actionPerformed(null);
223 af.setProgressBar(null, id);
232 public synchronized boolean allFinished()
234 return queued == 0 && running == 0;
239 public static Jalview getInstance()
245 * main class for Jalview application
248 * open <em>filename</em>
250 public static void main(String[] args)
252 // setLogging(); // BH - for event debugging in JavaScript
253 instance = new Jalview();
254 instance.doMain(args);
257 private static void logClass(String name)
259 // BH - for event debugging in JavaScript
260 ConsoleHandler consoleHandler = new ConsoleHandler();
261 consoleHandler.setLevel(Level.ALL);
262 Logger logger = Logger.getLogger(name);
263 logger.setLevel(Level.ALL);
264 logger.addHandler(consoleHandler);
267 @SuppressWarnings("unused")
268 private static void setLogging()
276 System.out.println("not in js");
279 // BH - for event debugging in JavaScript (Java mode only)
280 if (!Platform.isJS())
287 Logger.getLogger("").setLevel(Level.ALL);
288 logClass("java.awt.EventDispatchThread");
289 logClass("java.awt.EventQueue");
290 logClass("java.awt.Component");
291 logClass("java.awt.focus.Component");
292 logClass("java.awt.focus.DefaultKeyboardFocusManager");
300 void doMain(String[] args)
302 if (!Platform.isJS())
304 System.setSecurityManager(null);
307 if (args == null || args.length == 0 || (args.length == 1
308 && (args[0] == null || args[0].length() == 0)))
310 args = new String[] {};
313 // get args needed before proper ArgParser
314 bootstrapArgs = BootstrapArgs.getBootstrapArgs(args);
316 if (!Platform.isJS())
318 // are we being --quiet ?
319 if (bootstrapArgs.contains(Arg.QUIET))
322 OutputStream devNull = new OutputStream()
326 public void write(int b)
331 System.setOut(new PrintStream(devNull));
332 // redirecting stderr not working
333 if (bootstrapArgs.getList(Arg.QUIET).size() > 1)
335 System.setErr(new PrintStream(devNull));
339 if (bootstrapArgs.contains(Arg.HELP)
340 || bootstrapArgs.contains(Arg.VERSION))
346 // set individual session preferences
347 if (bootstrapArgs.contains(Arg.P))
349 for (String kev : bootstrapArgs.getValueList(Arg.P))
355 int equalsIndex = kev.indexOf(ArgParser.EQUALS);
356 if (equalsIndex > -1)
358 String key = kev.substring(0, equalsIndex);
359 String val = kev.substring(equalsIndex + 1);
360 Cache.setSessionProperty(key, val);
365 // Move any new getdown-launcher-new.jar into place over old
366 // getdown-launcher.jar
367 String appdirString = System.getProperty("getdownappdir");
368 if (appdirString != null && appdirString.length() > 0)
370 final File appdir = new File(appdirString);
377 LaunchUtil.upgradeGetdown(
378 new File(appdir, "getdown-launcher-old.jar"),
379 new File(appdir, "getdown-launcher.jar"),
380 new File(appdir, "getdown-launcher-new.jar"));
385 if (!quiet() || bootstrapArgs.contains(Arg.VERSION))
388 "Java version: " + System.getProperty("java.version"));
389 System.out.println("Java home: " + System.getProperty("java.home"));
390 System.out.println("Java arch: " + System.getProperty("os.arch") + " "
391 + System.getProperty("os.name") + " "
392 + System.getProperty("os.version"));
394 String val = System.getProperty("sys.install4jVersion");
397 System.out.println("Install4j version: " + val);
399 val = System.getProperty("installer_template_version");
402 System.out.println("Install4j template version: " + val);
404 val = System.getProperty("launcher_version");
407 System.out.println("Launcher version: " + val);
411 if (Platform.isLinux() && LaunchUtils.getJavaVersion() < 11)
413 System.setProperty("flatlaf.uiScale", "1");
416 // get bootstrap properties (mainly for the logger level)
417 Properties bootstrapProperties = Cache
418 .bootstrapProperties(bootstrapArgs.getValue(Arg.PROPS));
420 // report Jalview version
421 Cache.loadBuildProperties(
422 !quiet() || bootstrapArgs.contains(Arg.VERSION));
424 // stop now if only after --version
425 if (bootstrapArgs.contains(Arg.VERSION))
427 Jalview.exit(null, 0);
431 ArgsParser aparser = new ArgsParser(args);
434 boolean headless = false;
436 boolean headlessArg = false;
440 String logLevel = null;
441 if (bootstrapArgs.contains(Arg.TRACE))
445 else if (bootstrapArgs.contains(Arg.DEBUG))
449 if (logLevel == null && !(bootstrapProperties == null))
451 logLevel = bootstrapProperties.getProperty(Cache.JALVIEWLOGLEVEL);
453 Console.initLogger(logLevel);
454 } catch (NoClassDefFoundError error)
456 error.printStackTrace();
457 String message = "\nEssential logging libraries not found."
458 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview";
459 Jalview.exit(message, 0);
462 // register SIGTERM listener
463 Runtime.getRuntime().addShutdownHook(new Thread()
467 Console.debug("Running shutdown hook");
468 QuitHandler.startForceQuit();
469 boolean closeExternal = Cache
470 .getDefault("DEFAULT_CLOSE_EXTERNAL_VIEWERS", false)
471 || Cache.getDefault("ALWAYS_CLOSE_EXTERNAL_VIEWERS", false);
472 StructureViewerBase.setQuitClose(closeExternal);
475 for (JInternalFrame frame : Desktop.desktop.getAllFrames())
477 if (frame instanceof StructureViewerBase)
479 ((StructureViewerBase) frame).closeViewer(closeExternal);
484 if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT)
486 // Got to here by a SIGTERM signal.
487 // Note we will not actually cancel the quit from here -- it's too
488 // late -- but we can wait for saving files and close external viewers
490 // Close viewers/Leave viewers open
491 Console.debug("Checking for saving files");
492 QuitHandler.getQuitResponse(false);
496 Console.debug("Nothing more to do");
498 Console.debug("Exiting, bye!");
499 // shutdownHook cannot be cancelled, JVM will now halt
503 String usrPropsFile = bootstrapArgs.contains(Arg.PROPS)
504 ? bootstrapArgs.getValue(Arg.PROPS)
505 : aparser.getValue("props");
506 // if usrPropsFile == null, loadProperties will use the Channel
508 Cache.loadProperties(usrPropsFile);
509 if (usrPropsFile != null)
512 "CMD [-props " + usrPropsFile + "] executed successfully!");
513 testoutput(bootstrapArgs, Arg.PROPS,
514 "test/jalview/bin/testProps.jvprops", usrPropsFile);
517 // --argfile=... -- OVERRIDES ALL NON-BOOTSTRAP ARGS
518 if (bootstrapArgs.contains(Arg.ARGFILE))
520 argparser = ArgParser.parseArgFiles(
521 bootstrapArgs.getValueList(Arg.ARGFILE),
522 bootstrapArgs.getBoolean(Arg.INITSUBSTITUTIONS),
527 argparser = new ArgParser(args,
528 bootstrapArgs.getBoolean(Arg.INITSUBSTITUTIONS),
532 if (!Platform.isJS())
539 if (bootstrapArgs.contains(Arg.HELP))
541 List<Map.Entry<Type, String>> helpArgs = bootstrapArgs
543 System.out.println(Arg.usage(helpArgs.stream().map(e -> e.getKey())
544 .collect(Collectors.toList())));
545 Jalview.exit(null, 0);
547 if (aparser.contains("help") || aparser.contains("h"))
550 * Now using new usage statement.
553 System.out.println(Arg.usage());
554 Jalview.exit(null, 0);
558 headlessArg = bootstrapArgs.isHeadless();
561 System.setProperty("java.awt.headless", "true");
564 if (aparser.contains("nodisplay") || aparser.contains("nogui")
565 || aparser.contains("headless"))
567 System.setProperty("java.awt.headless", "true");
572 // allow https handshakes to download intermediate certs if necessary
573 System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
575 String jabawsUrl = bootstrapArgs.getValue(Arg.JABAWS);
576 if (jabawsUrl == null)
577 jabawsUrl = aparser.getValue("jabaws");
578 if (jabawsUrl != null)
582 Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
584 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
585 testoutput(bootstrapArgs, Arg.JABAWS,
586 "http://www.compbio.dundee.ac.uk/jabaws", jabawsUrl);
587 } catch (MalformedURLException e)
590 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
595 List<String> setprops = new ArrayList<>();
596 if (bootstrapArgs.contains(Arg.SETPROP))
598 setprops = bootstrapArgs.getValueList(Arg.SETPROP);
602 String sp = aparser.getValue("setprop");
606 sp = aparser.getValue("setprop");
609 for (String setprop : setprops)
611 int p = setprop.indexOf('=');
615 .println("Ignoring invalid setprop argument : " + setprop);
619 System.out.println("Executing setprop argument: " + setprop);
622 Cache.setProperty(setprop.substring(0, p),
623 setprop.substring(p + 1));
625 // DISABLED FOR SECURITY REASONS
626 // TODO: add a property to allow properties to be overriden by cli args
627 // Cache.setProperty(setprop.substring(0,p), setprop.substring(p+1));
630 if (System.getProperty("java.awt.headless") != null
631 && System.getProperty("java.awt.headless").equals("true"))
635 System.setProperty("http.agent",
636 "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
640 Console.initLogger();
643 NoClassDefFoundError error)
645 error.printStackTrace();
646 String message = "\nEssential logging libraries not found."
647 + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview";
648 Jalview.exit(message, 0);
652 if (!(headless || headlessArg))
656 * configure 'full' SO model if preferences say to, else use the default (full SO)
657 * - as JS currently doesn't have OBO parsing, it must use 'Lite' version
659 boolean soDefault = !Platform.isJS();
660 if (Cache.getDefault("USE_FULL_SO", soDefault))
662 SequenceOntologyFactory.setInstance(new SequenceOntology());
665 if (!(headless || headlessArg))
667 Desktop.nosplash = "false".equals(bootstrapArgs.getValue(Arg.SPLASH))
668 || aparser.contains("nosplash")
669 || Cache.getDefault("SPLASH", "true").equals("false");
670 desktop = new Desktop();
671 desktop.setInBatchMode(true); // indicate we are starting up
675 JalviewTaskbar.setTaskbar(this);
676 } catch (Exception e)
678 Console.info("Cannot set Taskbar");
679 Console.error(e.getMessage());
680 // e.printStackTrace();
681 } catch (Throwable t)
683 Console.info("Cannot set Taskbar");
684 Console.error(t.getMessage());
685 // t.printStackTrace();
688 // set Proxy settings before all the internet calls
689 Cache.setProxyPropertiesFromPreferences();
691 desktop.setVisible(true);
693 if (!Platform.isJS())
702 * Check to see that the JVM version being run is suitable for the Java
703 * version this Jalview was compiled for. Popup a warning if not.
705 if (!LaunchUtils.checkJavaVersion())
707 Console.warn("The Java version being used (Java "
708 + LaunchUtils.getJavaVersion()
709 + ") may lead to problems. This installation of Jalview should be used with Java "
710 + LaunchUtils.getJavaCompileVersion() + ".");
713 .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
716 MessageManager.getString("label.continue") };
717 JOptionPane.showOptionDialog(null,
718 MessageManager.formatMessage(
719 "warning.wrong_jvm_version_message",
720 LaunchUtils.getJavaVersion(),
721 LaunchUtils.getJavaCompileVersion()),
723 .getString("warning.wrong_jvm_version_title"),
724 JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
725 null, options, options[0]);
729 boolean webservicediscovery = bootstrapArgs
730 .getBoolean(Arg.WEBSERVICEDISCOVERY);
731 if (aparser.contains("nowebservicediscovery"))
732 webservicediscovery = false;
733 if (webservicediscovery)
735 desktop.startServiceDiscovery();
739 testoutput(argparser, Arg.WEBSERVICEDISCOVERY);
742 boolean usagestats = !bootstrapArgs.getBoolean(Arg.NOUSAGESTATS);
743 if (aparser.contains("nousagestats"))
747 startUsageStats(desktop);
748 testoutput(argparser, Arg.NOUSAGESTATS);
752 System.out.println("CMD [-nousagestats] executed successfully!");
753 testoutput(argparser, Arg.NOUSAGESTATS);
756 boolean questionnaire = bootstrapArgs.getBoolean(Arg.QUESTIONNAIRE);
757 if (aparser.contains("noquestionnaire"))
758 questionnaire = false;
761 String url = aparser.getValue("questionnaire");
764 // Start the desktop questionnaire prompter with the specified
766 Console.debug("Starting questionnaire url at " + url);
767 desktop.checkForQuestionnaire(url);
768 System.out.println("CMD questionnaire[-" + url
769 + "] executed successfully!");
773 if (Cache.getProperty("NOQUESTIONNAIRES") == null)
775 // Start the desktop questionnaire prompter with the specified
778 // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
780 String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl";
782 "Starting questionnaire with default url: " + defurl);
783 desktop.checkForQuestionnaire(defurl);
790 .println("CMD [-noquestionnaire] executed successfully!");
791 testoutput(argparser, Arg.QUESTIONNAIRE);
794 if ((!aparser.contains("nonews")
795 && Cache.getProperty("NONEWS") == null
796 && !"false".equals(bootstrapArgs.getValue(Arg.NEWS)))
797 || "true".equals(bootstrapArgs.getValue(Arg.NEWS)))
799 desktop.checkForNews();
802 if (!aparser.contains("nohtmltemplates")
803 && Cache.getProperty("NOHTMLTEMPLATES") == null)
805 BioJsHTMLOutput.updateBioJS();
809 // Run Commands from cli
810 cmds = new Commands(argparser, headlessArg);
811 boolean commandsSuccess = cmds.argsWereParsed();
816 if (argparser.getBoolean(Arg.NOQUIT))
819 "Completed " + Arg.HEADLESS.getName() + " commands, but "
820 + Arg.NOQUIT + " is set so not quitting!");
824 Jalview.exit("Successfully completed commands in headless mode",
828 Console.info("Successfully completed commands");
834 Jalview.exit("Error when running Commands in headless mode", 1);
836 Console.warn("Error when running commands");
839 // Check if JVM and compile version might cause problems and log if it
841 if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
843 Console.warn("The Java version being used (Java "
844 + LaunchUtils.getJavaVersion()
845 + ") may lead to problems. This installation of Jalview should be used with Java "
846 + LaunchUtils.getJavaCompileVersion() + ".");
849 String file = null, data = null;
851 FileFormatI format = null;
853 DataSourceType protocol = null;
855 FileLoader fileLoader = new FileLoader(!headless);
857 String groovyscript = null; // script to execute after all loading is
858 // completed one way or another
859 // extract groovy argument and execute if necessary
860 groovyscript = aparser.getValue("groovy", true);
861 file = aparser.getValue("open", true);
863 if (file == null && desktop == null && !commandsSuccess)
865 Jalview.exit("No files to open!", 1);
869 // Finally, deal with the remaining input data.
874 desktop.setProgressBar(
876 .getString("status.processing_commandline_args"),
877 progress = System.currentTimeMillis());
879 System.out.println("CMD [-open " + file + "] executed successfully!");
881 if (!Platform.isJS())
883 * ignore in JavaScript -- can't just file existence - could load it?
888 if (!HttpUtils.startsWithHttpOrHttps(file))
890 if (!(new File(file)).exists())
895 "Can't find file '" + file + "' in headless mode", 1);
897 Console.warn("Can't find file'" + file + "'");
902 protocol = AppletFormatAdapter.checkProtocol(file);
906 format = new IdentifyFile().identify(file, protocol);
907 } catch (FileFormatException e1)
912 AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
916 System.out.println("error");
920 setCurrentAlignFrame(af);
921 data = aparser.getValue("colour", true);
924 data.replaceAll("%20", " ");
926 ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
927 af.getViewport(), af.getViewport().getAlignment(), data);
932 "CMD [-colour " + data + "] executed successfully!");
937 // Must maintain ability to use the groups flag
938 data = aparser.getValue("groups", true);
941 af.parseFeaturesFile(data,
942 AppletFormatAdapter.checkProtocol(data));
943 // System.out.println("Added " + data);
945 "CMD groups[-" + data + "] executed successfully!");
947 data = aparser.getValue("features", true);
950 af.parseFeaturesFile(data,
951 AppletFormatAdapter.checkProtocol(data));
952 // System.out.println("Added " + data);
954 "CMD [-features " + data + "] executed successfully!");
957 data = aparser.getValue("annotations", true);
960 af.loadJalviewDataFile(data, null, null, null);
961 // System.out.println("Added " + data);
963 "CMD [-annotations " + data + "] executed successfully!");
965 // set or clear the sortbytree flag.
966 if (aparser.contains("sortbytree"))
968 af.getViewport().setSortByTree(true);
969 if (af.getViewport().getSortByTree())
971 System.out.println("CMD [-sortbytree] executed successfully!");
974 if (aparser.contains("no-annotation"))
976 af.getViewport().setShowAnnotation(false);
977 if (!af.getViewport().isShowAnnotation())
979 System.out.println("CMD no-annotation executed successfully!");
982 if (aparser.contains("nosortbytree"))
984 af.getViewport().setSortByTree(false);
985 if (!af.getViewport().getSortByTree())
988 .println("CMD [-nosortbytree] executed successfully!");
991 data = aparser.getValue("tree", true);
997 "CMD [-tree " + data + "] executed successfully!");
998 NewickFile nf = new NewickFile(data,
999 AppletFormatAdapter.checkProtocol(data));
1001 .setCurrentTree(af.showNewickTree(nf, data).getTree());
1002 } catch (IOException ex)
1004 System.err.println("Couldn't add tree " + data);
1005 ex.printStackTrace(System.err);
1008 // TODO - load PDB structure(s) to alignment JAL-629
1009 // (associate with identical sequence in alignment, or a specified
1011 if (groovyscript != null)
1013 // Execute the groovy script after we've done all the rendering stuff
1014 // and before any images or figures are generated.
1015 System.out.println("Executing script " + groovyscript);
1016 executeGroovyScript(groovyscript, af);
1017 System.out.println("CMD groovy[" + groovyscript
1018 + "] executed successfully!");
1019 groovyscript = null;
1021 String imageName = "unnamed.png";
1022 while (aparser.getSize() > 1)
1024 String outputFormat = aparser.nextValue();
1025 file = aparser.nextValue();
1027 if (outputFormat.equalsIgnoreCase("png"))
1029 af.createPNG(new File(file));
1030 imageName = (new File(file)).getName();
1031 System.out.println("Creating PNG image: " + file);
1034 else if (outputFormat.equalsIgnoreCase("svg"))
1036 File imageFile = new File(file);
1037 imageName = imageFile.getName();
1038 af.createSVG(imageFile);
1039 System.out.println("Creating SVG image: " + file);
1042 else if (outputFormat.equalsIgnoreCase("html"))
1044 File imageFile = new File(file);
1045 imageName = imageFile.getName();
1046 HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
1047 htmlSVG.exportHTML(file);
1049 System.out.println("Creating HTML image: " + file);
1052 else if (outputFormat.equalsIgnoreCase("biojsmsa"))
1056 System.err.println("The output html file must not be null");
1061 BioJsHTMLOutput.refreshVersionInfo(
1062 BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
1063 } catch (URISyntaxException e)
1065 e.printStackTrace();
1067 BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
1068 bjs.exportHTML(file);
1070 .println("Creating BioJS MSA Viwer HTML file: " + file);
1073 else if (outputFormat.equalsIgnoreCase("imgMap"))
1075 af.createImageMap(new File(file), imageName);
1076 System.out.println("Creating image map: " + file);
1079 else if (outputFormat.equalsIgnoreCase("eps"))
1081 File outputFile = new File(file);
1083 "Creating EPS file: " + outputFile.getAbsolutePath());
1084 af.createEPS(outputFile);
1087 FileFormatI outFormat = null;
1090 outFormat = FileFormats.getInstance().forName(outputFormat);
1091 } catch (Exception formatP)
1093 System.out.println("Couldn't parse " + outFormat
1094 + " as a valid Jalview format string.");
1096 if (outFormat != null)
1098 if (!outFormat.isWritable())
1101 "This version of Jalview does not support alignment export as "
1106 af.saveAlignment(file, outFormat);
1107 if (af.isSaveAlignmentSuccessful())
1109 System.out.println("Written alignment in "
1110 + outFormat.getName() + " format to " + file);
1114 System.out.println("Error writing file " + file + " in "
1115 + outFormat.getName() + " format!!");
1122 while (aparser.getSize() > 0)
1124 System.out.println("Unknown arg: " + aparser.nextValue());
1129 AlignFrame startUpAlframe = null;
1130 // We'll only open the default file if the desktop is visible.
1132 // ////////////////////
1134 if (!Platform.isJS() && !headless && file == null
1135 && Cache.getDefault("SHOW_STARTUP_FILE", true)
1136 && !cmds.commandArgsProvided()
1137 && !bootstrapArgs.getBoolean(Arg.NOSTARTUPFILE))
1138 // don't open the startup file if command line args have been processed
1139 // (&& !Commands.commandArgsProvided())
1146 file = Cache.getDefault("STARTUP_FILE",
1147 Cache.getDefault("www.jalview.org", "https://www.jalview.org")
1148 + "/examples/exampleFile_2_7.jvp");
1149 if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar")
1151 "http://www.jalview.org/examples/exampleFile_2_7.jar"))
1153 file.replace("http:", "https:");
1154 // hardwire upgrade of the startup file
1155 file.replace("_2_3", "_2_7");
1156 file.replace("2_7.jar", "2_7.jvp");
1157 // and remove the stale setting
1158 Cache.removeProperty("STARTUP_FILE");
1161 protocol = AppletFormatAdapter.checkProtocol(file);
1163 if (file.endsWith(".jar"))
1165 format = FileFormat.Jalview;
1171 format = new IdentifyFile().identify(file, protocol);
1172 } catch (FileFormatException e)
1178 startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
1180 // don't ask to save when quitting if only the startup file has been
1182 Console.debug("Resetting up-to-date flag for startup file");
1183 startUpAlframe.getViewport().setSavedUpToDate(true);
1184 // extract groovy arguments before anything else.
1187 // Once all other stuff is done, execute any groovy scripts (in order)
1188 if (groovyscript != null)
1190 if (Cache.groovyJarsPresent())
1192 System.out.println("Executing script " + groovyscript);
1193 executeGroovyScript(groovyscript, startUpAlframe);
1198 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
1202 // and finally, turn off batch mode indicator - if the desktop still exists
1203 if (desktop != null)
1207 desktop.setProgressBar(null, progress);
1209 desktop.setInBatchMode(false);
1213 private static void setLookAndFeel()
1215 // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
1217 // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
1218 // try Quaqua/Vaqua.
1219 String lafProp = System.getProperty("laf");
1220 String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
1221 String laf = "none";
1222 if (lafProp != null)
1226 else if (lafSetting != null)
1230 boolean lafSet = false;
1233 case "crossplatform":
1234 lafSet = setCrossPlatformLookAndFeel();
1237 Console.error("Could not set requested laf=" + laf);
1241 lafSet = setSystemLookAndFeel();
1244 Console.error("Could not set requested laf=" + laf);
1248 lafSet = setGtkLookAndFeel();
1251 Console.error("Could not set requested laf=" + laf);
1255 lafSet = setMetalLookAndFeel();
1258 Console.error("Could not set requested laf=" + laf);
1262 lafSet = setNimbusLookAndFeel();
1265 Console.error("Could not set requested laf=" + laf);
1269 lafSet = setFlatLookAndFeel();
1272 Console.error("Could not set requested laf=" + laf);
1276 lafSet = setMacLookAndFeel();
1279 Console.error("Could not set requested laf=" + laf);
1285 Console.error("Requested laf=" + laf + " not implemented");
1289 // Flatlaf default for everyone!
1290 lafSet = setFlatLookAndFeel();
1293 setSystemLookAndFeel();
1295 if (Platform.isLinux())
1297 setLinuxLookAndFeel();
1299 if (Platform.isMac())
1301 setMacLookAndFeel();
1306 private static boolean setCrossPlatformLookAndFeel()
1308 boolean set = false;
1311 UIManager.setLookAndFeel(
1312 UIManager.getCrossPlatformLookAndFeelClassName());
1314 } catch (Exception ex)
1316 Console.error("Unexpected Look and Feel Exception");
1317 Console.error(ex.getMessage());
1318 Console.debug(Cache.getStackTraceString(ex));
1323 private static boolean setSystemLookAndFeel()
1325 boolean set = false;
1328 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
1330 } catch (Exception ex)
1332 Console.error("Unexpected Look and Feel Exception");
1333 Console.error(ex.getMessage());
1334 Console.debug(Cache.getStackTraceString(ex));
1339 private static boolean setSpecificLookAndFeel(String name,
1340 String className, boolean nameStartsWith)
1342 boolean set = false;
1345 for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
1347 if (info.getName() != null && nameStartsWith
1348 ? info.getName().toLowerCase(Locale.ROOT)
1349 .startsWith(name.toLowerCase(Locale.ROOT))
1350 : info.getName().toLowerCase(Locale.ROOT)
1351 .equals(name.toLowerCase(Locale.ROOT)))
1353 className = info.getClassName();
1357 UIManager.setLookAndFeel(className);
1359 } catch (Exception ex)
1361 Console.error("Unexpected Look and Feel Exception");
1362 Console.error(ex.getMessage());
1363 Console.debug(Cache.getStackTraceString(ex));
1368 private static boolean setGtkLookAndFeel()
1370 return setSpecificLookAndFeel("gtk",
1371 "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
1374 private static boolean setMetalLookAndFeel()
1376 return setSpecificLookAndFeel("metal",
1377 "javax.swing.plaf.metal.MetalLookAndFeel", false);
1380 private static boolean setNimbusLookAndFeel()
1382 return setSpecificLookAndFeel("nimbus",
1383 "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
1386 private static boolean setFlatLookAndFeel()
1388 boolean set = false;
1389 if (SystemInfo.isMacOS)
1393 UIManager.setLookAndFeel(
1394 "com.formdev.flatlaf.themes.FlatMacLightLaf");
1396 Console.debug("Using FlatMacLightLaf");
1397 } catch (ClassNotFoundException | InstantiationException
1398 | IllegalAccessException | UnsupportedLookAndFeelException e)
1400 Console.debug("Exception loading FlatLightLaf", e);
1402 System.setProperty("apple.laf.useScreenMenuBar", "true");
1403 System.setProperty("apple.awt.application.name",
1404 ChannelProperties.getProperty("app_name"));
1405 System.setProperty("apple.awt.application.appearance", "system");
1406 if (SystemInfo.isMacFullWindowContentSupported
1407 && Desktop.desktop != null)
1409 Console.debug("Setting transparent title bar");
1410 Desktop.desktop.getRootPane()
1411 .putClientProperty("apple.awt.fullWindowContent", true);
1412 Desktop.desktop.getRootPane()
1413 .putClientProperty("apple.awt.transparentTitleBar", true);
1414 Desktop.desktop.getRootPane()
1415 .putClientProperty("apple.awt.fullscreenable", true);
1417 SwingUtilities.invokeLater(() -> {
1418 FlatMacLightLaf.setup();
1420 Console.debug("Using FlatMacLightLaf");
1427 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1429 Console.debug("Using FlatLightLaf");
1430 } catch (ClassNotFoundException | InstantiationException
1431 | IllegalAccessException | UnsupportedLookAndFeelException e)
1433 Console.debug("Exception loading FlatLightLaf", e);
1435 // Windows specific properties here
1436 SwingUtilities.invokeLater(() -> {
1437 FlatLightLaf.setup();
1439 Console.debug("Using FlatLightLaf");
1442 else if (SystemInfo.isLinux)
1446 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1448 Console.debug("Using FlatLightLaf");
1449 } catch (ClassNotFoundException | InstantiationException
1450 | IllegalAccessException | UnsupportedLookAndFeelException e)
1452 Console.debug("Exception loading FlatLightLaf", e);
1454 // enable custom window decorations
1455 JFrame.setDefaultLookAndFeelDecorated(true);
1456 JDialog.setDefaultLookAndFeelDecorated(true);
1457 SwingUtilities.invokeLater(() -> {
1458 FlatLightLaf.setup();
1460 Console.debug("Using FlatLightLaf");
1468 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
1470 Console.debug("Using FlatLightLaf");
1471 } catch (ClassNotFoundException | InstantiationException
1472 | IllegalAccessException | UnsupportedLookAndFeelException e)
1474 Console.debug("Exception loading FlatLightLaf", e);
1480 UIManager.put("TabbedPane.tabType", "card");
1481 UIManager.put("TabbedPane.showTabSeparators", true);
1482 UIManager.put("TabbedPane.showContentSeparator", true);
1483 UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
1484 UIManager.put("TabbedPane.tabsOverlapBorder", true);
1485 UIManager.put("TabbedPane.hasFullBorder", true);
1486 UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
1487 UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
1488 UIManager.put("TabbedPane.smoothScrolling", true);
1489 UIManager.put("TabbedPane.tabWidthMode", "compact");
1490 UIManager.put("TabbedPane.selectedBackground", Color.white);
1491 UIManager.put("TabbedPane.background", new Color(236, 236, 236));
1492 UIManager.put("TabbedPane.hoverColor", Color.lightGray);
1495 Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
1499 private static boolean setMacLookAndFeel()
1501 boolean set = false;
1502 System.setProperty("com.apple.mrj.application.apple.menu.about.name",
1503 ChannelProperties.getProperty("app_name"));
1504 System.setProperty("apple.laf.useScreenMenuBar", "true");
1506 * broken native LAFs on (ARM?) macbooks
1507 set = setQuaquaLookAndFeel();
1508 if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
1509 .toLowerCase(Locale.ROOT).contains("quaqua"))
1511 set = setVaquaLookAndFeel();
1514 set = setFlatLookAndFeel();
1518 private static boolean setLinuxLookAndFeel()
1520 boolean set = false;
1521 set = setFlatLookAndFeel();
1523 set = setMetalLookAndFeel();
1524 // avoid GtkLookAndFeel -- not good results especially on HiDPI
1526 set = setNimbusLookAndFeel();
1531 private static void showUsage()
1534 "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1535 + "-nodisplay\tRun Jalview without User Interface.\n"
1536 + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1537 + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1538 + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1539 + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1540 + "-features FILE\tUse the given file to mark features on the alignment.\n"
1541 + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1542 + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1543 + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1544 + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1545 + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1546 + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1547 + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1548 + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1549 + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1550 + "-png FILE\tCreate PNG image FILE from alignment.\n"
1551 + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1552 + "-html FILE\tCreate HTML file from alignment.\n"
1553 + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1554 + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1555 + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1556 + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1557 + "-noquestionnaire\tTurn off questionnaire check.\n"
1558 + "-nonews\tTurn off check for Jalview news.\n"
1559 + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1560 + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1562 // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1563 // after all other properties files have been read\n\t
1564 // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1565 // passed in correctly)"
1566 + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1567 + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1568 + "-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"
1569 + "-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"
1570 + "-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"
1571 + "\n~Read documentation in Application or visit https://www.jalview.org for description of Features and Annotations file~\n\n");
1575 private static void startUsageStats(final Desktop desktop)
1578 * start a User Config prompt asking if we can log usage statistics.
1580 PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
1581 "USAGESTATS", "Jalview Usage Statistics",
1582 "Do you want to help make Jalview better by enabling "
1583 + "the collection of usage statistics with Google Analytics ?"
1584 + "\n\n(you can enable or disable usage tracking in the preferences)",
1591 "Initialising googletracker for usage stats.");
1592 Cache.initGoogleTracker();
1593 Console.debug("Tracking enabled.");
1600 Console.debug("Not enabling Google Tracking.");
1603 desktop.addDialogThread(prompter);
1607 * Locate the given string as a file and pass it to the groovy interpreter.
1609 * @param groovyscript
1610 * the script to execute
1611 * @param jalviewContext
1612 * the Jalview Desktop object passed in to the groovy binding as the
1615 protected void executeGroovyScript(String groovyscript, AlignFrame af)
1618 * for scripts contained in files
1625 if (groovyscript.trim().equals("STDIN"))
1627 // read from stdin into a tempfile and execute it
1630 tfile = File.createTempFile("jalview", "groovy");
1631 PrintWriter outfile = new PrintWriter(
1632 new OutputStreamWriter(new FileOutputStream(tfile)));
1633 BufferedReader br = new BufferedReader(
1634 new InputStreamReader(System.in));
1636 while ((line = br.readLine()) != null)
1638 outfile.write(line + "\n");
1644 } catch (Exception ex)
1646 System.err.println("Failed to read from STDIN into tempfile "
1647 + ((tfile == null) ? "(tempfile wasn't created)"
1648 : tfile.toString()));
1649 ex.printStackTrace();
1654 sfile = tfile.toURI().toURL();
1655 } catch (Exception x)
1658 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1660 x.printStackTrace();
1668 sfile = new URI(groovyscript).toURL();
1669 } catch (Exception x)
1671 tfile = new File(groovyscript);
1672 if (!tfile.exists())
1674 System.err.println("File '" + groovyscript + "' does not exist.");
1677 if (!tfile.canRead())
1679 System.err.println("File '" + groovyscript + "' cannot be read.");
1682 if (tfile.length() < 1)
1684 System.err.println("File '" + groovyscript + "' is empty.");
1689 sfile = tfile.getAbsoluteFile().toURI().toURL();
1690 } catch (Exception ex)
1692 System.err.println("Failed to create a file URL for "
1693 + tfile.getAbsoluteFile());
1700 Map<String, java.lang.Object> vbinding = new HashMap<>();
1701 vbinding.put("Jalview", this);
1704 vbinding.put("currentAlFrame", af);
1706 Binding gbinding = new Binding(vbinding);
1707 GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1708 gse.run(sfile.toString(), gbinding);
1709 if ("STDIN".equals(groovyscript))
1711 // delete temp file that we made -
1712 // only if it was successfully executed
1715 } catch (Exception e)
1717 System.err.println("Exception Whilst trying to execute file " + sfile
1718 + " as a groovy script.");
1719 e.printStackTrace(System.err);
1724 public static boolean isHeadlessMode()
1726 String isheadless = System.getProperty("java.awt.headless");
1727 if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1734 public AlignFrame[] getAlignFrames()
1736 return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1737 : Desktop.getAlignFrames();
1742 * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
1746 // System.exit will run the shutdownHook first
1747 Jalview.exit("Quitting now. Bye!", 0);
1750 public static AlignFrame getCurrentAlignFrame()
1752 return Jalview.currentAlignFrame;
1755 public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1757 Jalview.currentAlignFrame = currentAlignFrame;
1760 protected Commands getCommands()
1765 public static void exit(String message, int exitcode)
1767 if (Console.log == null)
1769 // Don't start the logger just to exit!
1770 if (message != null)
1774 System.out.println(message);
1778 System.err.println(message);
1784 Console.debug("Using Jalview.exit");
1785 if (message != null)
1789 Console.info(message);
1793 Console.error(message);
1799 System.exit(exitcode);
1804 * testoutput for string values
1806 protected static void testoutput(ArgParser ap, Arg a, String s1,
1809 BootstrapArgs bsa = ap.getBootstrapArgs();
1810 if (!bsa.getBoolean(Arg.TESTOUTPUT))
1812 if (!((s1 == null && s2 == null) || (s1 != null && s1.equals(s2))))
1814 Console.debug("testoutput with unmatching values '" + s1 + "' and '"
1815 + s2 + "' for arg " + a.argString());
1818 boolean isset = a.hasOption(Opt.BOOTSTRAP) ? bsa.contains(a)
1822 Console.warn("Arg '" + a.getName() + "' not set at all");
1825 testoutput(true, a, s1, s2);
1828 protected static void testoutput(BootstrapArgs bsa, Arg a, String s1,
1831 if (!bsa.getBoolean(Arg.TESTOUTPUT))
1833 if (!((s1 == null && s2 == null) || (s1 != null && s1.equals(s2))))
1835 Console.debug("testoutput with unmatching values '" + s1 + "' and '"
1836 + s2 + "' for arg " + a.argString());
1839 if (!a.hasOption(Opt.BOOTSTRAP))
1841 Console.error("Non-bootstrap Arg '" + a.getName()
1842 + "' given to testoutput(BootstrapArgs bsa, Arg a, String s1, String s2) with only BootstrapArgs");
1844 if (!bsa.contains(a))
1846 Console.warn("Arg '" + a.getName() + "' not set at all");
1849 testoutput(true, a, s1, s2);
1852 private static void testoutput(boolean yes, Arg a, String s1, String s2)
1854 if (yes && ((s1 == null && s2 == null)
1855 || (s1 != null && s1.equals(s2))))
1857 System.out.println("[TESTOUTPUT] arg " + a.argString() + "='" + s1
1863 * testoutput for boolean and unary values
1865 protected static void testoutput(ArgParser ap, Arg a)
1869 BootstrapArgs bsa = ap.getBootstrapArgs();
1872 if (!bsa.getBoolean(Arg.TESTOUTPUT))
1874 boolean val = a.hasOption(Opt.BOOTSTRAP) ? bsa.getBoolean(a)
1876 boolean isset = a.hasOption(Opt.BOOTSTRAP) ? bsa.contains(a)
1880 Console.warn("Arg '" + a.getName() + "' not set at all");
1886 protected static void testoutput(BootstrapArgs bsa, Arg a)
1888 if (!bsa.getBoolean(Arg.TESTOUTPUT))
1890 if (!a.hasOption(Opt.BOOTSTRAP))
1892 Console.warn("Non-bootstrap Arg '" + a.getName()
1893 + "' given to testoutput(BootstrapArgs bsa, Arg a) with only BootstrapArgs");
1896 if (!bsa.contains(a))
1898 Console.warn("Arg '" + a.getName() + "' not set at all");
1901 testoutput(bsa.getBoolean(a), a);
1904 private static void testoutput(boolean yes, Arg a)
1906 String message = null;
1907 if (a.hasOption(Opt.BOOLEAN))
1909 message = (yes ? a.argString() : a.negateArgString()) + " was set";
1911 else if (a.hasOption(Opt.UNARY))
1913 message = a.argString() + (yes ? " was set" : " was not set");
1915 System.out.println("[TESTOUTPUT] arg " + message);