new ajax api methods for linking existing jmol viewers with sequences in an alignframe
[jalview.git] / src / jalview / gui / AppJmol.java
index 32fc85f..7945fa7 100644 (file)
@@ -1,20 +1,19 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
- * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5)
+ * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
  * 
- * This program 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 2
- * of the License, or (at your option) any later version.
+ * This file is part of Jalview.
  * 
- * This program 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.
+ * 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.
  * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ * 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/>.
  */
 package jalview.gui;
 
@@ -27,6 +26,7 @@ import java.awt.event.*;
 import java.io.*;
 
 import jalview.jbgui.GStructureViewer;
+import jalview.bin.Cache;
 import jalview.datamodel.*;
 import jalview.gui.*;
 import jalview.structure.*;
@@ -38,6 +38,7 @@ import jalview.ws.ebi.EBIFetchClient;
 import org.jmol.api.*;
 import org.jmol.adapter.smarter.SmarterJmolAdapter;
 import org.jmol.popup.*;
+import org.jmol.viewer.JmolConstants;
 
 public class AppJmol extends GStructureViewer implements StructureListener,
         JmolStatusListener, Runnable
@@ -76,14 +77,15 @@ public class AppJmol extends GStructureViewer implements StructureListener,
   {
     this(file, id, seq, ap, loadStatus, bounds, null);
   }
+
   public AppJmol(String file, String id, SequenceI[] seq,
-            AlignmentPanel ap, String loadStatus, Rectangle bounds, String viewid)
+          AlignmentPanel ap, String loadStatus, Rectangle bounds,
+          String viewid)
   {
     loadingFromArchive = true;
     pdbentry = new PDBEntry();
     pdbentry.setFile(file);
     pdbentry.setId(id);
-    this.chains = chains;
     this.sequence = seq;
     this.ap = ap;
     this.setBounds(bounds);
@@ -225,15 +227,13 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     this.setTitle(title.toString());
     jalview.gui.Desktop.addInternalFrame(this, title.toString(),
             getBounds().width, getBounds().height);
+    // * OK, but safer to assign htmlName, URL bases, comandOptions, and
+    // statusListener now.
 
     viewer = org.jmol.api.JmolViewer.allocateViewer(renderPanel,
-            new SmarterJmolAdapter());
-
-    viewer.setAppletContext("", null, null, "");
+            new SmarterJmolAdapter(), "", null, null, "", this);
 
-    viewer.setJmolStatusListener(this);
-
-    jmolpopup = JmolPopup.newJmolPopup(viewer);
+    jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
 
     viewer.evalStringQuiet(command);
   }
@@ -315,11 +315,27 @@ public class AppJmol extends GStructureViewer implements StructureListener,
   {
     try
     {
-      EBIFetchClient ebi = new EBIFetchClient();
-      String query = "pdb:" + pdbentry.getId();
-      pdbentry.setFile(ebi.fetchDataAsFile(query, "default", "raw")
-              .getAbsolutePath());
-      initJmol("load " + pdbentry.getFile());
+      // TODO: replace with reference fetching/transfer code (validate PDBentry
+      // as a DBRef?)
+      jalview.ws.dbsources.Pdb pdbclient = new jalview.ws.dbsources.Pdb();
+      AlignmentI pdbseq;
+      if ((pdbseq = pdbclient.getSequenceRecords(pdbentry.getId())) != null)
+      {
+        // just transfer the file name from the first seuqence's first PDBEntry
+        pdbentry.setFile(((PDBEntry) pdbseq.getSequenceAt(0).getPDBId()
+                .elementAt(0)).getFile());
+        initJmol("load " + pdbentry.getFile());
+      }
+      else
+      {
+        JOptionPane
+                .showInternalMessageDialog(
+                        Desktop.desktop,
+                        pdbentry.getId()
+                                + " could not be retrieved. Please try downloading the file manually.",
+                        "Couldn't load file", JOptionPane.ERROR_MESSAGE);
+
+      }
     } catch (OutOfMemoryError oomerror)
     {
       new OOMWarning("Retrieving PDB id " + pdbentry.getId() + " from MSD",
@@ -379,7 +395,7 @@ public class AppJmol extends GStructureViewer implements StructureListener,
    * DOCUMENT ME!
    * 
    * @param e
-   *                DOCUMENT ME!
+   *          DOCUMENT ME!
    */
   public void eps_actionPerformed(ActionEvent e)
   {
@@ -390,7 +406,7 @@ public class AppJmol extends GStructureViewer implements StructureListener,
    * DOCUMENT ME!
    * 
    * @param e
-   *                DOCUMENT ME!
+   *          DOCUMENT ME!
    */
   public void png_actionPerformed(ActionEvent e)
   {
@@ -580,6 +596,7 @@ public class AppJmol extends GStructureViewer implements StructureListener,
   public void highlightAtom(int atomIndex, int pdbResNum, String chain,
           String pdbfile)
   {
+    // TODO: rna: remove CA dependency in select string
     if (!pdbfile.equals(pdbentry.getFile()))
       return;
 
@@ -594,19 +611,22 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     resetLastRes.setLength(0);
     resetLastRes.append("select " + pdbResNum);
 
+    eval.append(":");
+    resetLastRes.append(":");
     if (!chain.equals(" "))
     {
-      eval.append(":" + chain);
-      resetLastRes.append(":" + chain);
+      eval.append(chain);
+      resetLastRes.append(chain);
     }
 
-    eval.append(";wireframe 100;" + eval.toString() + ".CA;");
+    eval.append(";wireframe 100;" + eval.toString() + " and not hetero;"); // ".*;");
 
     resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
-            + ".CA;spacefill 0;");
+    // + ".*;spacefill 0;");
+            + " and not hetero;spacefill 0;");
 
     eval.append("spacefill 200;select none");
-
+    // System.out.println("jmol:\n"+eval+"\n");
     viewer.evalStringQuiet(eval.toString());
   }
 
@@ -758,13 +778,8 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     System.out.println("JMOL CREATE IMAGE");
   }
 
-  public void setCallbackFunction(String callbackType,
-          String callbackFunction)
-  {
-  }
-
   public void notifyFileLoaded(String fullPathName, String fileName,
-          String modelName, Object clientFile, String errorMsg)
+          String modelName, String errorMsg, int modelParts)
   {
     if (errorMsg != null)
     {
@@ -777,7 +792,7 @@ public class AppJmol extends GStructureViewer implements StructureListener,
 
     if (fileName != null)
     {
-
+      // TODO: do some checking using the modelPts number of parts against our own estimate of the number of chains
       // FILE LOADED OK
       ssm = StructureSelectionManager.getStructureSelectionManager();
       MCview.PDBfile pdbFile = ssm.setMapping(sequence, chains, pdbentry
@@ -809,15 +824,6 @@ public class AppJmol extends GStructureViewer implements StructureListener,
       return;
   }
 
-  public void notifyFrameChanged(int frameNo)
-  {
-    boolean isAnimationRunning = (frameNo <= -2);
-  }
-
-  public void notifyScriptStart(String statusMessage, String additionalInfo)
-  {
-  }
-
   public void sendConsoleEcho(String strEcho)
   {
     if (scriptWindow != null)
@@ -843,15 +849,15 @@ public class AppJmol extends GStructureViewer implements StructureListener,
 
   public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
   {
-    notifyAtomPicked(iatom, strMeasure);
-  }
-
-  public void notifyNewDefaultModeMeasurement(int count, String strInfo)
-  {
+    notifyAtomPicked(iatom, strMeasure, null);
   }
 
-  public void notifyAtomPicked(int atomIndex, String strInfo)
+  public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
   {
+    if (strData!=null)
+    {
+      Cache.log.info("Non null pick data string: "+strData+" (other info: '"+strInfo+"' pos "+atomIndex+")");
+    }
     Matcher matcher = pattern.matcher(strInfo);
     matcher.find();
 
@@ -864,7 +870,7 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     if (chainId != null)
       picked += (":" + chainId.substring(1, chainId.length()));
 
-    picked += ".CA";
+    picked = "(("+picked+".CA" + ")|("+picked+".P"+"))";
 
     if (!atomsPicked.contains(picked))
     {
@@ -887,17 +893,25 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     }
   }
 
-  public void notifyAtomHovered(int atomIndex, String strInfo)
+  public void notifyAtomHovered(int atomIndex, String strInfo, String data)
   {
+    if (data!=null)
+    {
+      Cache.log.info("Non null hover data string: "+data+" (other info: '"+strInfo+"' pos "+atomIndex+")");
+    }
     mouseOverStructure(atomIndex, strInfo);
   }
 
-  public void sendSyncScript(String script, String appletName)
-  {
-  }
-
+  @Override
   public void showUrl(String url)
   {
+    try {
+      jalview.util.BrowserLauncher.openURL(url);
+    } catch (IOException e)
+    {
+      Cache.log.error("Failed to launch Jmol-associated url "+url,e);
+      // TODO: 2.6 : warn user if browser was not configured.
+    }
   }
 
   public void showConsole(boolean showConsole)
@@ -931,9 +945,9 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     validate();
   }
 
-  public float functionXY(String functionName, int x, int y)
+  public float[][] functionXY(String functionName, int x, int y)
   {
-    return 0;
+    return null;
   }
 
   // /End JmolStatusListener
@@ -973,14 +987,108 @@ public class AppJmol extends GStructureViewer implements StructureListener,
       }
     }
   }
-  String viewId=null;
+
+  String viewId = null;
+
   public String getViewId()
   {
-    if (viewId==null)
+    if (viewId == null)
     {
-      viewId=System.currentTimeMillis()+"."+this.hashCode();
+      viewId = System.currentTimeMillis() + "." + this.hashCode();
     }
     return viewId;
   }
 
+  @Override
+  public String createImage(String fileName, String type,
+          Object textOrBytes, int quality)
+  {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
+  {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Hashtable getRegistryInfo()
+  {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public void notifyCallback(int type, Object[] data)
+  {
+    try {
+    switch (type)
+    {
+    case JmolConstants.CALLBACK_LOADSTRUCT:
+      notifyFileLoaded((String) data[1], (String) data[2], 
+              (String) data[3], (String) data[4], ((Integer) data[5]).intValue());
+              
+      break;
+    case JmolConstants.CALLBACK_PICK:
+      notifyAtomPicked(((Integer) data[2]).intValue(), (String) data[1], (String) data[0]);
+      // also highlight in alignment
+    case JmolConstants.CALLBACK_HOVER:
+      notifyAtomHovered(((Integer) data[2]).intValue(), (String) data[1], (String) data[0]);
+      break;
+    case JmolConstants.CALLBACK_SCRIPT:
+      notifyScriptTermination((String)data[2], ((Integer)data[3]).intValue());
+      break;
+    case JmolConstants.CALLBACK_ECHO:
+      sendConsoleEcho((String)data[1]);
+      break;
+    case JmolConstants.CALLBACK_MESSAGE:
+      sendConsoleMessage((data==null) ? ((String) null) : (String)data[1]);
+      break;
+    case JmolConstants.CALLBACK_MEASURE:
+    case JmolConstants.CALLBACK_CLICK:
+      default:
+        System.err.println("Unhandled callback "+type+" "+data);
+        break;
+    }
+    }
+    catch (Exception e)
+    {
+      Cache.log.warn("Squashed Jmol callback handler error: ",e);
+    }
+  }
+
+  @Override
+  public boolean notifyEnabled(int callbackPick)
+  {
+    switch (callbackPick)
+    {
+    case JmolConstants.CALLBACK_ECHO:
+    case JmolConstants.CALLBACK_LOADSTRUCT:
+    case JmolConstants.CALLBACK_MEASURE:
+    case JmolConstants.CALLBACK_MESSAGE:
+    case JmolConstants.CALLBACK_PICK:
+    case JmolConstants.CALLBACK_SCRIPT:
+    case JmolConstants.CALLBACK_HOVER:
+    case JmolConstants.CALLBACK_ERROR:
+      return true;
+    case JmolConstants.CALLBACK_CLICK:
+      case JmolConstants.CALLBACK_ANIMFRAME:
+    case JmolConstants.CALLBACK_MINIMIZATION:
+    case JmolConstants.CALLBACK_RESIZE:
+    case JmolConstants.CALLBACK_SYNC:
+    }
+    return false;
+  }
+
+  @Override
+  public void setCallbackFunction(String callbackType,
+          String callbackFunction)
+  {
+    Cache.log.debug("Ignoring set-callback request to associate "+callbackType+" with function "+callbackFunction);
+    
+  }
+
 }