X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fjalview%2Fbin%2FJalview.java;h=5f1f228ba4c7af0b116a059c7b30dbafb9eb4b6e;hb=9f4be220ec9450a669805117a30df98b7848b82c;hp=19de95e0d316598dc6232274d0f6e48183ade492;hpb=76cfeb5e50dd69a3ba963096556f9677c9eea55a;p=jalview.git diff --git a/src/jalview/bin/Jalview.java b/src/jalview/bin/Jalview.java index 19de95e..5f1f228 100755 --- a/src/jalview/bin/Jalview.java +++ b/src/jalview/bin/Jalview.java @@ -20,12 +20,15 @@ */ 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; @@ -37,20 +40,38 @@ import java.security.PermissionCollection; import java.security.Permissions; import java.security.Policy; 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; @@ -65,7 +86,9 @@ import jalview.io.NewickFile; import jalview.io.gff.SequenceOntologyFactory; import jalview.schemes.ColourSchemeI; 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; @@ -87,6 +110,15 @@ import jalview.ws.jws2.Jws2Discoverer; */ public class Jalview { + static + { + Platform.getURLCommandArguments(); + Platform.addJ2SDirectDatabaseCall("https://www.jalview.org"); + Platform.addJ2SDirectDatabaseCall("http://www.jalview.org"); + Platform.addJ2SDirectDatabaseCall("http://www.compbio.dundee.ac.uk"); + Platform.addJ2SDirectDatabaseCall("https://www.compbio.dundee.ac.uk"); + } + /* * singleton instance of this class */ @@ -94,26 +126,36 @@ public class Jalview private Desktop desktop; + protected Commands cmds; + public static AlignFrame currentAlignFrame; static { - // grab all the rights we can the JVM - Policy.setPolicy(new Policy() + if (!Platform.isJS()) + /** + * Java only + * + * @j2sIgnore + */ { - @Override - public PermissionCollection getPermissions(CodeSource codesource) + // grab all the rights we can for the JVM + Policy.setPolicy(new Policy() { - Permissions perms = new Permissions(); - perms.add(new AllPermission()); - return (perms); - } + @Override + public PermissionCollection getPermissions(CodeSource codesource) + { + Permissions perms = new Permissions(); + perms.add(new AllPermission()); + return (perms); + } - @Override - public void refresh() - { - } - }); + @Override + public void refresh() + { + } + }); + } } /** @@ -188,22 +230,113 @@ public class Jalview */ public static void main(String[] args) { + // setLogging(); // BH - for event debugging in JavaScript instance = new Jalview(); instance.doMain(args); } + private static void logClass(String name) + { + // BH - for event debugging in JavaScript + ConsoleHandler consoleHandler = new ConsoleHandler(); + consoleHandler.setLevel(Level.ALL); + Logger logger = Logger.getLogger(name); + logger.setLevel(Level.ALL); + logger.addHandler(consoleHandler); + } + + @SuppressWarnings("unused") + private static void setLogging() + { + + /** + * @j2sIgnore + * + */ + { + System.out.println("not in js"); + } + + // BH - for event debugging in JavaScript (Java mode only) + if (!Platform.isJS()) + /** + * Java only + * + * @j2sIgnore + */ + { + Logger.getLogger("").setLevel(Level.ALL); + logClass("java.awt.EventDispatchThread"); + logClass("java.awt.EventQueue"); + logClass("java.awt.Component"); + logClass("java.awt.focus.Component"); + logClass("java.awt.focus.DefaultKeyboardFocusManager"); + } + + } + /** * @param args */ void doMain(String[] args) { - System.setSecurityManager(null); + + if (!Platform.isJS()) + { + System.setSecurityManager(null); + } + + // Move any new getdown-launcher-new.jar into place over old + // getdown-launcher.jar + String appdirString = System.getProperty("getdownappdir"); + if (appdirString != null && appdirString.length() > 0) + { + final File appdir = new File(appdirString); + new Thread() + { + @Override + public void run() + { + LaunchUtil.upgradeGetdown( + new File(appdir, "getdown-launcher-old.jar"), + new File(appdir, "getdown-launcher.jar"), + new File(appdir, "getdown-launcher-new.jar")); + } + }.start(); + } + + // 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) { @@ -220,45 +353,133 @@ public class Jalview 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; - if (aparser.contains("help") || aparser.contains("h")) + try { - showUsage(); - System.exit(0); - } - if (aparser.contains("nodisplay") || aparser.contains("nogui") - || aparser.contains("headless")) + String logLevel = bootstrapArgs.contains(Arg.DEBUG) ? "DEBUG" : null; + if (logLevel == null && !(bootstrapProperties == null)) + { + logLevel = bootstrapProperties.getProperty(Cache.JALVIEWLOGLEVEL); + } + Console.initLogger(logLevel); + } catch (NoClassDefFoundError error) { - System.setProperty("java.awt.headless", "true"); - headless = true; + error.printStackTrace(); + String message = "\nEssential logging libraries not found." + + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview"; + Jalview.exit(message, 0); } - String usrPropsFile = aparser.getValue("props"); - Cache.loadProperties(usrPropsFile); // must do this before + + // 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!"); } - // anything else! + // 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); + } - final String jabawsUrl = aparser.getValue("jabaws"); - if (jabawsUrl != null) + if (!Platform.isJS()) + /** + * Java only + * + * @j2sIgnore + */ { - try + if (aparser.contains("help") || aparser.contains("h") + || argparser.getBool(Arg.HELP)) { - Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl); - System.out.println( - "CMD [-jabaws " + jabawsUrl + "] executed successfully!"); - } catch (MalformedURLException e) + showUsage(); + Jalview.exit(null, 0); + } + + if (bootstrapArgs.contains(Arg.HEADLESS)) { - System.err.println( - "Invalid jabaws parameter: " + jabawsUrl + " ignored"); + 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! + + // allow https handshakes to download intermediate certs if necessary + System.setProperty("com.sun.security.enableAIAcaIssuers", "true"); + + final String jabawsUrl = aparser.getValue("jabaws"); + if (jabawsUrl != null) + { + try + { + Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl); + System.out.println( + "CMD [-jabaws " + jabawsUrl + "] executed successfully!"); + } catch (MalformedURLException e) + { + System.err.println( + "Invalid jabaws parameter: " + jabawsUrl + " ignored"); + } } } @@ -273,6 +494,10 @@ public class Jalview else { System.out.println("Executing setprop argument: " + defs); + if (Platform.isJS()) + { + Cache.setProperty(defs.substring(0, p), defs.substring(p + 1)); + } // DISABLED FOR SECURITY REASONS // TODO: add a property to allow properties to be overriden by cli args // Cache.setProperty(defs.substring(0,p), defs.substring(p+1)); @@ -286,33 +511,37 @@ public class Jalview } System.setProperty("http.agent", "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown")); + try { - Cache.initLogger(); - } catch (NoClassDefFoundError error) + Console.initLogger(); + } 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); + String message = "\nEssential logging libraries not found." + + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview"; + Jalview.exit(message, 0); } - desktop = null; - setLookAndFeel(); + if (!(headless || headlessArg)) + setLookAndFeel(); /* - * configure 'full' SO model if preferences say to, else use the default (SO - * Lite) + * configure 'full' SO model if preferences say to, else use the default (full SO) + * - as JS currently doesn't have OBO parsing, it must use 'Lite' version */ - if (Cache.getDefault("USE_FULL_SO", true)) + boolean soDefault = !Platform.isJS(); + if (Cache.getDefault("USE_FULL_SO", soDefault)) { SequenceOntologyFactory.setInstance(new SequenceOntology()); } - if (!headless) + if (!(headless || headlessArg)) { - + Desktop.nosplash = aparser.contains("nosplash"); desktop = new Desktop(); desktop.setInBatchMode(true); // indicate we are starting up @@ -321,95 +550,153 @@ public class Jalview JalviewTaskbar.setTaskbar(this); } catch (Exception e) { - Cache.log.info("Cannot set Taskbar"); - Cache.log.error(e.getMessage()); + Console.info("Cannot set Taskbar"); + Console.error(e.getMessage()); // e.printStackTrace(); } catch (Throwable t) { - Cache.log.info("Cannot set Taskbar"); - Cache.log.error(t.getMessage()); + Console.info("Cannot set Taskbar"); + Console.error(t.getMessage()); // t.printStackTrace(); } + // set Proxy settings before all the internet calls + Cache.setProxyPropertiesFromPreferences(); + desktop.setVisible(true); - desktop.startServiceDiscovery(); - if (!aparser.contains("nousagestats")) - { - startUsageStats(desktop); - } - else - { - System.err.println("CMD [-nousagestats] executed successfully!"); - } - if (!aparser.contains("noquestionnaire")) + if (!Platform.isJS()) + /** + * Java only + * + * @j2sIgnore + */ { - String url = aparser.getValue("questionnaire"); - if (url != null) + + /** + * 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()) { - // Start the desktop questionnaire prompter with the specified - // questionnaire - Cache.log.debug("Starting questionnaire url at " + url); - desktop.checkForQuestionnaire(url); - System.out.println( - "CMD questionnaire[-" + url + "] executed successfully!"); + 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(); + } + if (!aparser.contains("nousagestats")) + { + startUsageStats(desktop); } else { - if (Cache.getProperty("NOQUESTIONNAIRES") == null) + System.err.println("CMD [-nousagestats] executed successfully!"); + } + + if (!aparser.contains("noquestionnaire")) + { + String url = aparser.getValue("questionnaire"); + if (url != null) { // Start the desktop questionnaire prompter with the specified // questionnaire - // String defurl = - // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl"; - // // - String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl"; - Cache.log.debug( - "Starting questionnaire with default url: " + defurl); - desktop.checkForQuestionnaire(defurl); + Console.debug("Starting questionnaire url at " + url); + desktop.checkForQuestionnaire(url); + System.out.println("CMD questionnaire[-" + url + + "] executed successfully!"); + } + else + { + if (Cache.getProperty("NOQUESTIONNAIRES") == null) + { + // Start the desktop questionnaire prompter with the specified + // questionnaire + // String defurl = + // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl"; + // // + String defurl = "https://www.jalview.org/cgi-bin/questionnaire.pl"; + Console.debug( + "Starting questionnaire with default url: " + defurl); + desktop.checkForQuestionnaire(defurl); + } } } - } - else - { - System.err.println("CMD [-noquestionnaire] executed successfully!"); - } + else + { + System.err + .println("CMD [-noquestionnaire] executed successfully!"); + } - if (!aparser.contains("nonews") - || Cache.getProperty("NONEWS") == null) + if (!aparser.contains("nonews") + || Cache.getProperty("NONEWS") == null) + { + desktop.checkForNews(); + } + + if (!aparser.contains("nohtmltemplates") + || Cache.getProperty("NOHTMLTEMPLATES") == null) + { + BioJsHTMLOutput.updateBioJS(); + } + } + } + // Run Commands from cli + cmds = new Commands(argparser, headlessArg); + boolean commandsSuccess = cmds.argsWereParsed(); + if (commandsSuccess) + { + if (headlessArg) { - desktop.checkForNews(); + Jalview.exit("Successfully completed commands in headless mode", 0); } - - if (!aparser.contains("nohtmltemplates") - || Cache.getProperty("NOHTMLTEMPLATES") == null) + Console.info("Successfully completed commands"); + } + else + { + if (headlessArg) { - BioJsHTMLOutput.updateBioJS(); + Jalview.exit("Error when running Commands in headless mode", 1); } + Console.warn("Error when running commands"); } - // Move any new getdown-launcher-new.jar into place over old - // getdown-launcher.jar - String appdirString = System.getProperty("getdownappdir"); - if (appdirString != null && appdirString.length() > 0) + // Check if JVM and compile version might cause problems and log if it + // might. + if (headless && !Platform.isJS() && !LaunchUtils.checkJavaVersion()) { - final File appdir = new File(appdirString); - new Thread() - { - @Override - public void run() - { - LaunchUtil.upgradeGetdown( - new File(appdir, "getdown-launcher-old.jar"), - new File(appdir, "getdown-launcher.jar"), - new File(appdir, "getdown-launcher-new.jar")); - } - }.start(); + 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() + "."); } 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 @@ -420,9 +707,9 @@ public class Jalview if (file == null && desktop == null) { - System.out.println("No files to open!"); - System.exit(1); + Jalview.exit("No files to open!", 1); } + long progress = -1; // Finally, deal with the remaining input data. if (file != null) @@ -436,20 +723,29 @@ public class Jalview } System.out.println("CMD [-open " + file + "] executed successfully!"); - protocol = AppletFormatAdapter.checkProtocol(file); - - if (protocol == DataSourceType.FILE) + if (!Platform.isJS()) + /** + * ignore in JavaScript -- can't just file existence - could load it? + * + * @j2sIgnore + */ { - if (!(new File(file)).exists()) + if (!HttpUtils.startsWithHttpOrHttps(file)) { - System.out.println("Can't find " + file); - if (headless) + if (!(new File(file)).exists()) { - System.exit(1); + if (headless) + { + Jalview.exit( + "Can't find file '" + file + "' in headless mode", 1); + } + Console.warn("Can't find file'" + file + "'"); } } } + protocol = AppletFormatAdapter.checkProtocol(file); + try { format = new IdentifyFile().identify(file, protocol); @@ -478,7 +774,7 @@ public class Jalview if (cs != null) { System.out.println( - "CMD [-color " + data + "] executed successfully!"); + "CMD [-colour " + data + "] executed successfully!"); } af.changeColour(cs); } @@ -652,18 +948,20 @@ public class Jalview } else { - if (af.saveAlignment(file, outFormat)) + af.saveAlignment(file, outFormat); + if (af.isSaveAlignmentSuccessful()) { - System.out.println("Written alignment in " + format - + " format to " + file); + System.out.println("Written alignment in " + + outFormat.getName() + " format to " + file); } else { System.out.println("Error writing file " + file + " in " - + format + " format!!"); + + outFormat.getName() + " format!!"); } } } + } while (aparser.getSize() > 0) @@ -672,17 +970,25 @@ public class Jalview } } } + AlignFrame startUpAlframe = null; // We'll only open the default file if the desktop is visible. // And the user // //////////////////// - if (!headless && file == null - && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true)) + if (!Platform.isJS() && !headless && file == null + && 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 + * + * @j2sIgnore + */ { - file = jalview.bin.Cache.getDefault("STARTUP_FILE", - jalview.bin.Cache.getDefault("www.jalview.org", - "https://www.jalview.org") + file = Cache.getDefault("STARTUP_FILE", + Cache.getDefault("www.jalview.org", "https://www.jalview.org") + "/examples/exampleFile_2_7.jvp"); if (file.equals("http://www.jalview.org/examples/exampleFile_2_3.jar") || file.equals( @@ -693,7 +999,7 @@ public class Jalview file.replace("_2_3", "_2_7"); file.replace("2_7.jar", "2_7.jvp"); // and remove the stale setting - jalview.bin.Cache.removeProperty("STARTUP_FILE"); + Cache.removeProperty("STARTUP_FILE"); } protocol = AppletFormatAdapter.checkProtocol(file); @@ -715,6 +1021,10 @@ public class Jalview 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. } @@ -746,8 +1056,8 @@ public class Jalview 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"); @@ -768,71 +1078,64 @@ public class Jalview lafSet = setCrossPlatformLookAndFeel(); if (!lafSet) { - Cache.log.error("Could not set requested laf=" + laf); + Console.error("Could not set requested laf=" + laf); } break; case "system": lafSet = setSystemLookAndFeel(); if (!lafSet) { - Cache.log.error("Could not set requested laf=" + laf); + Console.error("Could not set requested laf=" + laf); } break; case "gtk": lafSet = setGtkLookAndFeel(); if (!lafSet) { - Cache.log.error("Could not set requested laf=" + laf); + Console.error("Could not set requested laf=" + laf); } break; case "metal": lafSet = setMetalLookAndFeel(); if (!lafSet) { - Cache.log.error("Could not set requested laf=" + laf); + Console.error("Could not set requested laf=" + laf); } break; case "nimbus": lafSet = setNimbusLookAndFeel(); if (!lafSet) { - Cache.log.error("Could not set requested laf=" + laf); - } - break; - case "quaqua": - lafSet = setQuaquaLookAndFeel(); - if (!lafSet) - { - Cache.log.error("Could not set requested laf=" + laf); + Console.error("Could not set requested laf=" + laf); } break; - case "vaqua": - lafSet = setVaquaLookAndFeel(); + case "flat": + lafSet = setFlatLookAndFeel(); if (!lafSet) { - Cache.log.error("Could not set requested laf=" + laf); + Console.error("Could not set requested laf=" + laf); } break; case "mac": lafSet = setMacLookAndFeel(); if (!lafSet) { - Cache.log.error("Could not set requested laf=" + laf); + Console.error("Could not set requested laf=" + laf); } break; case "none": break; default: - Cache.log.error("Requested laf=" + laf + " not implemented"); + Console.error("Requested laf=" + laf + " not implemented"); } if (!lafSet) { setSystemLookAndFeel(); if (Platform.isLinux()) { - setMetalLookAndFeel(); + setLinuxLookAndFeel(); } - if (Platform.isAMac()) + if (Platform.isMac()) { setMacLookAndFeel(); } @@ -841,28 +1144,33 @@ public class Jalview private static boolean setCrossPlatformLookAndFeel() { - return setGenericLookAndFeel(false); + boolean set = false; + try + { + UIManager.setLookAndFeel( + UIManager.getCrossPlatformLookAndFeelClassName()); + set = true; + } catch (Exception ex) + { + Console.error("Unexpected Look and Feel Exception"); + Console.error(ex.getMessage()); + Console.debug(Cache.getStackTraceString(ex)); + } + return set; } private static boolean setSystemLookAndFeel() { - return setGenericLookAndFeel(true); - } - - private static boolean setGenericLookAndFeel(boolean system) - { boolean set = false; try { - UIManager.setLookAndFeel( - system ? UIManager.getSystemLookAndFeelClassName() - : UIManager.getCrossPlatformLookAndFeelClassName()); + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); set = true; } catch (Exception ex) { - Cache.log.error("Unexpected Look and Feel Exception"); - Cache.log.error(ex.getMessage()); - Cache.log.debug(Cache.getStackTraceString(ex)); + Console.error("Unexpected Look and Feel Exception"); + Console.error(ex.getMessage()); + Console.debug(Cache.getStackTraceString(ex)); } return set; } @@ -876,9 +1184,10 @@ public class Jalview for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { if (info.getName() != null && nameStartsWith - ? info.getName().toLowerCase() - .startsWith(name.toLowerCase()) - : info.getName().toLowerCase().equals(name.toLowerCase())) + ? info.getName().toLowerCase(Locale.ROOT) + .startsWith(name.toLowerCase(Locale.ROOT)) + : info.getName().toLowerCase(Locale.ROOT) + .equals(name.toLowerCase(Locale.ROOT))) { className = info.getClassName(); break; @@ -888,9 +1197,9 @@ public class Jalview set = true; } catch (Exception ex) { - Cache.log.error("Unexpected Look and Feel Exception"); - Cache.log.error(ex.getMessage()); - Cache.log.debug(Cache.getStackTraceString(ex)); + Console.error("Unexpected Look and Feel Exception"); + Console.error(ex.getMessage()); + Console.debug(Cache.getStackTraceString(ex)); } return set; } @@ -913,32 +1222,145 @@ public class Jalview "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() { boolean set = false; System.setProperty("com.apple.mrj.application.apple.menu.about.name", - "Jalview"); + 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().contains("quaqua")) + .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; } @@ -1000,17 +1422,17 @@ public class Jalview @Override public void run() { - Cache.log.debug( + Console.debug( "Initialising googletracker for usage stats."); Cache.initGoogleTracker(); - Cache.log.debug("Tracking enabled."); + Console.debug("Tracking enabled."); } }, new Runnable() { @Override public void run() { - Cache.log.debug("Not enabling Google Tracking."); + Console.debug("Not enabling Google Tracking."); } }, null, true); desktop.addDialogThread(prompter); @@ -1152,19 +1574,12 @@ public class Jalview } /** - * 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 + Jalview.exit("Quitting now. Bye!", 0); } public static AlignFrame getCurrentAlignFrame() @@ -1176,4 +1591,22 @@ public class Jalview { Jalview.currentAlignFrame = currentAlignFrame; } + + protected Commands getCommands() + { + return cmds; + } + + public static void exit(String message, int exitcode) + { + System.err.println("####### EXITING HERE!"); + Console.debug("Using Jalview.exit"); + if (message != null) + if (exitcode == 0) + Console.info(message); + else + Console.error(message); + if (exitcode > -1) + System.exit(exitcode); + } }