*/
package jalview.bin;
+import java.awt.Color;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.io.OutputStream;
import java.io.OutputStreamWriter;
+import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.Properties;
import java.util.Vector;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
+import javax.swing.UnsupportedLookAndFeelException;
+import com.formdev.flatlaf.FlatLightLaf;
+import com.formdev.flatlaf.themes.FlatMacLightLaf;
+import com.formdev.flatlaf.util.SystemInfo;
import com.threerings.getdown.util.LaunchUtil;
//import edu.stanford.ejalbert.launching.IBrowserLaunching;
import groovy.lang.Binding;
import groovy.util.GroovyScriptEngine;
+import jalview.bin.ArgParser.Arg;
+import jalview.bin.ArgParser.BootstrapArgs;
import jalview.ext.so.SequenceOntology;
import jalview.gui.AlignFrame;
import jalview.gui.Desktop;
import jalview.gui.PromptUserConfig;
+import jalview.gui.QuitHandler;
+import jalview.gui.QuitHandler.QResponse;
import jalview.io.AppletFormatAdapter;
import jalview.io.BioJsHTMLOutput;
import jalview.io.DataSourceType;
import jalview.schemes.ColourSchemeProperty;
import jalview.util.ChannelProperties;
import jalview.util.HttpUtils;
+import jalview.util.LaunchUtils;
import jalview.util.MessageManager;
import jalview.util.Platform;
import jalview.ws.jws2.Jws2Discoverer;
private Desktop desktop;
+ protected Commands cmds;
+
public static AlignFrame currentAlignFrame;
static
System.setSecurityManager(null);
}
+ // get args needed before proper ArgParser
+ BootstrapArgs bootstrapArgs = BootstrapArgs.getBootstrapArgs(args);
+
+ if (!Platform.isJS())
+ {
+ // are we being --quiet ?
+ if (bootstrapArgs.contains(Arg.QUIET))
+ {
+ OutputStream devNull = new OutputStream()
+ {
+ @Override
+ public void write(int b)
+ {
+ // DO NOTHING
+ }
+ };
+ System.setOut(new PrintStream(devNull));
+ // redirecting stderr not working
+ if (bootstrapArgs.getList(Arg.QUIET).size() > 1)
+ {
+ System.setErr(new PrintStream(devNull));
+ }
+ }
+ }
+
System.out
.println("Java version: " + System.getProperty("java.version"));
System.out.println("Java Home: " + System.getProperty("java.home"));
System.out.println(System.getProperty("os.arch") + " "
+ System.getProperty("os.name") + " "
+ System.getProperty("os.version"));
+
String val = System.getProperty("sys.install4jVersion");
if (val != null)
{
System.out.println("Launcher version: " + val);
}
+ if (Platform.isLinux() && LaunchUtils.getJavaVersion() < 11)
+ {
+ System.setProperty("flatlaf.uiScale", "1");
+ }
+
+ // get bootstrap properties (mainly for the logger level)
+ Properties bootstrapProperties = Cache
+ .bootstrapProperties(bootstrapArgs.get(Arg.PROPS));
+
// report Jalview version
Cache.loadBuildProperties(true);
+ // old ArgsParser
ArgsParser aparser = new ArgsParser(args);
+
+ // old
boolean headless = false;
+ // new
+ boolean headlessArg = false;
- String usrPropsFile = aparser.getValue("props");
- Cache.loadProperties(usrPropsFile); // must do this before
+ try
+ {
+ String logLevel = bootstrapArgs.contains(Arg.DEBUG) ? "DEBUG" : null;
+ if (logLevel == null && !(bootstrapProperties == null))
+ {
+ logLevel = bootstrapProperties.getProperty(Cache.JALVIEWLOGLEVEL);
+ }
+ Console.initLogger(logLevel);
+ } catch (NoClassDefFoundError error)
+ {
+ error.printStackTrace();
+ System.out.println("\nEssential logging libraries not found."
+ + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
+ System.exit(0);
+ }
+
+ // register SIGTERM listener
+ Runtime.getRuntime().addShutdownHook(new Thread()
+ {
+ public void run()
+ {
+ Console.debug("Running shutdown hook");
+ if (QuitHandler.gotQuitResponse() == QResponse.CANCEL_QUIT)
+ {
+ // Got to here by a SIGTERM signal.
+ // Note we will not actually cancel the quit from here -- it's too
+ // late -- but we can wait for saving files.
+ Console.debug("Checking for saving files");
+ QuitHandler.getQuitResponse(false);
+ }
+ else
+ {
+ Console.debug("Nothing more to do");
+ }
+ Console.debug("Exiting, bye!");
+ // shutdownHook cannot be cancelled, JVM will now halt
+ }
+ });
+
+ String usrPropsFile = bootstrapArgs.contains(Arg.PROPS)
+ ? bootstrapArgs.get(Arg.PROPS)
+ : aparser.getValue("props");
+ Cache.loadProperties(usrPropsFile);
if (usrPropsFile != null)
{
System.out.println(
"CMD [-props " + usrPropsFile + "] executed successfully!");
}
+ // new ArgParser
+ ArgParser argparser;
+ // --argfile=... -- OVERRIDES ALL NON-BOOTSTRAP ARGS
+ if (bootstrapArgs.contains(Arg.ARGFILE))
+ {
+ argparser = ArgParser
+ .parseArgFiles(bootstrapArgs.getList(Arg.ARGFILE));
+ }
+ else
+ {
+ argparser = new ArgParser(args);
+ }
+
if (!Platform.isJS())
/**
* Java only
* @j2sIgnore
*/
{
- if (aparser.contains("help") || aparser.contains("h"))
+ if (aparser.contains("help") || aparser.contains("h")
+ || argparser.getBool(Arg.HELP))
{
showUsage();
System.exit(0);
}
+
+ if (bootstrapArgs.contains(Arg.HEADLESS))
+ {
+ System.setProperty("java.awt.headless", "true");
+ // new
+ headlessArg = argparser.getBool(Arg.HEADLESS);
+ }
if (aparser.contains("nodisplay") || aparser.contains("nogui")
|| aparser.contains("headless"))
{
System.setProperty("java.awt.headless", "true");
+ // old
headless = true;
}
// anything else!
try
{
Console.initLogger();
- } catch (NoClassDefFoundError error)
+ } catch (
+
+ NoClassDefFoundError error)
{
error.printStackTrace();
System.out.println("\nEssential logging libraries not found."
+ "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
System.exit(0);
}
-
desktop = null;
- setLookAndFeel();
+ if (!(headless || headlessArg))
+ setLookAndFeel();
/*
* configure 'full' SO model if preferences say to, else use the default (full SO)
SequenceOntologyFactory.setInstance(new SequenceOntology());
}
- if (!headless)
+ if (!(headless || headlessArg))
{
Desktop.nosplash = aparser.contains("nosplash");
desktop = new Desktop();
* @j2sIgnore
*/
{
+
+ /**
+ * Check to see that the JVM version being run is suitable for the Java
+ * version this Jalview was compiled for. Popup a warning if not.
+ */
+ if (!LaunchUtils.checkJavaVersion())
+ {
+ Console.warn("The Java version being used (Java "
+ + LaunchUtils.getJavaVersion()
+ + ") may lead to problems. This installation of Jalview should be used with Java "
+ + LaunchUtils.getJavaCompileVersion() + ".");
+
+ if (!LaunchUtils
+ .getBooleanUserPreference("IGNORE_JVM_WARNING_POPUP"))
+ {
+ Object[] options = {
+ MessageManager.getString("label.continue") };
+ JOptionPane.showOptionDialog(null,
+ MessageManager.formatMessage(
+ "warning.wrong_jvm_version_message",
+ LaunchUtils.getJavaVersion(),
+ LaunchUtils.getJavaCompileVersion()),
+ MessageManager
+ .getString("warning.wrong_jvm_version_title"),
+ JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
+ null, options, options[0]);
+ }
+ }
+
if (!aparser.contains("nowebservicediscovery"))
{
desktop.startServiceDiscovery();
}
}
}
+ // Run Commands from cli
+ cmds = new Commands(argparser, headlessArg);
+ boolean commandsSuccess = cmds.argsWereParsed();
+ if (commandsSuccess)
+ {
+ Console.info("Successfully completed commands");
+ if (headlessArg)
+ {
+ System.out.println("#### EXITING");
+ System.exit(0);
+ }
+ }
+ else
+ {
+ Console.warn("Error when running commands");
+ if (headlessArg)
+ System.exit(1);
+ }
+
+ // Check if JVM and compile version might cause problems and log if it
+ // might.
+ if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion())
+ {
+ Console.warn("The Java version being used (Java "
+ + LaunchUtils.getJavaVersion()
+ + ") may lead to problems. This installation of Jalview should be used with Java "
+ + LaunchUtils.getJavaCompileVersion() + ".");
+ }
// Move any new getdown-launcher-new.jar into place over old
// getdown-launcher.jar
}
String file = null, data = null;
+
FileFormatI format = null;
+
DataSourceType protocol = null;
+
FileLoader fileLoader = new FileLoader(!headless);
String groovyscript = null; // script to execute after all loading is
System.out.println("No files to open!");
System.exit(1);
}
+
long progress = -1;
// Finally, deal with the remaining input data.
if (file != null)
if (cs != null)
{
System.out.println(
- "CMD [-color " + data + "] executed successfully!");
+ "CMD [-colour " + data + "] executed successfully!");
}
af.changeColour(cs);
}
}
}
}
+
AlignFrame startUpAlframe = null;
// We'll only open the default file if the desktop is visible.
// And the user
// ////////////////////
if (!Platform.isJS() && !headless && file == null
- && Cache.getDefault("SHOW_STARTUP_FILE", true))
+ && Cache.getDefault("SHOW_STARTUP_FILE", true)
+ && !cmds.commandArgsProvided())
+ // don't open the startup file if command line args have been processed
+ // (&& !Commands.commandArgsProvided())
/**
* Java only
*
startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
format);
+ // don't ask to save when quitting if only the startup file has been
+ // opened
+ Console.debug("Resetting up-to-date flag for startup file");
+ startUpAlframe.getViewport().setSavedUpToDate(true);
// extract groovy arguments before anything else.
}
private static void setLookAndFeel()
{
- // property laf = "crossplatform", "system", "gtk", "metal", "nimbus" or
- // "mac"
+ // property laf = "crossplatform", "system", "gtk", "metal", "nimbus",
+ // "mac" or "flat"
// If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
// try Quaqua/Vaqua.
String lafProp = System.getProperty("laf");
Console.error("Could not set requested laf=" + laf);
}
break;
- case "quaqua":
- lafSet = setQuaquaLookAndFeel();
- if (!lafSet)
- {
- Console.error("Could not set requested laf=" + laf);
- }
- break;
- case "vaqua":
- lafSet = setVaquaLookAndFeel();
+ case "flat":
+ lafSet = setFlatLookAndFeel();
if (!lafSet)
{
Console.error("Could not set requested laf=" + laf);
setSystemLookAndFeel();
if (Platform.isLinux())
{
- setMetalLookAndFeel();
+ setLinuxLookAndFeel();
}
if (Platform.isMac())
{
"javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
}
- private static boolean setQuaquaLookAndFeel()
+ private static boolean setFlatLookAndFeel()
{
- return setSpecificLookAndFeel("quaqua",
- ch.randelshofer.quaqua.QuaquaManager.getLookAndFeel().getClass()
- .getName(),
- false);
- }
+ boolean set = false;
+ if (SystemInfo.isMacOS)
+ {
+ try
+ {
+ UIManager.setLookAndFeel(
+ "com.formdev.flatlaf.themes.FlatMacLightLaf");
+ set = true;
+ Console.debug("Using FlatMacLightLaf");
+ } catch (ClassNotFoundException | InstantiationException
+ | IllegalAccessException | UnsupportedLookAndFeelException e)
+ {
+ Console.debug("Exception loading FlatLightLaf", e);
+ }
+ System.setProperty("apple.laf.useScreenMenuBar", "true");
+ System.setProperty("apple.awt.application.name",
+ ChannelProperties.getProperty("app_name"));
+ System.setProperty("apple.awt.application.appearance", "system");
+ if (SystemInfo.isMacFullWindowContentSupported
+ && Desktop.desktop != null)
+ {
+ Console.debug("Setting transparent title bar");
+ Desktop.desktop.getRootPane()
+ .putClientProperty("apple.awt.fullWindowContent", true);
+ Desktop.desktop.getRootPane()
+ .putClientProperty("apple.awt.transparentTitleBar", true);
+ Desktop.desktop.getRootPane()
+ .putClientProperty("apple.awt.fullscreenable", true);
+ }
+ SwingUtilities.invokeLater(() -> {
+ FlatMacLightLaf.setup();
+ });
+ Console.debug("Using FlatMacLightLaf");
+ set = true;
+ }
+ if (!set)
+ {
+ try
+ {
+ UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
+ set = true;
+ Console.debug("Using FlatLightLaf");
+ } catch (ClassNotFoundException | InstantiationException
+ | IllegalAccessException | UnsupportedLookAndFeelException e)
+ {
+ Console.debug("Exception loading FlatLightLaf", e);
+ }
+ // Windows specific properties here
+ SwingUtilities.invokeLater(() -> {
+ FlatLightLaf.setup();
+ });
+ Console.debug("Using FlatLightLaf");
+ set = true;
+ }
+ else if (SystemInfo.isLinux)
+ {
+ try
+ {
+ UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
+ set = true;
+ Console.debug("Using FlatLightLaf");
+ } catch (ClassNotFoundException | InstantiationException
+ | IllegalAccessException | UnsupportedLookAndFeelException e)
+ {
+ Console.debug("Exception loading FlatLightLaf", e);
+ }
+ // enable custom window decorations
+ JFrame.setDefaultLookAndFeelDecorated(true);
+ JDialog.setDefaultLookAndFeelDecorated(true);
+ SwingUtilities.invokeLater(() -> {
+ FlatLightLaf.setup();
+ });
+ Console.debug("Using FlatLightLaf");
+ set = true;
+ }
- private static boolean setVaquaLookAndFeel()
- {
- return setSpecificLookAndFeel("vaqua",
- "org.violetlib.aqua.AquaLookAndFeel", false);
+ if (!set)
+ {
+ try
+ {
+ UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf");
+ set = true;
+ Console.debug("Using FlatLightLaf");
+ } catch (ClassNotFoundException | InstantiationException
+ | IllegalAccessException | UnsupportedLookAndFeelException e)
+ {
+ Console.debug("Exception loading FlatLightLaf", e);
+ }
+ }
+
+ if (set)
+ {
+ UIManager.put("TabbedPane.tabType", "card");
+ UIManager.put("TabbedPane.showTabSeparators", true);
+ UIManager.put("TabbedPane.showContentSeparator", true);
+ UIManager.put("TabbedPane.tabSeparatorsFullHeight", true);
+ UIManager.put("TabbedPane.tabsOverlapBorder", true);
+ UIManager.put("TabbedPane.hasFullBorder", true);
+ UIManager.put("TabbedPane.tabLayoutPolicy", "scroll");
+ UIManager.put("TabbedPane.scrollButtonsPolicy", "asNeeded");
+ UIManager.put("TabbedPane.smoothScrolling", true);
+ UIManager.put("TabbedPane.tabWidthMode", "compact");
+ UIManager.put("TabbedPane.selectedBackground", Color.white);
+ }
+
+ Desktop.setLiveDragMode(Cache.getDefault("FLAT_LIVE_DRAG_MODE", true));
+ return set;
}
private static boolean setMacLookAndFeel()
System.setProperty("com.apple.mrj.application.apple.menu.about.name",
ChannelProperties.getProperty("app_name"));
System.setProperty("apple.laf.useScreenMenuBar", "true");
+ /*
+ * broken native LAFs on (ARM?) macbooks
set = setQuaquaLookAndFeel();
if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
.toLowerCase(Locale.ROOT).contains("quaqua"))
{
set = setVaquaLookAndFeel();
}
+ */
+ set = setFlatLookAndFeel();
+ return set;
+ }
+
+ private static boolean setLinuxLookAndFeel()
+ {
+ boolean set = false;
+ set = setFlatLookAndFeel();
+ if (!set)
+ set = setMetalLookAndFeel();
+ // avoid GtkLookAndFeel -- not good results especially on HiDPI
+ if (!set)
+ set = setNimbusLookAndFeel();
return set;
}
}
/**
- * Quit method delegates to Desktop.quit - unless running in headless mode
- * when it just ends the JVM
+ * jalview.bin.Jalview.quit() will just run the non-GUI shutdownHook and exit
*/
public void quit()
{
- if (desktop != null)
- {
- desktop.quit();
- }
- else
- {
- System.exit(0);
- }
+ // System.exit will run the shutdownHook first
+ System.out.println("Quitting now. Bye!");
+ System.exit(0);
}
public static AlignFrame getCurrentAlignFrame()
{
Jalview.currentAlignFrame = currentAlignFrame;
}
+
+ protected Commands getCommands()
+ {
+ return cmds;
+ }
}