Merge branch 'merge/JAL-3609_and_JAL-3608' into releases/Release_2_11_1_Branch
authorJim Procter <jprocter@issues.jalview.org>
Sat, 4 Jul 2020 14:11:45 +0000 (15:11 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Sat, 4 Jul 2020 14:11:45 +0000 (15:11 +0100)
22 files changed:
build.gradle
getdown/lib/FJVL_VERSION
getdown/lib/JVL_VERSION
getdown/lib/getdown-core.jar
getdown/lib/getdown-launcher-local.jar
getdown/lib/getdown-launcher.jar
getdown/src/getdown/ant/pom.xml
getdown/src/getdown/core/pom.xml
getdown/src/getdown/core/src/main/java/com/threerings/getdown/data/Application.java
getdown/src/getdown/core/src/main/java/jalview/bin/GetMemory.java
getdown/src/getdown/core/src/main/java/jalview/bin/HiDPISetting.java [new file with mode: 0644]
getdown/src/getdown/core/src/main/java/jalview/bin/MemorySetting.java
getdown/src/getdown/launcher/pom.xml
getdown/src/getdown/mvn_cmd
getdown/src/getdown/pom.xml
j11lib/getdown-core.jar
j8lib/getdown-core.jar
src/jalview/bin/Cache.java
src/jalview/bin/HiDPISetting.java [new file with mode: 0644]
src/jalview/bin/Jalview.java
src/jalview/bin/Launcher.java
src/jalview/util/Platform.java

index f7233f1..2c7f138 100644 (file)
@@ -958,6 +958,16 @@ test {
 
   workingDir = jalviewDir
   //systemProperties 'clover.jar' System.properties.clover.jar
+  def testLaf = project.findProperty("test_laf")
+  if (testLaf != null) {
+    println("Setting Test LaF to '${testLaf}'")
+    systemProperty "laf", testLaf
+  }
+  def testHiDPIScale = project.findProperty("test_HiDPIScale")
+  if (testHiDPIScale != null) {
+    println("Setting Test HiDPI Scale to '${testHiDPIScale}'")
+    systemProperty "sun.java2d.uiScale", testHiDPIScale
+  }
   sourceCompatibility = compile_source_compatibility
   targetCompatibility = compile_target_compatibility
   jvmArgs += additional_compiler_args
index e7a1de7..fdf3dcc 100644 (file)
@@ -1 +1 @@
-1.8.3-1.2.4_FJVL
+1.8.3-1.2.6_FJVL
index 756f4bd..4492183 100644 (file)
@@ -1 +1 @@
-1.8.3-1.2.4_JVL
+1.8.3-1.2.6_JVL
index 9c0f96e..6748a25 100644 (file)
Binary files a/getdown/lib/getdown-core.jar and b/getdown/lib/getdown-core.jar differ
index cfa96f3..9a27f55 100644 (file)
Binary files a/getdown/lib/getdown-launcher-local.jar and b/getdown/lib/getdown-launcher-local.jar differ
index 2f8baa7..e441bc6 100644 (file)
Binary files a/getdown/lib/getdown-launcher.jar and b/getdown/lib/getdown-launcher.jar differ
index 8dcef42..65686d2 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.threerings.getdown</groupId>
     <artifactId>getdown</artifactId>
-    <version>1.8.3-1.2.4_FJVL</version>
+    <version>1.8.3-1.2.6_FJVL</version>
   </parent>
 
   <artifactId>getdown-ant</artifactId>
index 2d0e89a..6a9e169 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.threerings.getdown</groupId>
     <artifactId>getdown</artifactId>
-    <version>1.8.3-1.2.4_FJVL</version>
+    <version>1.8.3-1.2.6_FJVL</version>
   </parent>
 
   <artifactId>getdown-core</artifactId>
index fd53c79..b11a380 100644 (file)
@@ -27,6 +27,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.zip.GZIPInputStream;
 
+import jalview.bin.HiDPISetting;
 import jalview.bin.MemorySetting;
 //import com.install4j.api.launcher.Variables;
 
@@ -1071,6 +1072,13 @@ public class Application
         args.add("-Dinstaller_template_version=" + System.getProperty("installer_template_version"));
         args.add("-Dlauncher_version=" + Build.version());
 
+        // set HiDPI property if wanted
+        String scalePropertyArg = HiDPISetting.getScalePropertyArg();
+        if (scalePropertyArg != null)
+        {
+          args.add(scalePropertyArg);
+        }
+
         // set the native library path if we have native resources
         // @TODO optional getdown.txt parameter to set addCurrentLibraryPath to true or false?
         ClassPath javaLibPath = PathBuilder.buildLibsPath(this, true);
index e89bffb..b01dfb8 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
 package jalview.bin;
 
 import java.lang.management.ManagementFactory;
diff --git a/getdown/src/getdown/core/src/main/java/jalview/bin/HiDPISetting.java b/getdown/src/getdown/core/src/main/java/jalview/bin/HiDPISetting.java
new file mode 100644 (file)
index 0000000..497900f
--- /dev/null
@@ -0,0 +1,180 @@
+package jalview.bin;
+
+import java.awt.HeadlessException;
+import java.awt.Toolkit;
+
+public class HiDPISetting
+{
+  private static final int hidpiThreshold = 160;
+
+  private static final int hidpiMultiThreshold = 240;
+
+  private static final int bigScreenThreshold = 1400;
+
+  private static final String scalePropertyName = "sun.java2d.uiScale";
+
+  private static final boolean isLinux;
+
+  // private static final boolean isAMac;
+
+  // private static final boolean isWindows;
+
+  public static final String setHiDPIPropertyName = "setHiDPI";
+
+  public static final String setHiDPIScalePropertyName = "setHiDPIScale";
+
+  private static boolean setHiDPI = false;
+
+  private static int setHiDPIScale = 0;
+
+  public static int dpi = 0;
+
+  public static int mindimension = 0;
+
+  public static int width = 0;
+
+  public static int scale = 0;
+
+  private static boolean doneInit = false;
+
+  private static boolean allowScalePropertyArg = false;
+
+  static
+  {
+    String system = System.getProperty("os.name") == null ? null
+            : System.getProperty("os.name").toLowerCase();
+    if (system != null)
+    {
+      isLinux = system.indexOf("linux") > -1;
+      // isAMac = system.indexOf("mac") > -1;
+      // isWindows = system.indexOf("windows") > -1;
+    }
+    else
+    {
+      isLinux = false;
+      // isAMac = isWindows = false;
+    }
+  }
+
+  private static void init()
+  {
+    if (doneInit)
+    {
+      return;
+    }
+
+    // get and use command line property values first
+    String setHiDPIProperty = System.getProperty(setHiDPIPropertyName);
+    setHiDPI = setHiDPIProperty != null
+            && setHiDPIProperty.equalsIgnoreCase("true");
+
+    String setHiDPIScaleProperty = System
+            .getProperty(setHiDPIScalePropertyName);
+    if (setHiDPIScaleProperty != null)
+    {
+      try
+      {
+        setHiDPIScale = Integer.parseInt(setHiDPIScaleProperty);
+      } catch (NumberFormatException e)
+      {
+        System.err.println(setHiDPIScalePropertyName + " property give ("
+                + setHiDPIScaleProperty + ") but not parseable as integer");
+      }
+    }
+    if (setHiDPI && setHiDPIScale > 0)
+    {
+      setHiDPIScale(setHiDPIScale);
+      return;
+    }
+
+    // check to see if the scale property has already been set by something else
+    // (e.g. the OS)
+    String existingProperty = System.getProperty(scalePropertyName);
+    if (existingProperty != null)
+    {
+      try
+      {
+        int existingPropertyVal = Integer.parseInt(existingProperty);
+        System.out.println("Existing " + scalePropertyName + " is "
+                + existingPropertyVal);
+        if (existingPropertyVal > 1)
+        {
+          setHiDPIScale(existingPropertyVal);
+          return;
+        }
+      } catch (NumberFormatException e)
+      {
+        System.out.println("Could not convert property " + scalePropertyName
+                + " vale '" + existingProperty + "' to number");
+      }
+    }
+
+    // Try and auto guess a good scale based on reported DPI (not trustworthy)
+    // and screen resolution (more trustworthy)
+
+    // get screen dpi
+    try
+    {
+      dpi = Toolkit.getDefaultToolkit().getScreenResolution();
+    } catch (HeadlessException e)
+    {
+      System.err.println("Cannot get screen resolution: " + e.getMessage());
+    }
+
+    // try and get screen size height and width
+    try
+    {
+      int height = Toolkit.getDefaultToolkit().getScreenSize().height;
+      int width = Toolkit.getDefaultToolkit().getScreenSize().width;
+      // using mindimension in case of portrait screens
+      mindimension = Math.min(height, width);
+    } catch (HeadlessException e)
+    {
+      System.err.println(
+              "Cannot get screen size height and width:" + e.getMessage());
+    }
+
+    // attempt at a formula for scaling based on screen dpi and mindimension.
+    // scale will be an integer >=1. This formula is based on some testing and
+    // guesswork!
+
+    // scale based on reported dpi. if dpi>hidpiThreshold then scale=2+multiples
+    // of hidpiMultiThreshold (else scale=1)
+    // (e.g. dpi of 110 scales 1. dpi of 120 scales 2. dpi of 360 scales 3)
+    int dpiScale = (dpi - hidpiThreshold > 0)
+            ? 2 + ((dpi - hidpiThreshold) / hidpiMultiThreshold)
+            : 1;
+
+    int dimensionScale = 1 + (mindimension / bigScreenThreshold);
+
+    // choose larger of dimensionScale or dpiScale (most likely dimensionScale
+    // as dpiScale often misreported)
+    int autoScale = Math.max(dpiScale, dimensionScale);
+
+    // only make an automatic change if scale is changed and other conditions
+    // (OS is linux) apply, or if setHiDPI has been specified
+    if ((autoScale > 1 && isLinux) || setHiDPI)
+    {
+      setHiDPIScale(autoScale);
+      return;
+    }
+
+    // looks like we're not doing any scaling
+    doneInit = true;
+  }
+
+  public static void setHiDPIScale(int s)
+  {
+    scale = s;
+    allowScalePropertyArg = true;
+    doneInit = true;
+  }
+
+  public static String getScalePropertyArg()
+  {
+    init();
+    // HiDPI setting. Just looking at Linux to start with. Test with Windows.
+    return allowScalePropertyArg ? "-D" + scalePropertyName + "=" + scale
+            : null;
+  }
+}
index 7849ba2..159374a 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
 package jalview.bin;
 
 /**
index ad87541..0410815 100644 (file)
@@ -4,7 +4,7 @@
   <parent>
     <groupId>com.threerings.getdown</groupId>
     <artifactId>getdown</artifactId>
-    <version>1.8.3-1.2.4_FJVL</version>
+    <version>1.8.3-1.2.6_FJVL</version>
   </parent>
 
   <artifactId>getdown-launcher</artifactId>
index 3f9b4a2..25faf6f 100755 (executable)
@@ -3,7 +3,7 @@
 if [ x$JVLVERSION != x ]; then
   export VERSION=$JVLVERSION
 else
-  export VERSION=1.8.3-1.2.4_JVL
+  export VERSION=1.8.3-1.2.6_JVL
 fi
 
 if [ x${VERSION%_JVL} = x$VERSION ]; then
index 2ca4aa1..0011325 100644 (file)
@@ -10,7 +10,7 @@
   <groupId>com.threerings.getdown</groupId>
   <artifactId>getdown</artifactId>
   <packaging>pom</packaging>
-  <version>1.8.3-1.2.4_FJVL</version>
+  <version>1.8.3-1.2.6_FJVL</version>
 
   <name>getdown</name>
   <description>An application installer and updater.</description>
index 9c0f96e..6748a25 100644 (file)
Binary files a/j11lib/getdown-core.jar and b/j11lib/getdown-core.jar differ
index 9c0f96e..6748a25 100644 (file)
Binary files a/j8lib/getdown-core.jar and b/j8lib/getdown-core.jar differ
index 35d6aa3..751461f 100755 (executable)
  */
 package jalview.bin;
 
-import jalview.datamodel.PDBEntry;
-import jalview.gui.UserDefinedColours;
-import jalview.schemes.ColourSchemeLoader;
-import jalview.schemes.ColourSchemes;
-import jalview.schemes.UserColourScheme;
-import jalview.structure.StructureImportSettings;
-import jalview.urls.IdOrgSettings;
-import jalview.util.ColorUtils;
-import jalview.ws.sifts.SiftsSettings;
-
 import java.awt.Color;
 import java.io.BufferedReader;
 import java.io.File;
@@ -46,12 +36,26 @@ import java.util.Locale;
 import java.util.Properties;
 import java.util.StringTokenizer;
 import java.util.TreeSet;
+import java.util.regex.Pattern;
+
+import javax.swing.LookAndFeel;
+import javax.swing.UIManager;
 
 import org.apache.log4j.ConsoleAppender;
 import org.apache.log4j.Level;
 import org.apache.log4j.Logger;
 import org.apache.log4j.SimpleLayout;
 
+import jalview.datamodel.PDBEntry;
+import jalview.gui.UserDefinedColours;
+import jalview.schemes.ColourSchemeLoader;
+import jalview.schemes.ColourSchemes;
+import jalview.schemes.UserColourScheme;
+import jalview.structure.StructureImportSettings;
+import jalview.urls.IdOrgSettings;
+import jalview.util.ColorUtils;
+import jalview.ws.sifts.SiftsSettings;
+
 /**
  * Stores and retrieves Jalview Application Properties Lists and fields within
  * list entries are separated by '|' symbols unless otherwise stated (|) clauses
@@ -435,7 +439,8 @@ public class Cache
 
     String jnlpVersion = System.getProperty("jalview.version");
 
-    // jnlpVersion will be null if a latest version check for the channel needs to
+    // jnlpVersion will be null if a latest version check for the channel needs
+    // to
     // be done
     // Dont do this check if running in headless mode
 
@@ -555,8 +560,8 @@ public class Cache
     new BuildDetails(codeVersion, null, codeInstallation);
     if (printV && reportVersion)
     {
-      System.out
-            .println("Jalview Version: " + codeVersion + codeInstallation);
+      System.out.println(
+              "Jalview Version: " + codeVersion + codeInstallation);
     }
   }
 
@@ -1099,16 +1104,20 @@ public class Cache
   public static String getVersionDetailsForConsole()
   {
     StringBuilder sb = new StringBuilder();
-    sb.append("Jalview Version: " + jalview.bin.Cache.getDefault("VERSION", "TEST"));
+    sb.append("Jalview Version: "
+            + jalview.bin.Cache.getDefault("VERSION", "TEST"));
     sb.append("\n");
     sb.append("Jalview Installation: "
             + jalview.bin.Cache.getDefault("INSTALLATION", "unknown"));
     sb.append("\n");
-    sb.append("Build Date: " + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
+    sb.append("Build Date: "
+            + jalview.bin.Cache.getDefault("BUILD_DATE", "unknown"));
     sb.append("\n");
     sb.append("Java version: " + System.getProperty("java.version"));
     sb.append("\n");
-    sb.append(System.getProperty("os.arch") + " " + System.getProperty("os.name") + " " + System.getProperty("os.version"));
+    sb.append(System.getProperty("os.arch") + " "
+            + System.getProperty("os.name") + " "
+            + System.getProperty("os.version"));
     sb.append("\n");
     appendIfNotNull(sb, "Install4j version: ",
             System.getProperty("sys.install4jVersion"), "\n", null);
@@ -1116,7 +1125,12 @@ public class Cache
             System.getProperty("installer_template_version"), "\n", null);
     appendIfNotNull(sb, "Launcher version: ",
             System.getProperty("launcher_version"), "\n", null);
-    if (jalview.bin.Cache.getDefault("VERSION", "TEST").equals("DEVELOPMENT")) {
+    LookAndFeel laf = UIManager.getLookAndFeel();
+    String lafName = laf == null?"Not obtained":laf.getName();
+    String lafClass = laf == null?"unknown":laf.getClass().getName();
+    appendIfNotNull(sb, "LookAndFeel: ", lafName+" ("+lafClass+")", "\n", null);
+    // Not displayed in release version ( determined by possible version number regex 9[9.]*9[.-_a9]* )
+    if (Pattern.matches("^\\d[\\d\\.]*\\d[\\.\\-\\w]*$", jalview.bin.Cache.getDefault("VERSION", "TEST"))) {
       appendIfNotNull(sb, "Getdown appdir: ",
               System.getProperty("getdownappdir"), "\n", null);
       appendIfNotNull(sb, "Java home: ", System.getProperty("java.home"),
diff --git a/src/jalview/bin/HiDPISetting.java b/src/jalview/bin/HiDPISetting.java
new file mode 100644 (file)
index 0000000..497900f
--- /dev/null
@@ -0,0 +1,180 @@
+package jalview.bin;
+
+import java.awt.HeadlessException;
+import java.awt.Toolkit;
+
+public class HiDPISetting
+{
+  private static final int hidpiThreshold = 160;
+
+  private static final int hidpiMultiThreshold = 240;
+
+  private static final int bigScreenThreshold = 1400;
+
+  private static final String scalePropertyName = "sun.java2d.uiScale";
+
+  private static final boolean isLinux;
+
+  // private static final boolean isAMac;
+
+  // private static final boolean isWindows;
+
+  public static final String setHiDPIPropertyName = "setHiDPI";
+
+  public static final String setHiDPIScalePropertyName = "setHiDPIScale";
+
+  private static boolean setHiDPI = false;
+
+  private static int setHiDPIScale = 0;
+
+  public static int dpi = 0;
+
+  public static int mindimension = 0;
+
+  public static int width = 0;
+
+  public static int scale = 0;
+
+  private static boolean doneInit = false;
+
+  private static boolean allowScalePropertyArg = false;
+
+  static
+  {
+    String system = System.getProperty("os.name") == null ? null
+            : System.getProperty("os.name").toLowerCase();
+    if (system != null)
+    {
+      isLinux = system.indexOf("linux") > -1;
+      // isAMac = system.indexOf("mac") > -1;
+      // isWindows = system.indexOf("windows") > -1;
+    }
+    else
+    {
+      isLinux = false;
+      // isAMac = isWindows = false;
+    }
+  }
+
+  private static void init()
+  {
+    if (doneInit)
+    {
+      return;
+    }
+
+    // get and use command line property values first
+    String setHiDPIProperty = System.getProperty(setHiDPIPropertyName);
+    setHiDPI = setHiDPIProperty != null
+            && setHiDPIProperty.equalsIgnoreCase("true");
+
+    String setHiDPIScaleProperty = System
+            .getProperty(setHiDPIScalePropertyName);
+    if (setHiDPIScaleProperty != null)
+    {
+      try
+      {
+        setHiDPIScale = Integer.parseInt(setHiDPIScaleProperty);
+      } catch (NumberFormatException e)
+      {
+        System.err.println(setHiDPIScalePropertyName + " property give ("
+                + setHiDPIScaleProperty + ") but not parseable as integer");
+      }
+    }
+    if (setHiDPI && setHiDPIScale > 0)
+    {
+      setHiDPIScale(setHiDPIScale);
+      return;
+    }
+
+    // check to see if the scale property has already been set by something else
+    // (e.g. the OS)
+    String existingProperty = System.getProperty(scalePropertyName);
+    if (existingProperty != null)
+    {
+      try
+      {
+        int existingPropertyVal = Integer.parseInt(existingProperty);
+        System.out.println("Existing " + scalePropertyName + " is "
+                + existingPropertyVal);
+        if (existingPropertyVal > 1)
+        {
+          setHiDPIScale(existingPropertyVal);
+          return;
+        }
+      } catch (NumberFormatException e)
+      {
+        System.out.println("Could not convert property " + scalePropertyName
+                + " vale '" + existingProperty + "' to number");
+      }
+    }
+
+    // Try and auto guess a good scale based on reported DPI (not trustworthy)
+    // and screen resolution (more trustworthy)
+
+    // get screen dpi
+    try
+    {
+      dpi = Toolkit.getDefaultToolkit().getScreenResolution();
+    } catch (HeadlessException e)
+    {
+      System.err.println("Cannot get screen resolution: " + e.getMessage());
+    }
+
+    // try and get screen size height and width
+    try
+    {
+      int height = Toolkit.getDefaultToolkit().getScreenSize().height;
+      int width = Toolkit.getDefaultToolkit().getScreenSize().width;
+      // using mindimension in case of portrait screens
+      mindimension = Math.min(height, width);
+    } catch (HeadlessException e)
+    {
+      System.err.println(
+              "Cannot get screen size height and width:" + e.getMessage());
+    }
+
+    // attempt at a formula for scaling based on screen dpi and mindimension.
+    // scale will be an integer >=1. This formula is based on some testing and
+    // guesswork!
+
+    // scale based on reported dpi. if dpi>hidpiThreshold then scale=2+multiples
+    // of hidpiMultiThreshold (else scale=1)
+    // (e.g. dpi of 110 scales 1. dpi of 120 scales 2. dpi of 360 scales 3)
+    int dpiScale = (dpi - hidpiThreshold > 0)
+            ? 2 + ((dpi - hidpiThreshold) / hidpiMultiThreshold)
+            : 1;
+
+    int dimensionScale = 1 + (mindimension / bigScreenThreshold);
+
+    // choose larger of dimensionScale or dpiScale (most likely dimensionScale
+    // as dpiScale often misreported)
+    int autoScale = Math.max(dpiScale, dimensionScale);
+
+    // only make an automatic change if scale is changed and other conditions
+    // (OS is linux) apply, or if setHiDPI has been specified
+    if ((autoScale > 1 && isLinux) || setHiDPI)
+    {
+      setHiDPIScale(autoScale);
+      return;
+    }
+
+    // looks like we're not doing any scaling
+    doneInit = true;
+  }
+
+  public static void setHiDPIScale(int s)
+  {
+    scale = s;
+    allowScalePropertyArg = true;
+    doneInit = true;
+  }
+
+  public static String getScalePropertyArg()
+  {
+    init();
+    // HiDPI setting. Just looking at Linux to start with. Test with Windows.
+    return allowScalePropertyArg ? "-D" + scalePropertyName + "=" + scale
+            : null;
+  }
+}
index 8c9d391..021aad6 100755 (executable)
  */
 package jalview.bin;
 
-import jalview.ext.so.SequenceOntology;
-import jalview.gui.AlignFrame;
-import jalview.gui.Desktop;
-import jalview.gui.PromptUserConfig;
-import jalview.io.AppletFormatAdapter;
-import jalview.io.BioJsHTMLOutput;
-import jalview.io.DataSourceType;
-import jalview.io.FileFormat;
-import jalview.io.FileFormatException;
-import jalview.io.FileFormatI;
-import jalview.io.FileLoader;
-import jalview.io.HtmlSvgOutput;
-import jalview.io.IdentifyFile;
-import jalview.io.NewickFile;
-import jalview.io.gff.SequenceOntologyFactory;
-import jalview.schemes.ColourSchemeI;
-import jalview.schemes.ColourSchemeProperty;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-import jalview.ws.jws2.Jws2Discoverer;
-
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -61,13 +40,33 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Vector;
 
-import javax.swing.LookAndFeel;
 import javax.swing.UIManager;
+import javax.swing.UIManager.LookAndFeelInfo;
 
 import com.threerings.getdown.util.LaunchUtil;
 
 import groovy.lang.Binding;
 import groovy.util.GroovyScriptEngine;
+import jalview.ext.so.SequenceOntology;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.PromptUserConfig;
+import jalview.io.AppletFormatAdapter;
+import jalview.io.BioJsHTMLOutput;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FileFormatException;
+import jalview.io.FileFormatI;
+import jalview.io.FileLoader;
+import jalview.io.HtmlSvgOutput;
+import jalview.io.IdentifyFile;
+import jalview.io.NewickFile;
+import jalview.io.gff.SequenceOntologyFactory;
+import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ColourSchemeProperty;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.ws.jws2.Jws2Discoverer;
 
 /**
  * Main class for Jalview Application <br>
@@ -183,7 +182,7 @@ public class Jalview
    * main class for Jalview application
    * 
    * @param args
-   *               open <em>filename</em>
+   *          open <em>filename</em>
    */
   public static void main(String[] args)
   {
@@ -198,22 +197,24 @@ public class Jalview
   {
     System.setSecurityManager(null);
     System.out
-            .println("Java version: "
-                    + System.getProperty("java.version"));
+            .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("Install4j version: " + val);
+    if (val != null)
+    {
+      System.out.println("Install4j version: " + val);
     }
     val = System.getProperty("installer_template_version");
-    if (val != null) {
+    if (val != null)
+    {
       System.out.println("Install4j template version: " + val);
     }
     val = System.getProperty("launcher_version");
-    if (val != null) {
+    if (val != null)
+    {
       System.out.println("Launcher version: " + val);
     }
 
@@ -296,49 +297,88 @@ public class Jalview
 
     desktop = null;
 
-    try
+    // property laf = "crossplatform", "system", "gtk", "metal" or "mac"
+    // If not set (or chosen laf fails), use the normal SystemLaF and if on Mac,
+    // try Quaqua/Vaqua.
+    String lafProp = System.getProperty("laf");
+    String lafSetting = Cache.getDefault("PREFERRED_LAF", null);
+    String laf = "none";
+    if (lafProp != null)
     {
-      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
-    } catch (Exception ex)
+      laf = lafProp;
+    }
+    else if (lafSetting != null)
     {
-      System.err.println("Unexpected Look and Feel Exception");
-      ex.printStackTrace();
+      laf = lafSetting;
     }
-    if (Platform.isAMac())
+    boolean lafSet = false;
+    switch (laf)
     {
-
-      LookAndFeel lookAndFeel = ch.randelshofer.quaqua.QuaquaManager
-              .getLookAndFeel();
-      System.setProperty("com.apple.mrj.application.apple.menu.about.name",
-              "Jalview");
-      System.setProperty("apple.laf.useScreenMenuBar", "true");
-      if (lookAndFeel != null)
+    case "crossplatform":
+      lafSet = setCrossPlatformLookAndFeel();
+      if (!lafSet)
       {
-        try
-        {
-          UIManager.setLookAndFeel(lookAndFeel);
-        } catch (Throwable e)
-        {
-          System.err.println(
-                  "Failed to set QuaQua look and feel: " + e.toString());
-        }
+        System.err.println("Could not set requested laf=" + laf);
       }
-      if (lookAndFeel == null
-              || !(lookAndFeel.getClass().isAssignableFrom(
-                      UIManager.getLookAndFeel().getClass()))
-              || !UIManager.getLookAndFeel().getClass().toString()
-                      .toLowerCase().contains("quaqua"))
+      break;
+    case "system":
+      lafSet = setSystemLookAndFeel();
+      if (!lafSet)
       {
-        try
-        {
-          System.err.println(
-                  "Quaqua LaF not available on this plaform. Using VAqua(4).\nSee https://issues.jalview.org/browse/JAL-2976");
-          UIManager.setLookAndFeel("org.violetlib.aqua.AquaLookAndFeel");
-        } catch (Throwable e)
-        {
-          System.err.println(
-                  "Failed to reset look and feel: " + e.toString());
-        }
+        System.err.println("Could not set requested laf=" + laf);
+      }
+      break;
+    case "gtk":
+      lafSet = setGtkLookAndFeel();
+    {
+      System.err.println("Could not set requested laf=" + laf);
+    }
+      break;
+    case "metal":
+      lafSet = setMetalLookAndFeel();
+    {
+      System.err.println("Could not set requested laf=" + laf);
+    }
+      break;
+    case "nimbus":
+      lafSet = setNimbusLookAndFeel();
+    {
+      System.err.println("Could not set requested laf=" + laf);
+    }
+      break;
+    case "quaqua":
+      lafSet = setQuaquaLookAndFeel();
+    {
+      System.err.println("Could not set requested laf=" + laf);
+    }
+      break;
+    case "vaqua":
+      lafSet = setVaquaLookAndFeel();
+    {
+      System.err.println("Could not set requested laf=" + laf);
+    }
+      break;
+    case "mac":
+      lafSet = setMacLookAndFeel();
+      if (!lafSet)
+      {
+        System.err.println("Could not set requested laf=" + laf);
+      }
+      break;
+    case "none":
+      break;
+    default:
+      System.err.println("Requested laf=" + laf + " not implemented");
+    }
+    if (!lafSet)
+    {
+      setSystemLookAndFeel();
+      if (Platform.isLinux()) {
+        setMetalLookAndFeel();
+      }
+      if (Platform.isAMac())
+      {
+        setMacLookAndFeel();
       }
     }
 
@@ -353,6 +393,7 @@ public class Jalview
 
     if (!headless)
     {
+
       desktop = new Desktop();
       desktop.setInBatchMode(true); // indicate we are starting up
 
@@ -760,6 +801,111 @@ public class Jalview
     }
   }
 
+  private static boolean setCrossPlatformLookAndFeel()
+  {
+    boolean set = false;
+    try
+    {
+      UIManager.setLookAndFeel(
+              UIManager.getCrossPlatformLookAndFeelClassName());
+      set = true;
+    } catch (Exception ex)
+    {
+      System.err.println("Unexpected Look and Feel Exception");
+      ex.printStackTrace();
+    }
+    return set;
+  }
+
+  private static boolean setSystemLookAndFeel()
+  {
+    boolean set = false;
+    try
+    {
+      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+      set = true;
+    } catch (Exception ex)
+    {
+      System.err.println("Unexpected Look and Feel Exception");
+      ex.printStackTrace();
+    }
+    return set;
+  }
+
+  private static boolean setSpecificLookAndFeel(String name,
+          String className, boolean nameStartsWith)
+  {
+    boolean set = false;
+    try
+    {
+      for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
+      {
+        if (info.getName() != null && nameStartsWith
+                ? info.getName().toLowerCase()
+                        .startsWith(name.toLowerCase())
+                : info.getName().toLowerCase().equals(name.toLowerCase()))
+        {
+          className = info.getClassName();
+          break;
+        }
+      }
+      UIManager.setLookAndFeel(className);
+      set = true;
+    } catch (Exception ex)
+    {
+      System.err.println("Unexpected Look and Feel Exception");
+      ex.printStackTrace();
+    }
+    return set;
+  }
+
+  private static boolean setGtkLookAndFeel()
+  {
+    return setSpecificLookAndFeel("gtk",
+            "com.sun.java.swing.plaf.gtk.GTKLookAndFeel", true);
+  }
+
+  private static boolean setMetalLookAndFeel()
+  {
+    return setSpecificLookAndFeel("metal",
+            "javax.swing.plaf.metal.MetalLookAndFeel", false);
+  }
+
+  private static boolean setNimbusLookAndFeel()
+  {
+    return setSpecificLookAndFeel("nimbus",
+            "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
+  }
+
+  private static boolean setQuaquaLookAndFeel()
+  {
+    return setSpecificLookAndFeel("quaqua",
+            ch.randelshofer.quaqua.QuaquaManager.getLookAndFeel().getClass()
+                    .getName(),
+            false);
+  }
+
+  private static boolean setVaquaLookAndFeel()
+  {
+    return setSpecificLookAndFeel("vaqua",
+            "org.violetlib.aqua.AquaLookAndFeel", false);
+  }
+
+  private static boolean setMacLookAndFeel()
+  {
+    boolean set = false;
+    System.setProperty("com.apple.mrj.application.apple.menu.about.name",
+            "Jalview");
+    System.setProperty("apple.laf.useScreenMenuBar", "true");
+    set = setQuaquaLookAndFeel();
+    if ((!set) || !UIManager.getLookAndFeel().getClass().toString()
+            .toLowerCase().contains("quaqua"))
+    {
+      set = setVaquaLookAndFeel();
+    }
+    return set;
+  }
+
   private static void showUsage()
   {
     System.out.println(
@@ -836,10 +982,10 @@ public class Jalview
    * Locate the given string as a file and pass it to the groovy interpreter.
    * 
    * @param groovyscript
-   *                         the script to execute
+   *          the script to execute
    * @param jalviewContext
-   *                         the Jalview Desktop object passed in to the groovy
-   *                         binding as the 'Jalview' object.
+   *          the Jalview Desktop object passed in to the groovy binding as the
+   *          'Jalview' object.
    */
   private void executeGroovyScript(String groovyscript, AlignFrame af)
   {
@@ -968,8 +1114,8 @@ public class Jalview
   }
 
   /**
-   * Quit method delegates to Desktop.quit - unless running in headless mode when
-   * it just ends the JVM
+   * Quit method delegates to Desktop.quit - unless running in headless mode
+   * when it just ends the JVM
    */
   public void quit()
   {
index fb1c5cd..fecacbe 100644 (file)
@@ -49,8 +49,8 @@ public class Launcher
 
   /**
    * main method for jalview.bin.Launcher. This restarts the same JRE's JVM with
-   * the same arguments but with memory adjusted based on extracted -jvmmempc and
-   * -jvmmemmax application arguments. If on a Mac then extra dock:icon and
+   * the same arguments but with memory adjusted based on extracted -jvmmempc
+   * and -jvmmemmax application arguments. If on a Mac then extra dock:icon and
    * dock:name arguments are also set.
    * 
    * @param args
@@ -130,7 +130,7 @@ public class Launcher
     if (!memSet)
     {
       long maxMemLong = MemorySetting.getMemorySetting(jvmmemmax, jvmmempc);
-      
+
       if (maxMemLong > 0)
       {
         memSetting = "-Xmx" + Long.toString(maxMemLong);
@@ -153,6 +153,14 @@ public class Launcher
       }
     }
 
+    String scalePropertyArg = HiDPISetting.getScalePropertyArg();
+    if (scalePropertyArg != null)
+    {
+      System.out.println("Running " + startClass + " with scale setting "
+              + scalePropertyArg);
+      command.add(scalePropertyArg);
+    }
+
     command.add(startClass);
     command.addAll(arguments);
 
@@ -160,7 +168,8 @@ public class Launcher
 
     // System.out.println("COMMAND: " + String.join(" ", builder.command()));
     System.out.println("Running " + startClass + " with "
-            + (memSetting == null ? "no memory setting" : memSetting));
+            + (memSetting == null ? "no memory setting"
+                    : ("memory setting " + memSetting)));
 
     if (Boolean.parseBoolean(System.getProperty("launcherstop")))
     {
@@ -176,7 +185,8 @@ public class Launcher
       if (e.getMessage().toLowerCase().contains("memory"))
       {
         System.out.println("Caught a memory exception: " + e.getMessage());
-        // Probably the "Cannot allocate memory" error, try without the memory setting
+        // Probably the "Cannot allocate memory" error, try without the memory
+        // setting
         ArrayList<String> commandNoMem = new ArrayList<>();
         for (int i = 0; i < command.size(); i++)
         {
index e8558fa..a5bee7c 100644 (file)
@@ -29,11 +29,23 @@ import java.awt.event.MouseEvent;
  */
 public class Platform
 {
-  private static Boolean isAMac = null, isWindows = null;
+  private static Boolean isAMac = null, isWindows = null, isLinux = null;
 
   private static Boolean isHeadless = null;
 
   /**
+   * added to check LaF for Linux
+   * 
+   * @return
+   */
+  public static boolean isLinux()
+  {
+    return (isLinux == null
+            ? (isLinux = (System.getProperty("os.name").indexOf("Linux") >= 0))
+            : isLinux);
+  }
+
+  /**
    * sorry folks - Macs really are different
    * 
    * @return true if we do things in a special way.
@@ -131,7 +143,8 @@ public class Platform
       {
         return false;
       }
-      return (jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx() // .getMenuShortcutKeyMaskEx()
+      return (jalview.util.ShortcutKeyMaskExWrapper
+              .getMenuShortcutKeyMaskEx() // .getMenuShortcutKeyMaskEx()
               & jalview.util.ShortcutKeyMaskExWrapper
                       .getModifiersEx(e)) != 0; // getModifiers()) != 0;
     }
@@ -139,8 +152,8 @@ public class Platform
   }
 
   /**
-   * A (case sensitive) file path comparator that ignores the difference between /
-   * and \
+   * A (case sensitive) file path comparator that ignores the difference between
+   * / and \
    * 
    * @param path1
    * @param path2