Merge branch 'improvement/JAL-1988+JAL-3416_Java8_macOS_APQHandlers_and_FlatLaF_optio...
authorJim Procter <j.procter@dundee.ac.uk>
Wed, 15 Jun 2022 14:41:53 +0000 (15:41 +0100)
committerJim Procter <j.procter@dundee.ac.uk>
Wed, 15 Jun 2022 14:41:53 +0000 (15:41 +0100)
j11lib/flatlaf-2.3.jar [new file with mode: 0644]
j11lib/flatlaf-extras-2.3.jar [new file with mode: 0644]
j8lib/flatlaf-2.3.jar [new file with mode: 0644]
j8lib/flatlaf-extras-2.3.jar [new file with mode: 0644]
src/jalview/bin/Jalview.java
src/jalview/gui/APQHandlers.java [deleted file]
src/jalview/gui/Desktop.java
src/jalview/jbgui/APQHandlers.java [new file with mode: 0644]
src/jalview/jbgui/GDesktop.java

diff --git a/j11lib/flatlaf-2.3.jar b/j11lib/flatlaf-2.3.jar
new file mode 100644 (file)
index 0000000..9f292d2
Binary files /dev/null and b/j11lib/flatlaf-2.3.jar differ
diff --git a/j11lib/flatlaf-extras-2.3.jar b/j11lib/flatlaf-extras-2.3.jar
new file mode 100644 (file)
index 0000000..39e9701
Binary files /dev/null and b/j11lib/flatlaf-extras-2.3.jar differ
diff --git a/j8lib/flatlaf-2.3.jar b/j8lib/flatlaf-2.3.jar
new file mode 100644 (file)
index 0000000..9f292d2
Binary files /dev/null and b/j8lib/flatlaf-2.3.jar differ
diff --git a/j8lib/flatlaf-extras-2.3.jar b/j8lib/flatlaf-extras-2.3.jar
new file mode 100644 (file)
index 0000000..39e9701
Binary files /dev/null and b/j8lib/flatlaf-extras-2.3.jar differ
index fc4c821..fd1783a 100755 (executable)
@@ -20,6 +20,7 @@
  */
 package jalview.bin;
 
+import java.awt.Color;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -44,9 +45,12 @@ import java.util.logging.ConsoleHandler;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
 import javax.swing.UIManager.LookAndFeelInfo;
 
+import com.formdev.flatlaf.FlatLightLaf;
+import com.formdev.flatlaf.util.SystemInfo;
 import com.threerings.getdown.util.LaunchUtil;
 
 //import edu.stanford.ejalbert.launching.IBrowserLaunching;
@@ -862,8 +866,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");
@@ -915,6 +919,13 @@ public class Jalview
         Console.error("Could not set requested laf=" + laf);
       }
       break;
+    case "flat":
+      lafSet = setFlatLookAndFeel();
+      if (!lafSet)
+      {
+        Console.error("Could not set requested laf=" + laf);
+      }
+      break;
     case "quaqua":
       lafSet = setQuaquaLookAndFeel();
       if (!lafSet)
@@ -1035,6 +1046,45 @@ public class Jalview
             "javax.swing.plaf.nimbus.NimbusLookAndFeel", false);
   }
 
+  private static boolean setFlatLookAndFeel()
+  {
+    boolean set = setSpecificLookAndFeel("flatlaf light",
+            "com.formdev.flatlaf.FlatLightLaf", false);
+    if (set)
+    {
+      if (Platform.isMac())
+      {
+        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)
+        {
+          Desktop.desktop.getRootPane()
+                  .putClientProperty("apple.awt.fullWindowContent", true);
+          Desktop.desktop.getRootPane()
+                  .putClientProperty("apple.awt.transparentTitleBar", true);
+        }
+
+        SwingUtilities.invokeLater(() -> {
+          FlatLightLaf.setup();
+        });
+      }
+
+      UIManager.put("TabbedPane.showTabSeparators", 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);
+    }
+    return set;
+  }
+
   private static boolean setQuaquaLookAndFeel()
   {
     return setSpecificLookAndFeel("quaqua",
diff --git a/src/jalview/gui/APQHandlers.java b/src/jalview/gui/APQHandlers.java
deleted file mode 100644 (file)
index e5e328f..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * 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.gui;
-
-import jalview.bin.Cache;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-
-import java.awt.Desktop;
-import java.awt.desktop.AboutEvent;
-import java.awt.desktop.AboutHandler;
-import java.awt.desktop.PreferencesEvent;
-import java.awt.desktop.PreferencesHandler;
-import java.awt.desktop.QuitEvent;
-import java.awt.desktop.QuitHandler;
-import java.awt.desktop.QuitResponse;
-import java.awt.desktop.QuitStrategy;
-
-import javax.swing.JOptionPane;
-
-public class APQHandlers
-{
-  private static boolean setAPQHandlers = false;
-
-  public APQHandlers()
-  {
-  }
-
-  protected static boolean setAPQHandlers(
-          jalview.gui.Desktop jalviewDesktop)
-  {
-    // flagging this test to avoid unnecessary reflection
-    if (!setAPQHandlers)
-    {
-      // see if the Quit, About and Preferences handlers are available
-      Class desktopClass = Desktop.class;
-      Desktop hdesktop = Desktop.getDesktop();
-
-      try
-      {
-        Float specversion = Float.parseFloat(
-                System.getProperty("java.specification.version"));
-
-        if (specversion >= 9)
-        {
-          if (Platform.isAMacAndNotJS())
-          {
-            if (desktopClass.getDeclaredMethod("setAboutHandler",
-                    new Class[]
-                    { AboutHandler.class }) != null)
-            {
-
-              hdesktop.setAboutHandler(new AboutHandler()
-              {
-                @Override
-                public void handleAbout(AboutEvent e)
-                {
-                  jalviewDesktop.aboutMenuItem_actionPerformed(null);
-                }
-              });
-
-            }
-
-            if (desktopClass.getDeclaredMethod("setPreferencesHandler",
-                    new Class[]
-                    { PreferencesHandler.class }) != null)
-            {
-
-              hdesktop.setPreferencesHandler(new PreferencesHandler()
-              {
-                @Override
-                public void handlePreferences(PreferencesEvent e)
-                {
-                  jalviewDesktop.preferences_actionPerformed(null);
-                }
-              });
-
-            }
-
-            if (desktopClass.getDeclaredMethod("setQuitHandler",
-                    new Class[]
-                    { QuitHandler.class }) != null)
-            {
-
-              hdesktop.setQuitHandler(new QuitHandler()
-              {
-                @Override
-                public void handleQuitRequestWith(QuitEvent e,
-                        QuitResponse r)
-                {
-                  boolean confirmQuit = Cache.getDefault(
-                          jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT, true);
-                  int n;
-                  if (confirmQuit)
-                  {
-                    n = JOptionPane.showConfirmDialog(null,
-                            MessageManager.getString("label.quit_jalview"),
-                            MessageManager.getString("action.quit"),
-                            JOptionPane.OK_CANCEL_OPTION,
-                            JOptionPane.PLAIN_MESSAGE, null);
-                  }
-                  else
-                  {
-                    n = JOptionPane.OK_OPTION;
-                  }
-                  if (n == JOptionPane.OK_OPTION)
-                  {
-                    System.out.println("Shortcut Quit confirmed by user");
-                    jalviewDesktop.quit();
-                    r.performQuit(); // probably won't reach this line, but just
-                                     // in
-                                     // case
-                  }
-                  else
-                  {
-                    r.cancelQuit();
-                    System.out.println("Shortcut Quit cancelled by user");
-                  }
-                }
-              });
-              hdesktop.setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
-
-            }
-          }
-          setAPQHandlers = true;
-        }
-        else
-        {
-          System.out.println(
-                  "Not going to try setting APQ Handlers as java.spec.version is "
-                          + specversion);
-        }
-
-      } catch (Exception e)
-      {
-        System.out.println(
-                "Exception when looking for About, Preferences, Quit Handlers");
-        // e.printStackTrace();
-      } catch (Throwable t)
-      {
-        System.out.println(
-                "Throwable when looking for About, Preferences, Quit Handlers");
-        // t.printStackTrace();
-      }
-
-    }
-
-    return setAPQHandlers;
-  }
-
-}
index aeb0fac..3ad5384 100644 (file)
@@ -20,8 +20,6 @@
  */
 package jalview.gui;
 
-import java.util.Locale;
-
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
@@ -64,6 +62,7 @@ import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.ListIterator;
+import java.util.Locale;
 import java.util.Vector;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -183,7 +182,7 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   private static final String EXPERIMENTAL_FEATURES = "EXPERIMENTAL_FEATURES";
 
-  protected static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
+  public static final String CONFIRM_KEYBOARD_QUIT = "CONFIRM_KEYBOARD_QUIT";
 
   public static HashMap<String, FileWriter> savingFiles = new HashMap<String, FileWriter>();
 
@@ -444,24 +443,6 @@ public class Desktop extends jalview.jbgui.GDesktop
       }
     }
 
-    /**
-     * APQHandlers sets handlers for About, Preferences and Quit actions
-     * peculiar to macOS's application menu. APQHandlers will check to see if a
-     * handler is supported before setting it.
-     */
-    try
-    {
-      APQHandlers.setAPQHandlers(this);
-    } catch (Exception e)
-    {
-      System.out.println("Cannot set APQHandlers");
-      // e.printStackTrace();
-    } catch (Throwable t)
-    {
-      jalview.bin.Console
-              .warn("Error setting APQHandlers: " + t.toString());
-      jalview.bin.Console.trace(Cache.getStackTraceString(t));
-    }
     setIconImages(ChannelProperties.getIconList());
 
     addWindowListener(new WindowAdapter()
diff --git a/src/jalview/jbgui/APQHandlers.java b/src/jalview/jbgui/APQHandlers.java
new file mode 100644 (file)
index 0000000..e18ec44
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.jbgui;
+
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+
+import com.formdev.flatlaf.extras.FlatDesktop;
+
+import jalview.util.MessageManager;
+
+public class APQHandlers
+{
+  protected static boolean setAPQHandlers = false;
+
+  public static boolean setAPQHandlers(GDesktop desktop)
+  {
+    FlatDesktop.setAboutHandler(() -> {
+      desktop.aboutMenuItem_actionPerformed(null);
+    });
+    FlatDesktop.setPreferencesHandler(() -> {
+      desktop.preferences_actionPerformed(null);
+    });
+    FlatDesktop.setQuitHandler(response -> {
+      boolean confirmQuit = jalview.bin.Cache
+              .getDefault(jalview.gui.Desktop.CONFIRM_KEYBOARD_QUIT, true);
+      boolean canQuit = !confirmQuit;
+      int n;
+      if (confirmQuit)
+      {
+        // ensure Jalview window is brought to front for Quit confirmation
+        // window to be
+        // visible
+
+        // this method of raising the Jalview window is broken in java
+        // jalviewDesktop.setVisible(true);
+        // jalviewDesktop.toFront();
+
+        // a better hack which works instead
+        JFrame dialogParent = new JFrame();
+        dialogParent.setAlwaysOnTop(true);
+
+        n = JOptionPane.showConfirmDialog(dialogParent,
+                MessageManager.getString("label.quit_jalview"),
+                MessageManager.getString("action.quit"),
+                JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE,
+                null);
+
+        dialogParent.setAlwaysOnTop(false);
+        dialogParent.dispose();
+      }
+      else
+      {
+        n = JOptionPane.OK_OPTION;
+      }
+      canQuit = (n == JOptionPane.OK_OPTION);
+      if (canQuit)
+      {
+        response.performQuit();
+      }
+      else
+      {
+        response.cancelQuit();
+      }
+    });
+
+    setAPQHandlers = true;
+
+    return setAPQHandlers;
+  }
+
+}
index e1224c2..f3d9a65 100755 (executable)
  */
 package jalview.jbgui;
 
-import jalview.api.AlignmentViewPanel;
-import jalview.io.FileFormatException;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-
 import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -35,6 +30,12 @@ import javax.swing.JMenu;
 import javax.swing.JMenuBar;
 import javax.swing.JMenuItem;
 
+import jalview.api.AlignmentViewPanel;
+import jalview.bin.Cache;
+import jalview.io.FileFormatException;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+
 /**
  * DOCUMENT ME!
  * 
@@ -139,6 +140,25 @@ public class GDesktop extends JFrame
    */
   private void jbInit() throws Exception
   {
+    /**
+     * APQHandlers sets handlers for About, Preferences and Quit actions
+     * peculiar to macOS's application menu. APQHandlers will check to see if a
+     * handler is supported before setting it.
+     */
+    try
+    {
+      APQHandlers.setAPQHandlers(this);
+    } catch (Exception e)
+    {
+      System.out.println("Cannot set APQHandlers");
+      // e.printStackTrace();
+    } catch (Throwable t)
+    {
+      jalview.bin.Console
+              .warn("Error setting APQHandlers: " + t.toString());
+      jalview.bin.Console.trace(Cache.getStackTraceString(t));
+    }
+
     setName("jalview-desktop");
     FileMenu.setText(MessageManager.getString("action.file"));
     HelpMenu.setText(MessageManager.getString("action.help"));
@@ -385,9 +405,12 @@ public class GDesktop extends JFrame
     FileMenu.add(loadState);
     FileMenu.addSeparator();
     FileMenu.add(quit);
-    HelpMenu.add(aboutMenuItem);
+    if (!APQHandlers.setAPQHandlers)
+    {
+      HelpMenu.add(aboutMenuItem);
+    }
     HelpMenu.add(documentationMenuItem);
-    if (!Platform.isAMacAndNotJS() || specversion < 11)
+    if (!APQHandlers.setAPQHandlers)
     {
       toolsMenu.add(preferences);
     }