+package jalview.javascript;
+
+import java.net.URL;
+import java.util.Vector;
+
+import netscape.javascript.JSException;
+import netscape.javascript.JSObject;
+import jalview.bin.JalviewLite;
+
+public class JSFunctionExec implements Runnable
+{
+ JalviewLite jvlite;
+
+ public JSFunctionExec(JalviewLite applet)
+ {
+ jvlite = applet;
+ }
+
+ private static Vector jsExecQueue;
+
+ private static Thread executor = null;
+
+ public static void stopQueue()
+ {
+ if (jsExecQueue != null)
+ {
+ Vector q = jsExecQueue;
+ jsExecQueue = null;
+ q.removeAllElements();
+ executor.notify();
+ executor = null;
+ }
+ }
+
+ public void run()
+ {
+ while (jsExecQueue != null)
+ {
+ if (jsExecQueue.size() > 0)
+ {
+ Runnable r = (Runnable) jsExecQueue.elementAt(0);
+ jsExecQueue.removeElementAt(0);
+ try
+ {
+ r.run();
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ } catch (Error ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ else
+ {
+ try
+ {
+ synchronized (jsExecQueue)
+ {
+ jsExecQueue.wait(1000);
+ }
+ } catch (Exception ex)
+ {
+ }
+ ;
+ }
+ }
+
+ }
+
+ /**
+ * execute a javascript callback asynchronously
+ *
+ * @param _listener
+ * @param objects
+ * @throws Exception
+ */
+ public void executeJavascriptFunction(final String _listener,
+ final Object[] objects) throws Exception
+ {
+ executeJavascriptFunction(false, _listener, objects);
+ }
+
+ /**
+ * execute a javascript callback synchronously or asynchronously
+ *
+ * @param async
+ * - true to execute asynchronously (do this for gui events)
+ * @param _listener
+ * - javascript function
+ * @param objects
+ * - arguments
+ * @throws Exception
+ * - only if call is synchronous
+ */
+ public void executeJavascriptFunction(final boolean async,
+ final String _listener, Object[] arguments) throws Exception
+ {
+ final Object[] objects = new Object[arguments != null ? arguments.length
+ : 0];
+ if (arguments != null)
+ {
+ System.arraycopy(arguments, 0, objects, 0, arguments.length);
+ }
+ final Exception[] jsex = new Exception[1];
+ Runnable exec = new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ JSObject scriptObject = null;
+ try
+ {
+ scriptObject = JSObject.getWindow(jvlite.applet);
+ } catch (Exception ex)
+ {
+ }
+ ;
+ if (scriptObject != null)
+ {
+ scriptObject.call(_listener, objects);
+ }
+ } catch (Exception jex)
+ {
+ // squash any malformedURLExceptions thrown by windows/safari
+ if (!(jex instanceof java.net.MalformedURLException))
+ {
+ if (jvlite.debug)
+ {
+ System.err.println(jex);
+ }
+ if (jex instanceof netscape.javascript.JSException)
+ {
+ jsex[0] = (netscape.javascript.JSException) jex;
+ if (jvlite.debug)
+ {
+ System.err.println("Falling back to javascript: url call");
+ }
+ StringBuffer sb = new StringBuffer("javascript:" + _listener
+ + "(");
+ for (int i = 0; objects != null && i < objects.length; i++)
+ {
+ if (i > 0)
+ {
+ sb.append(",");
+ }
+ sb.append("\"");
+ // strip out nulls and complex objects that we can't pass this
+ // way.
+ if (objects[i] != null
+ && !(objects[i].getClass().getPackage().getName()
+ .indexOf("jalview") == 0))
+ {
+ sb.append(objects[i].toString());
+ }
+ sb.append("\"");
+ }
+ sb.append(")");
+ if (jvlite.debug)
+ {
+ System.err.println(sb.toString());
+ }
+ // alternate
+ URL url = null;
+ try
+ {
+ url = new URL(sb.toString());
+ jvlite.getAppletContext().showDocument(url);
+ jex = null;
+ } catch (Exception uex)
+ {
+ jex = uex;
+ }
+ }
+ if (jex != null)
+ {
+ if (async)
+ {
+ jex.printStackTrace();
+ }
+ else
+ {
+ jsex[0] = new Exception(jex);
+ }
+ }
+ ;
+ }
+
+ }
+ }
+ };
+ if (async)
+ {
+ if (JSFunctionExec.executor == null)
+ {
+ JSFunctionExec.jsExecQueue = new Vector();
+ JSFunctionExec.executor = new Thread(new JSFunctionExec(jvlite));
+ executor.start();
+ }
+ synchronized (jsExecQueue)
+ {
+ jsExecQueue.addElement(exec);
+ jsExecQueue.notify();
+ }
+ }
+ else
+ {
+ exec.run();
+ if (jsex[0] != null)
+ {
+ throw (jsex[0]);
+ }
+ }
+ }
+
+}