JAL-4154 Add Platform.forArch method.
[jalview.git] / src / jalview / util / Platform.java
index 0a6a5c9..11b6270 100644 (file)
@@ -22,7 +22,10 @@ package jalview.util;
 
 import java.awt.Component;
 import java.awt.Dimension;
+import java.awt.GraphicsEnvironment;
+
 import java.awt.Toolkit;
+import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
 import java.io.BufferedReader;
 import java.io.File;
@@ -32,6 +35,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.Reader;
+import java.lang.reflect.Method;
 import java.net.URL;
 import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
@@ -43,6 +47,7 @@ import java.nio.file.attribute.BasicFileAttributes;
 import java.util.Date;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Properties;
 import java.util.logging.ConsoleHandler;
 import java.util.logging.Level;
@@ -58,7 +63,6 @@ import com.stevesoft.pat.Regex;
 import jalview.bin.Jalview;
 import jalview.javascript.json.JSON;
 import swingjs.api.JSUtilI;
-
 /**
  * System platform information used by Applet and Application
  * 
@@ -71,7 +75,7 @@ public class Platform
           false;
 
   private static Boolean isNoJSMac = null, isNoJSWin = null, isMac = null,
-          isWin = null;
+          isWin = null, isLinux = null;
 
   private static Boolean isHeadless = null;
 
@@ -94,8 +98,6 @@ public class Platform
       }
     }
   }
-  // private static Boolean isHeadless = null;
-
   /**
    * added to group mouse events into Windows and nonWindows (mac, unix, linux)
    * 
@@ -108,6 +110,56 @@ public class Platform
             : isMac);
   }
 
+  public static int SHORTCUT_KEY_MASK = (Platform.isMac()
+          ? KeyEvent.META_DOWN_MASK
+          : KeyEvent.CTRL_DOWN_MASK);
+
+  static
+  {
+    if (!GraphicsEnvironment.isHeadless())
+    {
+      // Using non-deprecated Extended key mask modifiers, but Java 8 has no
+      // getMenuShortcutKeyMaskEx method
+      Toolkit tk = Toolkit.getDefaultToolkit();
+      Method method = null;
+      try
+      {
+        method = tk.getClass().getMethod("getMenuShortcutKeyMaskEx");
+      } catch (Exception e)
+      {
+        System.err.println(
+                "Could not find Toolkit method getMenuShortcutKeyMaskEx. Trying getMenuShortcutKeyMask.");
+      }
+      if (method == null)
+      {
+        try
+        {
+          method = tk.getClass().getMethod("getMenuShortcutKeyMask");
+        } catch (Exception e)
+        {
+          System.err.println(
+                  "Could not find Toolkit method getMenuShortcutKeyMaskEx or getMenuShortcutKeyMask.");
+          e.printStackTrace();
+        }
+      }
+      if (method != null)
+      {
+        try
+        {
+          method.setAccessible(true);
+          SHORTCUT_KEY_MASK = ((int) method.invoke(tk, new Object[0]));
+        } catch (Exception e)
+        {
+          e.printStackTrace();
+        }
+      }
+      if (SHORTCUT_KEY_MASK <= 0xF)
+      {
+        // shift this into the extended region (was Java 8)
+        SHORTCUT_KEY_MASK = SHORTCUT_KEY_MASK << 6;
+      }
+    }
+  }
   /**
    * added to group mouse events into Windows and nonWindows (mac, unix, linux)
    * 
@@ -121,6 +173,19 @@ public class Platform
   }
 
   /**
+   * added to check LaF for Linux
+   * 
+   * @return
+   */
+  public static boolean isLinux()
+  {
+    return (isLinux == null
+            ? (isLinux = (System.getProperty("os.name")
+                    .indexOf("Linux") >= 0))
+            : isLinux);
+  }
+
+  /**
    * 
    * @return true if HTML5 JavaScript
    */
@@ -142,7 +207,7 @@ public class Platform
   }
 
   /**
-   * Check if we are on a Microsoft plaform...
+   * Check if we are on a Microsoft platform...
    * 
    * @return true if we have to cope with another platform variation
    */
@@ -152,7 +217,7 @@ public class Platform
   }
 
   /**
-   *
+   * 
    * @return true if we are running in non-interactive no UI mode
    */
   public static boolean isHeadless()
@@ -165,6 +230,147 @@ public class Platform
   }
 
   /**
+   * Construct the value that depends on the system architecture. The methods
+   * setting the value for subsequent platforms are chained after this call and
+   * finalized with a {@link PlatformDependentValue#value() value()} call.
+   * 
+   * Example: {@code
+   *   Platform.forArch(120).forMac(114).forWin(112).forLinux(115).value();
+   * }
+   * 
+   * @param <T>
+   *          type of the value
+   * @param defaultValue
+   *          default value used if platform not determined
+   * @return platform dependent value wrapper object
+   */
+  public static <T> PlatformDependentValue<T> forArch(T defaultValue)
+  {
+    return new PlatformDependentValue<T>(defaultValue);
+  }
+
+  /**
+   * 
+   * @author mmwarowny
+   *
+   * @param <T>
+   *          type of the value
+   */
+  public static class PlatformDependentValue<T>
+  {
+    private T defaultValue = null;
+
+    private T macValue = null;
+
+    private T winValue = null;
+
+    private T linuxValue = null;
+
+    private T jsValue = null;
+
+    private T headlessValue = null;
+
+    private PlatformDependentValue(T value)
+    {
+      Objects.requireNonNull(value);
+      defaultValue = value;
+    }
+
+    /**
+     * Set the value used on Mac platform.
+     * 
+     * @param value
+     *          parameter value
+     * @return
+     */
+    public PlatformDependentValue<T> forMac(T value)
+    {
+      Objects.requireNonNull(value);
+      macValue = value;
+      return this;
+    }
+
+    /**
+     * Set the value used on Windows platform.
+     * 
+     * @param value
+     *          parameter value
+     * @return
+     */
+    public PlatformDependentValue<T> forWin(T value)
+    {
+      Objects.requireNonNull(value);
+      winValue = value;
+      return this;
+    }
+
+    /**
+     * Set the value used on Linux platform.
+     * 
+     * @param value
+     *          parameter value
+     * @return
+     */
+    public PlatformDependentValue<T> forLinux(T value)
+    {
+      Objects.requireNonNull(value);
+      linuxValue = value;
+      return this;
+    }
+
+    /**
+     * Set the value used on JS platform.
+     * 
+     * @param value
+     *          parameter value
+     * @return
+     */
+    public PlatformDependentValue<T> forJS(T value)
+    {
+      Objects.requireNonNull(value);
+      jsValue = value;
+      return this;
+    }
+
+    /**
+     * Set the value used on headless platform. The headless value takes
+     * precedence over other platforms if set.
+     * 
+     * @param value
+     *          parameter value
+     * @return
+     */
+    public PlatformDependentValue<T> forHeadless(T value)
+    {
+      Objects.requireNonNull(value);
+      headlessValue = value;
+      return this;
+    }
+
+    /**
+     * Get the value of the parameter respecting the platform. The headless
+     * platform takes precedence over any other platform if it has the value
+     * set.
+     * 
+     * @return parameter value depending on the platform
+     */
+    public T value()
+    {
+      if (headlessValue != null && isHeadless())
+        return headlessValue;
+      if (macValue != null && isMac())
+        return macValue;
+      if (winValue != null && isWin())
+        return winValue;
+      if (linuxValue != null && isLinux())
+        return linuxValue;
+      if (jsValue != null && isJS())
+        return jsValue;
+      return defaultValue;
+    }
+  }
+
+  /**
    * 
    * @return nominal maximum command line length for this platform
    */
@@ -209,30 +415,14 @@ public class Platform
    */
   protected static boolean isControlDown(MouseEvent e, boolean aMac)
   {
-    if (!aMac)
-    {
-      return e.isControlDown();
-
-      // Jalview 2.11 code below: above is as amended for JalviewJS
-      // /*
-      // * answer false for right mouse button
-      // */
-      // if (e.isPopupTrigger())
-      // {
-      // return false;
-      // }
-      // return
-      // (jalview.util.ShortcutKeyMaskExWrapper.getMenuShortcutKeyMaskEx() //
-      // .getMenuShortcutKeyMaskEx()
-      // & jalview.util.ShortcutKeyMaskExWrapper
-      // .getModifiersEx(e)) != 0; // getModifiers()) != 0;
-    }
-    // answer false for right mouse button
-    // shortcut key will be META for a Mac
-    return !e.isPopupTrigger()
-            && (Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
-                    & e.getModifiers()) != 0;
-    // could we use e.isMetaDown() here?
+    //
+    // System.out.println(e.isPopupTrigger()
+    // + " " + ((SHORTCUT_KEY_MASK & e.getModifiersEx()) != 0)
+    // + " " + e.isControlDown());
+    return (aMac
+            ? !e.isPopupTrigger()
+                    && (SHORTCUT_KEY_MASK & e.getModifiersEx()) != 0
+            : e.isControlDown());
   }
 
   // BH: I don't know about that previous method. Here is what SwingJS uses.
@@ -474,6 +664,7 @@ public class Platform
   public static String getUniqueAppletID()
   {
     return (isJS ? (String) jsutil.getAppletAttribute("_uniqueId") : null);
+
   }
 
   /**
@@ -573,6 +764,7 @@ public class Platform
               "StringJS does not support FileReader parsing for JSON -- but it could...");
     }
     return JSON.parse(r);
+
   }
 
   /**
@@ -587,13 +779,11 @@ public class Platform
   public static void streamToFile(InputStream is, File outFile)
           throws IOException
   {
-
     if (isJS)
     {
       jsutil.setFileBytes(outFile, is);
       return;
     }
-
     FileOutputStream fio = new FileOutputStream(outFile);
     try
     {
@@ -626,10 +816,14 @@ public class Platform
     if (isJS)
     {
       jsutil.addDirectDatabaseCall(domain);
-
       System.out.println(
-              "Platform adding known access-control-allow-origin * for domain "
-                      + domain);
+            "Platform adding known access-control-allow-origin * for domain "
+                    + domain);
+      /**
+       * @j2sNative
+       * 
+       *            J2S.addDirectDatabaseCall(domain);
+       */
     }
 
   }
@@ -640,21 +834,20 @@ public class Platform
    */
   public static void getURLCommandArguments()
   {
-
-    try {
-    /**
-     * Retrieve the first query field as command arguments to Jalview. Include
-     * only if prior to "?j2s" or "&j2s" or "#". Assign the applet's __Info.args
-     * element to this value.
-     * 
-     * @j2sNative var a =
-     *            decodeURI((document.location.href.replace("&","?").split("?j2s")[0]
-     *            + "?").split("?")[1].split("#")[0]); a &&
-     *            (J2S.thisApplet.__Info.args = a.split(" "));
-     *            
-     *            System.out.println("URL arguments: " + a);
-     */
-    } catch (Throwable t) {
+      try {
+      /**
+       * Retrieve the first query field as command arguments to Jalview. Include
+       * only if prior to "?j2s" or "&j2s" or "#". Assign the applet's
+       * __Info.args element to this value.
+       * 
+       * @j2sNative var a =
+       *            decodeURI((document.location.href.replace("&","?").split("?j2s")[0]
+       *            + "?").split("?")[1].split("#")[0]); a && (System.out.println("URL arguments detected were "+a)) &&
+       *            (J2S.thisApplet.__Info.urlargs = a.split(" ")); 
+       *            (!J2S.thisApplet.__Info.args || J2S.thisApplet.__Info.args == "" || J2S.thisApplet.__Info.args == "??") && (J2S.thisApplet.__Info.args = a) && (System.out.println("URL arguments were passed to J2S main."));
+       */
+    } catch (Throwable t)
+    {
     }
   }
 
@@ -680,7 +873,6 @@ public class Platform
     String p2 = path2.replace('\\', '/');
     return p1.equals(p2);
   }
-
   ///////////// JAL-3253 Applet additions //////////////
 
   /**
@@ -808,17 +1000,18 @@ public class Platform
   {
     if (isJS)
     {
-      jsutil.setAppletAttribute("app", j);
+      jsutil.setAppClass(j);
     }
   }
 
   /**
    *
-   * If this frame ia embedded in a web page, return a known type.
+   * If this frame is embedded in a web page, return a known type.
    * 
    * @param frame
    *          a JFrame or JInternalFrame
    * @param type
+   *          "name", "node", "init", "dim", or any DOM attribute, such as "id"
    * @return null if frame is not embedded.
    */
   public static Object getEmbeddedAttribute(Component frame, String type)
@@ -934,17 +1127,17 @@ public class Platform
    */
   public static String getAppID(String frameType)
   {
-    
+
     String id = Jalview.getInstance().j2sAppletID;
     if (id == null)
     {
-      Jalview.getInstance().j2sAppletID = id = (isJS ? (String) jsutil
-              .getAppletAttribute("_id") : "jalview");
+      Jalview.getInstance().j2sAppletID = id = (isJS
+              ? (String) jsutil.getAppletAttribute("_id")
+              : "jalview");
     }
     return id + (frameType == null ? "" : "-" + frameType);
   }
 
-
   /**
    * Option to avoid unnecessary seeking of nonexistent resources in JavaScript.
    * Works in Java as well.
@@ -1003,5 +1196,4 @@ public class Platform
       }
     }
   }
-
 }