JAL-3210 Improvements to eclipse detection. New src tree and SwingJS updated from...
[jalview.git] / src / jalview / util / BrowserLauncher.java
index cf898b7..ca2e55e 100755 (executable)
@@ -1,30 +1,41 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.1)
- * Copyright (C) 2014 The Jalview Authors
+ * 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.
+ * 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/>.
+ * 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.util;
 
-import java.io.*;
-import java.lang.reflect.*;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 
 /**
- * BrowserLauncher is a class that provides one static method, openURL, which
- * opens the default web browser for the current user of the system to the given
- * URL. It may support other protocols depending on the system -- mailto, ftp,
+ * BrowserLauncher is a class that provides two static methods:
+ * 
+ * openURL(String url), which opens the default web browser for the current user
+ * of the system to the given URL, and
+ * 
+ * resetBrowser(), which allows switching browsers in Java.
+ * 
+ * openURL may support other protocols depending on the system -- mailto, ftp,
  * etc. -- but that has not been rigorously tested and is not guaranteed to
  * work.
  * <p>
@@ -63,16 +74,24 @@ import java.lang.reflect.*;
  * functionality or any adverse or unexpected effects of using this software.
  * <p>
  * Credits: <br>
- * Steven Spencer, JavaWorld magazine (<a
- * href="http://www.javaworld.com/javaworld/javatips/jw-javatip66.html">Java Tip
- * 66</a>) <br>
+ * Steven Spencer, JavaWorld magazine
+ * (<a href="http://www.javaworld.com/javaworld/javatips/jw-javatip66.html">Java
+ * Tip 66</a>) <br>
  * Thanks also to Ron B. Yeh, Eric Shapiro, Ben Engber, Paul Teitlebaum, Andrea
  * Cantatore, Larry Barowski, Trevor Bedzek, Frank Miedrich, and Ron Rabakukk
  * 
- * @author Eric Albert (<a
- *         href="mailto:ejalbert@cs.stanford.edu">ejalbert@cs.stanford.edu</a>)
+ * @author Eric Albert (<a href=
+ *         "mailto:ejalbert@cs.stanford.edu">ejalbert@cs.stanford.edu</a>)
  * @version 1.4b1 (Released June 20, 2001)
  */
+/*
+ * 
+ * SwingJS note: Do not use methods in this class directly. Use
+ * 
+ * Platform.openURL(String url) only.
+ * 
+ * JavaScript does not see this class.
+ */
 public class BrowserLauncher
 {
   /**
@@ -95,22 +114,22 @@ public class BrowserLauncher
   private static boolean loadedWithoutErrors;
 
   /** The com.apple.mrj.MRJFileUtils class */
-  private static Class mrjFileUtilsClass;
+  private static Class<?> mrjFileUtilsClass;
 
   /** The com.apple.mrj.MRJOSType class */
-  private static Class mrjOSTypeClass;
+  private static Class<?> mrjOSTypeClass;
 
   /** The com.apple.MacOS.AEDesc class */
-  private static Class aeDescClass;
+  private static Class<?> aeDescClass;
 
   /** The &lt;init&gt;(int) method of com.apple.MacOS.AETarget */
-  private static Constructor aeTargetConstructor;
+  private static Constructor<?> aeTargetConstructor;
 
   /** The &lt;init&gt;(int, int, int) method of com.apple.MacOS.AppleEvent */
-  private static Constructor appleEventConstructor;
+  private static Constructor<?> appleEventConstructor;
 
   /** The &lt;init&gt;(String) method of com.apple.MacOS.AEDesc */
-  private static Constructor aeDescConstructor;
+  private static Constructor<?> aeDescConstructor;
 
   /** The findFolder method of com.apple.mrj.MRJFileUtils */
   private static Method findFolder;
@@ -227,6 +246,7 @@ public class BrowserLauncher
    */
   static
   {
+
     loadedWithoutErrors = true;
 
     String osName = System.getProperty("os.name");
@@ -319,16 +339,18 @@ public class BrowserLauncher
    */
   private static boolean loadClasses()
   {
+
     switch (jvm)
     {
     case MRJ_2_0:
 
       try
       {
-        Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget");
-        Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils");
-        Class appleEventClass = Class.forName("com.apple.MacOS.AppleEvent");
-        Class aeClass = Class.forName("com.apple.MacOS.ae");
+        Class<?> aeTargetClass = Class.forName("com.apple.MacOS.AETarget");
+        Class<?> osUtilsClass = Class.forName("com.apple.MacOS.OSUtils");
+        Class<?> appleEventClass = Class
+                .forName("com.apple.MacOS.AppleEvent");
+        Class<?> aeClass = Class.forName("com.apple.MacOS.ae");
         aeDescClass = Class.forName("com.apple.MacOS.AEDesc");
 
         aeTargetConstructor = aeTargetClass
@@ -336,9 +358,11 @@ public class BrowserLauncher
                 { int.class });
         appleEventConstructor = appleEventClass
                 .getDeclaredConstructor(new Class[]
-                { int.class, int.class, aeTargetClass, int.class, int.class });
-        aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class[]
-        { String.class });
+                { int.class, int.class, aeTargetClass, int.class,
+                    int.class });
+        aeDescConstructor = aeDescClass
+                .getDeclaredConstructor(new Class[]
+                { String.class });
 
         makeOSType = osUtilsClass.getDeclaredMethod("makeOSType",
                 new Class[]
@@ -347,8 +371,7 @@ public class BrowserLauncher
                 new Class[]
                 { int.class, aeDescClass });
         sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply",
-                new Class[]
-                {});
+                new Class[] {});
 
         Field keyDirectObjectField = aeClass
                 .getDeclaredField("keyDirectObject");
@@ -399,8 +422,8 @@ public class BrowserLauncher
         findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder",
                 new Class[]
                 { mrjOSTypeClass });
-        getFileCreator = mrjFileUtilsClass.getDeclaredMethod(
-                "getFileCreator", new Class[]
+        getFileCreator = mrjFileUtilsClass
+                .getDeclaredMethod("getFileCreator", new Class[]
                 { File.class });
         getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType",
                 new Class[]
@@ -438,11 +461,13 @@ public class BrowserLauncher
 
       try
       {
-        Class linker = Class.forName("com.apple.mrj.jdirect.Linker");
-        Constructor constructor = linker.getConstructor(new Class[]
-        { Class.class });
-        linkage = constructor.newInstance(new Object[]
-        { BrowserLauncher.class });
+        Class<?> linker = Class.forName("com.apple.mrj.jdirect.Linker");
+        Constructor<?> constructor = linker
+                .getConstructor(new Class[]
+                { Class.class });
+        linkage = constructor
+                .newInstance(new Object[]
+                { BrowserLauncher.class });
       } catch (ClassNotFoundException cnfe)
       {
         errorMessage = cnfe.getMessage();
@@ -528,13 +553,16 @@ public class BrowserLauncher
         Integer finderCreatorCode = (Integer) makeOSType.invoke(null,
                 new Object[]
                 { FINDER_CREATOR });
-        Object aeTarget = aeTargetConstructor.newInstance(new Object[]
-        { finderCreatorCode });
-        Integer gurlType = (Integer) makeOSType.invoke(null, new Object[]
-        { GURL_EVENT });
-        Object appleEvent = appleEventConstructor.newInstance(new Object[]
-        { gurlType, gurlType, aeTarget, kAutoGenerateReturnID,
-            kAnyTransactionID });
+        Object aeTarget = aeTargetConstructor
+                .newInstance(new Object[]
+                { finderCreatorCode });
+        Integer gurlType = (Integer) makeOSType.invoke(null,
+                new Object[]
+                { GURL_EVENT });
+        Object appleEvent = appleEventConstructor
+                .newInstance(new Object[]
+                { gurlType, gurlType, aeTarget, kAutoGenerateReturnID,
+                    kAnyTransactionID });
 
         // Don't set browser = appleEvent because then the next time we call
         // locateBrowser(), we'll get the same AppleEvent, to which we'll
@@ -571,8 +599,9 @@ public class BrowserLauncher
 
       try
       {
-        systemFolder = (File) findFolder.invoke(null, new Object[]
-        { kSystemFolderType });
+        systemFolder = (File) findFolder.invoke(null,
+                new Object[]
+                { kSystemFolderType });
       } catch (IllegalArgumentException iare)
       {
         browser = null;
@@ -613,13 +642,13 @@ public class BrowserLauncher
           // applications being picked up on certain Mac OS 9 systems,
           // especially German ones, and sending a GURL event to those
           // applications results in a logout under Multiple Users.
-          Object fileType = getFileType.invoke(null, new Object[]
-          { file });
+          Object fileType = getFileType.invoke(null, new Object[] { file });
 
           if (FINDER_TYPE.equals(fileType.toString()))
           {
-            Object fileCreator = getFileCreator.invoke(null, new Object[]
-            { file });
+            Object fileCreator = getFileCreator.invoke(null,
+                    new Object[]
+                    { file });
 
             if (FINDER_CREATOR.equals(fileCreator.toString()))
             {
@@ -675,7 +704,6 @@ public class BrowserLauncher
 
       break;
     }
-
     return browser;
   }
 
@@ -698,16 +726,25 @@ public class BrowserLauncher
    */
   public static void openURL(String url) throws IOException
   {
+    if (Platform.isJS())
+    {
+      Platform.openURL(url);
+      return;
+    }
     if (!loadedWithoutErrors)
     {
-      throw new IOException("Exception in finding browser: " + errorMessage);
+      throw new IOException(MessageManager
+              .formatMessage("exception.browser_not_found", new String[]
+              { errorMessage }));
     }
 
     Object browser = locateBrowser();
 
     if (browser == null)
     {
-      throw new IOException("Unable to locate browser: " + errorMessage);
+      throw new IOException(MessageManager.formatMessage(
+              "exception.browser_unable_to_locate", new String[]
+              { errorMessage }));
     }
 
     switch (jvm)
@@ -718,27 +755,27 @@ public class BrowserLauncher
 
       try
       {
-        aeDesc = aeDescConstructor.newInstance(new Object[]
-        { url });
-        putParameter.invoke(browser, new Object[]
-        { keyDirectObject, aeDesc });
-        sendNoReply.invoke(browser, new Object[]
-        {});
+        aeDesc = aeDescConstructor.newInstance(new Object[] { url });
+        putParameter.invoke(browser,
+                new Object[]
+                { keyDirectObject, aeDesc });
+        sendNoReply.invoke(browser, new Object[] {});
       } catch (InvocationTargetException ite)
       {
-        throw new IOException(
-                "InvocationTargetException while creating AEDesc: "
-                        + ite.getMessage());
+        throw new IOException(MessageManager.formatMessage(
+                "exception.invocation_target_exception_creating_aedesc",
+                new String[]
+                { ite.getMessage() }));
       } catch (IllegalAccessException iae)
       {
-        throw new IOException(
-                "IllegalAccessException while building AppleEvent: "
-                        + iae.getMessage());
+        throw new IOException(MessageManager.formatMessage(
+                "exception.illegal_access_building_apple_evt", new String[]
+                { iae.getMessage() }));
       } catch (InstantiationException ie)
       {
-        throw new IOException(
-                "InstantiationException while creating AEDesc: "
-                        + ie.getMessage());
+        throw new IOException(MessageManager.formatMessage(
+                "exception.illegal_access_building_apple_evt", new String[]
+                { ie.getMessage() }));
       } finally
       {
         aeDesc = null; // Encourage it to get disposed if it was created
@@ -748,8 +785,7 @@ public class BrowserLauncher
       break;
 
     case MRJ_2_1:
-      Runtime.getRuntime().exec(new String[]
-      { (String) browser, url });
+      Runtime.getRuntime().exec(new String[] { (String) browser, url });
 
       break;
 
@@ -760,13 +796,11 @@ public class BrowserLauncher
 
       if (result == 0)
       {
-        int[] selectionStart = new int[]
-        { 0 };
+        int[] selectionStart = new int[] { 0 };
         byte[] urlBytes = url.getBytes();
-        int[] selectionEnd = new int[]
-        { urlBytes.length };
-        result = ICLaunchURL(instance[0], new byte[]
-        { 0 }, urlBytes, urlBytes.length, selectionStart, selectionEnd);
+        int[] selectionEnd = new int[] { urlBytes.length };
+        result = ICLaunchURL(instance[0], new byte[] { 0 }, urlBytes,
+                urlBytes.length, selectionStart, selectionEnd);
 
         if (result == 0)
         {
@@ -776,13 +810,16 @@ public class BrowserLauncher
         }
         else
         {
-          throw new IOException("Unable to launch URL: " + result);
+          throw new IOException(MessageManager.formatMessage(
+                  "exception.unable_to_launch_url", new String[]
+                  { Integer.valueOf(result).toString() }));
         }
       }
       else
       {
-        throw new IOException(
-                "Unable to create an Internet Config instance: " + result);
+        throw new IOException(MessageManager.formatMessage(
+                "exception.unable_to_create_internet_config", new String[]
+                { Integer.valueOf(result).toString() }));
       }
 
       break;
@@ -791,18 +828,17 @@ public class BrowserLauncher
 
       try
       {
-        openURL.invoke(null, new Object[]
-        { url });
+        openURL.invoke(null, new Object[] { url });
       } catch (InvocationTargetException ite)
       {
-        throw new IOException(
-                "InvocationTargetException while calling openURL: "
-                        + ite.getMessage());
+        throw new IOException(MessageManager.formatMessage(
+                "exception.invocation_target_calling_url", new String[]
+                { ite.getMessage() }));
       } catch (IllegalAccessException iae)
       {
-        throw new IOException(
-                "IllegalAccessException while calling openURL: "
-                        + iae.getMessage());
+        throw new IOException(MessageManager.formatMessage(
+                "exception.illegal_access_calling_url", new String[]
+                { iae.getMessage() }));
       }
 
       break;
@@ -812,8 +848,8 @@ public class BrowserLauncher
 
       // Add quotes around the URL to allow ampersands and other special
       // characters to work.
-      Process process = Runtime.getRuntime().exec(
-              new String[]
+      Process process = Runtime.getRuntime()
+              .exec(new String[]
               { (String) browser, FIRST_WINDOWS_PARAMETER,
                   SECOND_WINDOWS_PARAMETER, THIRD_WINDOWS_PARAMETER,
                   '"' + url + '"' });
@@ -827,9 +863,9 @@ public class BrowserLauncher
         process.exitValue();
       } catch (InterruptedException ie)
       {
-        throw new IOException(
-                "InterruptedException while launching browser: "
-                        + ie.getMessage());
+        throw new IOException(MessageManager.formatMessage(
+                "exception.interrupted_launching_browser", new String[]
+                { ie.getMessage() }));
       }
 
       break;
@@ -847,11 +883,9 @@ public class BrowserLauncher
        * NETSCAPE_REMOTE_PARAMETER+" "+ NETSCAPE_OPEN_PARAMETER_START + url +
        * NETSCAPE_OPEN_NEW_WINDOW + NETSCAPE_OPEN_PARAMETER_END);
        */
-      process = Runtime.getRuntime().exec(
-              new String[]
-              {
-                  (String) browser,
-                  NETSCAPE_REMOTE_PARAMETER,
+      process = Runtime.getRuntime()
+              .exec(new String[]
+              { (String) browser, NETSCAPE_REMOTE_PARAMETER,
 
                   NETSCAPE_OPEN_PARAMETER_START + url
                           + NETSCAPE_OPEN_NEW_WINDOW
@@ -863,29 +897,26 @@ public class BrowserLauncher
 
         if (exitCode != 0)
         { // if Netscape was not open
-          Runtime.getRuntime().exec(new String[]
-          { (String) browser, url });
+          Runtime.getRuntime().exec(new String[] { (String) browser, url });
         }
       } catch (InterruptedException ie)
       {
-        throw new IOException(
-                "InterruptedException while launching browser: "
-                        + ie.getMessage());
+        throw new IOException(MessageManager.formatMessage(
+                "exception.interrupted_launching_browser", new String[]
+                { ie.getMessage() }));
       }
 
       break;
 
     default:
-
       // This should never occur, but if it does, we'll try the simplest thing
       // possible
-      Runtime.getRuntime().exec(new String[]
-      { (String) browser, url });
-
+      Runtime.getRuntime().exec(new String[] { (String) browser, url });
       break;
     }
   }
 
+
   /**
    * Methods required for Mac OS X. The presence of native methods does not
    * cause any problems on other platforms.