upgrading structure/sequence binding so that a structure view can contain many pdb...
authorjprocter <Jim Procter>
Tue, 29 Jun 2010 16:23:00 +0000 (16:23 +0000)
committerjprocter <Jim Procter>
Tue, 29 Jun 2010 16:23:00 +0000 (16:23 +0000)
src/MCview/AppletPDBCanvas.java
src/MCview/PDBCanvas.java
src/jalview/appletgui/AppletJmol.java
src/jalview/gui/AppJmol.java
src/jalview/structure/StructureListener.java
src/jalview/structure/StructureSelectionManager.java

index cdad671..c82c331 100755 (executable)
@@ -1100,9 +1100,9 @@ public class AppletPDBCanvas extends Panel implements MouseListener,
 
   // ////////////////////////////////
   // /StructureListener
-  public String getPdbFile()
+  public String[] getPdbFile()
   {
-    return pdbentry.getFile();
+    return new String[] { pdbentry.getFile() };
   }
 
   String lastMessage;
index b3148df..584c076 100755 (executable)
@@ -1067,9 +1067,9 @@ public class PDBCanvas extends JPanel implements MouseListener,
 
   // ////////////////////////////////
   // /StructureListener
-  public String getPdbFile()
+  public String[] getPdbFile()
   {
-    return pdbentry.getFile();
+    return new String[] { pdbentry.getFile() };
   }
 
   String lastMessage;
index ff0f5ae..9809859 100644 (file)
@@ -21,6 +21,7 @@ import java.util.*;
 import java.awt.*;
 import java.awt.event.*;
 
+import jalview.api.SequenceStructureBinding;
 import jalview.datamodel.*;
 import jalview.structure.*;
 import jalview.io.*;
@@ -34,7 +35,7 @@ import org.jmol.viewer.JmolConstants;
 import jalview.schemes.*;
 
 public class AppletJmol extends EmbmenuFrame implements StructureListener,
-        JmolStatusListener, KeyListener, ActionListener, ItemListener
+        JmolStatusListener, KeyListener, ActionListener, ItemListener, SequenceStructureBinding
 
 {
   Menu fileMenu = new Menu("File");
@@ -189,8 +190,9 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
     embedMenuIfNeeded(renderPanel);
     this.add(renderPanel, BorderLayout.CENTER);
     viewer = JmolViewer.allocateViewer(renderPanel,
-            new SmarterJmolAdapter(), "jalviewJmol", ap.av.applet.getDocumentBase(),
-            ap.av.applet.getCodeBase(), "", this);
+            new SmarterJmolAdapter(), "jalviewJmol", ap.av.applet
+                    .getDocumentBase(), ap.av.applet.getCodeBase(), "",
+            this);
 
     jmolpopup = JmolPopup.newJmolPopup(viewer, true, "Jmol", true);
 
@@ -270,6 +272,21 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
     jalview.bin.JalviewLite.addFrame(this, "Jmol", 400, 400);
   }
 
+  /**
+   * create a new binding between structures in an existing jmol viewer instance and
+   * an alignpanel with sequences that have existing PDBFile entries. Note, this does not open a new Jmol window, 
+   * or modify the display of the structures in the original jmol window.
+   * @param viewer2
+   * @param alignPanel
+   * @param seqs - sequences to search for associations
+   */
+  public AppletJmol(JmolViewer viewer2, AlignmentPanel alignPanel,
+          SequenceI[] seqs)
+  {
+    
+    // TODO Auto-generated constructor stub
+  }
+
   public void loadInline(String string)
   {
     loadedInline = true;
@@ -299,14 +316,30 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
 
   void centerViewer()
   {
+    jmolHistory(false);
     StringBuffer cmd = new StringBuffer();
+    String lbl;
+    int mlength, p,mnum;
     for (int i = 0; i < chainMenu.getItemCount(); i++)
     {
       if (chainMenu.getItem(i) instanceof CheckboxMenuItem)
       {
         CheckboxMenuItem item = (CheckboxMenuItem) chainMenu.getItem(i);
         if (item.getState())
-          cmd.append(":" + item.getLabel() + " or ");
+        {
+          lbl = item.getLabel();
+          mlength = 0;
+          do
+          {
+            p = mlength;
+            mlength = lbl.indexOf(":", p);
+          } while (p < mlength && mlength < (lbl.length() - 2));
+                  mnum = 1+getModelNum(lbl.substring(0, mlength));
+        if (mnum>0)
+          {cmd.append(":" + lbl.substring(mlength + 1) + " /"
+                + mnum + " or ");
+          }
+        }
       }
     }
 
@@ -316,25 +349,42 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
     viewer
             .evalString("select *;restrict " + cmd + ";cartoon;center "
                     + cmd);
+    jmolHistory(true);
+  }
+
+  private int getModelNum(String modelFileName)
+  {
+    String[] mfn = getPdbFile();
+    if (mfn == null)
+    {
+      return -1;
+    }
+    for (int i = 0; i < mfn.length; i++)
+    {
+      if (mfn[i].equalsIgnoreCase(modelFileName))
+        return i;
+    }
+    return -1;
   }
 
   void closeViewer()
   {
     viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
+    // remove listeners for all structures in viewer
+    StructureSelectionManager.getStructureSelectionManager()
+            .removeStructureViewerListener(this, this.getPdbFile());
+    // and shut down jmol
     viewer.evalStringQuiet("zap");
     viewer.setJmolStatusListener(null);
-    viewer = null;
 
-    // We'll need to find out what other
-    // listeners need to be shut down in Jmol
-    StructureSelectionManager.getStructureSelectionManager()
-            .removeStructureViewerListener(this, pdbentry.getId());
+    viewer = null;
 
     this.setVisible(false);
   }
 
   public void actionPerformed(ActionEvent evt)
   {
+    jmolHistory(false);
     if (evt.getSource() == mappingMenuItem)
     {
       jalview.appletgui.CutAndPasteTransfer cap = new jalview.appletgui.CutAndPasteTransfer(
@@ -417,8 +467,12 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
       centerViewer();
       allChainsSelected = false;
     }
+    jmolHistory(true);
+  }
+  private void jmolHistory(boolean enable)
+  {
+    viewer.setBooleanProperty("history", enable);
   }
-
   public void setJalviewColourScheme(ColourSchemeI cs)
   {
     colourBySequence = false;
@@ -430,6 +484,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
     String res;
     int index;
     Color col;
+    jmolHistory(false);
 
     Enumeration en = ResidueProperties.aa3Hash.keys();
     StringBuffer command = new StringBuffer("select *;color white;");
@@ -447,6 +502,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
     }
 
     viewer.evalStringQuiet(command.toString());
+    jmolHistory(true);
   }
 
   public void itemStateChanged(ItemEvent evt)
@@ -480,24 +536,42 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
   {
   }
 
+  String[] modelFileNames = null;
+
   // ////////////////////////////////
   // /StructureListener
-  public String getPdbFile()
+  public String[] getPdbFile()
   {
-    return "???";
+    if (modelFileNames == null)
+    {
+      String mset[] = new String[viewer.getModelCount()];
+      for (int i = 0; i < mset.length; i++)
+      {
+        mset[i] = viewer.getModelFileName(i);
+      }
+      modelFileNames = mset;
+    }
+    return modelFileNames;
   }
 
   String lastMessage;
 
+  // jmol/ssm only
   public void mouseOverStructure(int atomIndex, String strInfo)
   {
     int pdbResNum;
-
-    int chainSeparator = strInfo.indexOf(":");
+    int mdlSep = strInfo.indexOf("/");
+    int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
 
     if (chainSeparator == -1)
+    {
       chainSeparator = strInfo.indexOf(".");
-
+      if (mdlSep > -1 && mdlSep < chainSeparator)
+      {
+        chainSeparator1 = chainSeparator;
+        chainSeparator = mdlSep;
+      }
+    }
     pdbResNum = Integer.parseInt(strInfo.substring(
             strInfo.indexOf("]") + 1, chainSeparator));
 
@@ -511,8 +585,27 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
       chainId = " ";
     }
 
+    String pdbfilename = pdbentry.getFile();
+    if (mdlSep > -1)
+    {
+      if (chainSeparator1 == -1)
+      {
+        chainSeparator1 = strInfo.indexOf(".", mdlSep);
+      }
+      String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
+              chainSeparator1) : strInfo.substring(mdlSep + 1);
+      try
+      {
+        // recover PDB filename for the model hovered over.
+        pdbfilename = viewer
+                .getModelFileName(new Integer(mdlId).intValue() - 1);
+      } catch (Exception e)
+      {
+      }
+      ;
+    }
     if (lastMessage == null || !lastMessage.equals(strInfo))
-      ssm.mouseOverStructure(pdbResNum, chainId, pdbentry.getFile());
+      ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
 
     lastMessage = strInfo;
   }
@@ -521,31 +614,42 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
 
   StringBuffer eval = new StringBuffer();
 
+  // jmol/ssm only
   public void highlightAtom(int atomIndex, int pdbResNum, String chain,
           String pdbfile)
   {
-    if (!pdbfile.equals(pdbentry.getFile()))
+    int mdlNum = 1+getModelNum(pdbfile);
+    if (mdlNum==0)
+    {
       return;
+    }
 
+    jmolHistory(false);
+    // if (!pdbfile.equals(pdbentry.getFile()))
+    // return;
     if (resetLastRes.length() > 0)
     {
       viewer.evalStringQuiet(resetLastRes.toString());
     }
 
     eval.setLength(0);
-    eval.append("select " + pdbResNum);
+    eval.append("select " + pdbResNum); // +modelNum
 
     resetLastRes.setLength(0);
-    resetLastRes.append("select " + pdbResNum);
+    resetLastRes.append("select " + pdbResNum); // +modelNum
 
-    eval.append(":");
-    resetLastRes.append(":");
     if (!chain.equals(" "))
     {
+    eval.append(":");
+    resetLastRes.append(":");
       eval.append(chain);
       resetLastRes.append(chain);
     }
-
+    // if (mdlNum != 0)
+    {
+      eval.append(" /" + (mdlNum));
+      resetLastRes.append("/" + (mdlNum));
+    }
     eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
 
     resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
@@ -554,6 +658,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
     eval.append("spacefill 200;select none");
 
     viewer.evalStringQuiet(eval.toString());
+    jmolHistory(true);
 
   }
 
@@ -584,12 +689,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
 
     if (!colourBySequence)
       return;
-
-    StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
-
-    if (mapping.length < 1)
-      return;
-
+    String[] files = getPdbFile();
     SequenceRenderer sr = new SequenceRenderer(ap.av);
 
     boolean showFeatures = false;
@@ -607,62 +707,74 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
 
     StringBuffer command = new StringBuffer();
 
-    int lastPos = -1;
-    for (int s = 0; s < sequence.length; s++)
+    for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
     {
-      for (int sp, m = 0; m < mapping.length; m++)
+      StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
+
+      if (mapping == null || mapping.length < 1)
+        continue;
+
+      int lastPos = -1;
+      for (int s = 0; s < sequence.length; s++)
       {
-        if (mapping[m].getSequence() == sequence[s]
-                && (sp = ap.av.alignment.findIndex(sequence[s])) > -1)
+        for (int sp, m = 0; m < mapping.length; m++)
         {
-          SequenceI asp = ap.av.alignment.getSequenceAt(sp);
-          for (int r = 0; r < asp.getLength(); r++)
+          if (mapping[m].getSequence() == sequence[s]
+                  && (sp = ap.av.alignment.findIndex(sequence[s])) > -1)
           {
-            // no mapping to gaps in sequence
-            if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
+            SequenceI asp = ap.av.alignment.getSequenceAt(sp);
+            for (int r = 0; r < asp.getLength(); r++)
             {
-              continue;
+              // no mapping to gaps in sequence
+              if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
+              {
+                continue;
+              }
+              int pos = mapping[m].getPDBResNum(asp.findPosition(r));
+
+              if (pos < 1 || pos == lastPos)
+                continue;
+
+              lastPos = pos;
+
+              Color col = sr.getResidueBoxColour(sequence[s], r);
+
+              if (showFeatures)
+                col = fr.findFeatureColour(col, sequence[s], r);
+              String newSelcom = (mapping[m].getChain() != " " ? ":"
+                      + mapping[m].getChain() : "")
+                      + "/"
+                      + (pdbfnum + 1)
+                      + ".1"
+                      + ";color["
+                      + col.getRed()
+                      + ","
+                      + col.getGreen()
+                      + ","
+                      + col.getBlue() + "]";
+              if (command.toString().endsWith(newSelcom))
+              {
+                command = condenseCommand(command.toString(), pos);
+                continue;
+              }
+              // TODO: deal with case when buffer is too large for Jmol to parse
+              // - execute command and flush
+
+              command.append(";select " + pos);
+              command.append(newSelcom);
             }
-            int pos = mapping[m].getPDBResNum(asp.findPosition(r));
-
-            if (pos < 1 || pos == lastPos)
-              continue;
-
-            lastPos = pos;
-
-            Color col = sr.getResidueBoxColour(sequence[s], r);
-
-            if (showFeatures)
-              col = fr.findFeatureColour(col, sequence[s], r);
-
-            if (command.toString().endsWith(
-                    ":" + mapping[m].getChain() + ";color[" + col.getRed()
-                            + "," + col.getGreen() + "," + col.getBlue()
-                            + "]"))
-            {
-              command = condenseCommand(command.toString(), pos);
-              continue;
-            }
-
-            command.append(";select " + pos);
-
-            if (!mapping[m].getChain().equals(" "))
-            {
-              command.append(":" + mapping[m].getChain());
-            }
-
-            command.append(";color[" + col.getRed() + "," + col.getGreen()
-                    + "," + col.getBlue() + "]");
+            break;
           }
-          break;
         }
       }
     }
 
+    jmolHistory(false);
     if (lastCommand == null || !lastCommand.equals(command.toString()))
     {
       viewer.evalStringQuiet(command.toString());
     }
+    jmolHistory(true);
     lastCommand = command.toString();
   }
 
@@ -704,7 +816,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
   {
   }
 
-  public void notifyFileLoaded(String fullPathName, String fileName,
+  public void notifyFileLoaded(String fullPathName, String fileName2,
           String modelName, String errorMsg, int modelParts)
   {
     if (errorMsg != null)
@@ -713,71 +825,93 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
       repaint();
       return;
     }
-
     fileLoadingError = null;
-
-    if (fileName != null)
+    modelFileNames = null;
+    
+    String[] modelfilenames = getPdbFile();
+    ssm = StructureSelectionManager.getStructureSelectionManager();
+    boolean modelsloaded=false;
+    for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
     {
-      // TODO: do some checking using the modelPts number of parts against our own estimate of the number of chains
-      // FILE LOADED OK
-      jmolpopup.updateComputedMenus();
-      viewer
-              .evalStringQuiet("select backbone;restrict;cartoon;wireframe off;spacefill off");
-
-      ssm = StructureSelectionManager.getStructureSelectionManager();
-      MCview.PDBfile pdb;
-      if (loadedInline)
+      String fileName = modelfilenames[modelnum];
+      if (fileName != null)
       {
-        pdb = ssm.setMapping(sequence, chains, pdbentry.getFile(),
-                AppletFormatAdapter.PASTE);
-        pdbentry.setFile("INLINE" + pdb.id);
-      }
-      else
-      {
-        // TODO: Jmol can in principle retrieve from CLASSLOADER but this needs
-        // to be tested. See mantis bug
-        // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
+        // search pdbentries and sequences to find correct pdbentry and sequence[] pair for this filename
+        if (pdbentry.getFile().equals(fileName))
+        {
+          modelsloaded=true;
+          MCview.PDBfile pdb;
+          if (loadedInline)
+          {
+            pdb = ssm.setMapping(sequence, chains, pdbentry.getFile(),
+                    AppletFormatAdapter.PASTE);
+            pdbentry.setFile("INLINE" + pdb.id);
+          }
+          else
+          {
+            // TODO: Jmol can in principle retrieve from CLASSLOADER but this
+            // needs
+            // to be tested. See mantis bug
+            // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
 
-        pdb = ssm.setMapping(sequence, chains, pdbentry.getFile(),
-                AppletFormatAdapter.URL);
+            pdb = ssm.setMapping(sequence, chains, pdbentry.getFile(),
+                    AppletFormatAdapter.URL);
 
-      }
+          }
 
-      pdbentry.setId(pdb.id);
+          pdbentry.setId(pdb.id);
 
-      ssm.addStructureViewerListener(this);
+          Vector chains = new Vector();
+          for (int i = 0; i < pdb.chains.size(); i++)
+          {
+            chains.addElement(new String(pdb.id + ":"
+                    + ((MCview.PDBChain) pdb.chains.elementAt(i)).id));
+          }
+          setChainMenuItems(chains);
 
-      Vector chains = new Vector();
-      for (int i = 0; i < pdb.chains.size(); i++)
-      {
-        chains.addElement(((MCview.PDBChain) pdb.chains.elementAt(i)).id);
-      }
-      setChainMenuItems(chains);
+          colourBySequence(ap);
 
-      colourBySequence(ap);
+          StringBuffer title = new StringBuffer(sequence[0].getName() + ":"
+                  + pdbentry.getId());
 
-      StringBuffer title = new StringBuffer(sequence[0].getName() + ":"
-              + pdbentry.getId());
+          if (pdbentry.getProperty() != null)
+          {
+            if (pdbentry.getProperty().get("method") != null)
+            {
+              title.append(" Method: ");
+              title.append(pdbentry.getProperty().get("method"));
+            }
+            if (pdbentry.getProperty().get("chains") != null)
+            {
+              title.append(" Chain:");
+              title.append(pdbentry.getProperty().get("chains"));
+            }
+          }
+
+          this.setTitle(title.toString());
 
-      if (pdbentry.getProperty() != null)
-      {
-        if (pdbentry.getProperty().get("method") != null)
-        {
-          title.append(" Method: ");
-          title.append(pdbentry.getProperty().get("method"));
         }
-        if (pdbentry.getProperty().get("chains") != null)
+        else
         {
-          title.append(" Chain:");
-          title.append(pdbentry.getProperty().get("chains"));
+          // this is a foreign pdb file that jalview doesn't know about - add it to the dataset
+          // and try to find a home - either on a matching sequence or as a new sequence.
+          String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
+                  "PDB");
+          // parse pdb file into a chain, etc.
+          // locate best match for pdb in associated views and add mapping to
+          // ssm
+          modelsloaded=true;
         }
       }
+      }
+      if (modelsloaded) {
+      // FILE LOADED OK
+      jmolpopup.updateComputedMenus();
+      viewer
+              .evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
 
-      this.setTitle(title.toString());
-
+      ssm.addStructureViewerListener(this);
     }
-    else
-      return;
   }
 
   public void sendConsoleEcho(String strEcho)
@@ -813,27 +947,32 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
 
   public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
   {
-    if (strData!=null)
+    if (strData != null)
     {
-      System.err.println("Ignoring additional pick data string "+strData);
+      System.err.println("Ignoring additional pick data string " + strData);
     }
     int chainSeparator = strInfo.indexOf(":");
-
+    int p=0;
     if (chainSeparator == -1)
       chainSeparator = strInfo.indexOf(".");
 
     String picked = strInfo.substring(strInfo.indexOf("]") + 1,
             chainSeparator);
-
-    if (strInfo.indexOf(":") > -1)
-      picked += strInfo.substring(strInfo.indexOf(":") + 1, strInfo
+    String mdlString="";
+    if ((p=strInfo.indexOf(":")) > -1)
+      picked += strInfo.substring(p + 1, strInfo
               .indexOf("."));
 
-    picked = "(("+picked+".CA" + ")|("+picked+".P"+"))";
+    if ((p=strInfo.indexOf("/"))> -1)
+            {
+      mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
+            }
+    picked = "((" + picked + ".CA" + mdlString+")|(" + picked + ".P" + mdlString+"))";
+    jmolHistory(false);
 
     if (!atomsPicked.contains(picked))
     {
-      viewer.evalString("select " + picked + ";label %n %r:%c");
+      viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
       atomsPicked.addElement(picked);
     }
     else
@@ -841,18 +980,19 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
       viewer.evalString("select " + picked + ";label off");
       atomsPicked.removeElement(picked);
     }
+    jmolHistory(true);
+
   }
 
   public void notifyAtomHovered(int atomIndex, String strInfo, String data)
   {
-    if (data!=null)
+    if (data != null)
     {
-      System.err.println("Ignoring additional hover info: "+data);
+      System.err.println("Ignoring additional hover info: " + data);
     }
     mouseOverStructure(atomIndex, strInfo);
   }
 
-
   public void showUrl(String url)
   {
     try
@@ -885,7 +1025,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
 
   public float[][] functionXY(String functionName, int x, int y)
   {
-    return null ;
+    return null;
   }
 
   // /End JmolStatusListener
@@ -943,37 +1083,42 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
 
   public void notifyCallback(int type, Object[] data)
   {
-    try {
-    switch (type)
+    try
     {
-    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:
+      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);
+        System.err.println("Unhandled callback " + type + " " + data);
         break;
-    }
-    }
-    catch (Exception e)
+      }
+    } catch (Exception e)
     {
       System.err.println("Squashed Jmol callback handler error:");
       e.printStackTrace();
@@ -994,7 +1139,7 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
     case JmolConstants.CALLBACK_ERROR:
       return true;
     case JmolConstants.CALLBACK_CLICK:
-      case JmolConstants.CALLBACK_ANIMFRAME:
+    case JmolConstants.CALLBACK_ANIMFRAME:
     case JmolConstants.CALLBACK_MINIMIZATION:
     case JmolConstants.CALLBACK_RESIZE:
     case JmolConstants.CALLBACK_SYNC:
@@ -1005,8 +1150,9 @@ public class AppletJmol extends EmbmenuFrame implements StructureListener,
   public void setCallbackFunction(String callbackType,
           String callbackFunction)
   {
-    System.err.println("Ignoring set-callback request to associate "+callbackType+" with function "+callbackFunction);
-    
+    System.err.println("Ignoring set-callback request to associate "
+            + callbackType + " with function " + callbackFunction);
+
   }
 
 }
index 7945fa7..dcca874 100644 (file)
@@ -26,6 +26,7 @@ import java.awt.event.*;
 import java.io.*;
 
 import jalview.jbgui.GStructureViewer;
+import jalview.api.SequenceStructureBinding;
 import jalview.bin.Cache;
 import jalview.datamodel.*;
 import jalview.gui.*;
@@ -41,7 +42,7 @@ import org.jmol.popup.*;
 import org.jmol.viewer.JmolConstants;
 
 public class AppJmol extends GStructureViewer implements StructureListener,
-        JmolStatusListener, Runnable
+        JmolStatusListener, Runnable, SequenceStructureBinding
 
 {
   JmolViewer viewer;
@@ -280,14 +281,32 @@ public class AppJmol extends GStructureViewer implements StructureListener,
 
   void centerViewer()
   {
+    jmolHistory(false);
     StringBuffer cmd = new StringBuffer();
+    String lbl;
+    int mlength, p,mnum;
     for (int i = 0; i < chainMenu.getItemCount(); i++)
     {
       if (chainMenu.getItem(i) instanceof JCheckBoxMenuItem)
       {
         JCheckBoxMenuItem item = (JCheckBoxMenuItem) chainMenu.getItem(i);
         if (item.isSelected())
-          cmd.append(":" + item.getText() + " or ");
+        {          lbl = item.getText();
+        mlength = 0;
+        do
+        {
+          p = mlength;
+          mlength = lbl.indexOf(":", p);
+        } while (p < mlength && mlength < (lbl.length() - 2));
+        if (pdbentry.getId().equals(lbl.substring(0,mlength)))
+        {
+          mnum = 1+getModelNum(pdbentry.getFile());
+        if (mnum>0)
+          {cmd.append(":" + lbl.substring(mlength + 1) + " /"
+                + mnum + " or ");
+          }
+        }
+        }
       }
     }
 
@@ -296,19 +315,33 @@ public class AppJmol extends GStructureViewer implements StructureListener,
 
     viewer.evalStringQuiet("select *;restrict " + cmd + ";cartoon;center "
             + cmd);
+    jmolHistory(true);
+  }
+  private int getModelNum(String modelFileName)
+  {
+    String[] mfn = getPdbFile();
+    if (mfn == null)
+    {
+      return -1;
+    }
+    for (int i = 0; i < mfn.length; i++)
+    {
+      if (mfn[i].equalsIgnoreCase(modelFileName))
+        return i;
+    }
+    return -1;
   }
 
   void closeViewer()
   {
     viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
+    // remove listeners for all structures in viewer
+    StructureSelectionManager.getStructureSelectionManager()
+            .removeStructureViewerListener(this, getPdbFile());
+    // and shut down jmol
     viewer.evalStringQuiet("zap");
     viewer.setJmolStatusListener(null);
     viewer = null;
-
-    // We'll need to find out what other
-    // listeners need to be shut down in Jmol
-    StructureSelectionManager.getStructureSelectionManager()
-            .removeStructureViewerListener(this, pdbentry.getFile());
   }
 
   public void run()
@@ -451,15 +484,19 @@ public class AppJmol extends GStructureViewer implements StructureListener,
   {
     colourBySequence = false;
     seqColour.setSelected(false);
+    jmolHistory(false);
     viewer.evalStringQuiet("select *;color chain");
+    jmolHistory(true);
   }
 
   public void chargeColour_actionPerformed(ActionEvent actionEvent)
   {
     colourBySequence = false;
     seqColour.setSelected(false);
+    jmolHistory(false);
     viewer.evalStringQuiet("select *;color white;select ASP,GLU;color red;"
             + "select LYS,ARG;color blue;select CYS;color yellow");
+    jmolHistory(true);
   }
 
   public void zappoColour_actionPerformed(ActionEvent actionEvent)
@@ -499,6 +536,7 @@ public class AppJmol extends GStructureViewer implements StructureListener,
 
   public void setJalviewColourScheme(ColourSchemeI cs)
   {
+    jmolHistory(false);
     colourBySequence = false;
     seqColour.setSelected(false);
 
@@ -525,6 +563,7 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     }
 
     viewer.evalStringQuiet(command.toString());
+    jmolHistory(true);
   }
 
   public void userColour_actionPerformed(ActionEvent actionEvent)
@@ -539,10 +578,16 @@ public class AppJmol extends GStructureViewer implements StructureListener,
 
     if (col != null)
     {
+      jmolHistory(false);
       viewer.evalStringQuiet("background [" + col.getRed() + ","
               + col.getGreen() + "," + col.getBlue() + "];");
+      jmolHistory(true);
     }
   }
+  private void jmolHistory(boolean enable)
+  {
+    viewer.setBooleanProperty("history", enable);
+  }
 
   public void jmolHelp_actionPerformed(ActionEvent actionEvent)
   {
@@ -554,39 +599,122 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     {
     }
   }
+  String[] modelFileNames = null;
 
   // ////////////////////////////////
   // /StructureListener
-  public String getPdbFile()
+  public String[] getPdbFile()
   {
-    return pdbentry.getFile();
+    if (modelFileNames == null)
+    {
+      String mset[] = new String[viewer.getModelCount()];
+      for (int i = 0; i < mset.length; i++)
+      {
+        try {
+          String mname = viewer.getModelFileName(i);
+          if (mname==null)
+          {
+            System.err.println("Model "+i+" has no filename!");
+            continue;
+          }
+          File fpath = new File(mname);
+          mset[i] = fpath.toString();
+        } catch (Exception e)
+        {
+          System.err.println("Couldn't parse "+viewer.getModelFileName(i)+" as a file!");
+        }
+      }
+      modelFileNames = mset;
+    }
+    return modelFileNames;
   }
 
   Pattern pattern = Pattern
-          .compile("\\[(.*)\\]([0-9]+)(:[a-zA-Z]*)?\\.([a-zA-Z]+)(/[0-9]*)?");
+          .compile("\\[(.*)\\]([0-9]+)(:[a-zA-Z]*)?\\.([a-zA-Z]+).*(/[0-9]*)?");
 
   String lastMessage;
 
   public void mouseOverStructure(int atomIndex, String strInfo)
   {
+    // copied from AppJmol - will be refactored to binding eventually
+    int pdbResNum;
+    int mdlSep = strInfo.indexOf("/");
+    int chainSeparator = strInfo.indexOf(":"), chainSeparator1 = -1;
+
+    if (chainSeparator == -1)
+    {
+      chainSeparator = strInfo.indexOf(".");
+      if (mdlSep > -1 && mdlSep < chainSeparator)
+      {
+        chainSeparator1 = chainSeparator;
+        chainSeparator = mdlSep;
+      }
+    }
+    pdbResNum = Integer.parseInt(strInfo.substring(
+            strInfo.indexOf("]") + 1, chainSeparator));
+
+    String chainId;
+
+    if (strInfo.indexOf(":") > -1)
+      chainId = strInfo.substring(strInfo.indexOf(":") + 1, strInfo
+              .indexOf("."));
+    else
+    {
+      chainId = " ";
+    }
+
+    String pdbfilename = pdbentry.getFile();
+    if (mdlSep > -1)
+    {
+      if (chainSeparator1 == -1)
+      {
+        chainSeparator1 = strInfo.indexOf(".", mdlSep);
+      }
+      String mdlId = (chainSeparator1 > -1) ? strInfo.substring(mdlSep + 1,
+              chainSeparator1) : strInfo.substring(mdlSep + 1);
+      try
+      {
+        // recover PDB filename for the model hovered over.
+        pdbfilename = viewer
+                .getModelFileName(new Integer(mdlId).intValue() - 1);
+      } catch (Exception e)
+      {
+      }
+      ;
+    }
+    if (lastMessage == null || !lastMessage.equals(strInfo))
+      ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
+
+    lastMessage = strInfo;
+/*
+ * Old Implementation based on Pattern regex.
     Matcher matcher = pattern.matcher(strInfo);
     matcher.find();
     matcher.group(1);
     int pdbResNum = Integer.parseInt(matcher.group(2));
     String chainId = matcher.group(3);
-
+    
     if (chainId != null)
       chainId = chainId.substring(1, chainId.length());
     else
     {
       chainId = " ";
     }
+    String mdlId = matcher.group(4);
+    String pdbfilename = pdbentry.getFile();
 
+    if (mdlId!=null && mdlId.length()>0)
+    {
+      try {
+        // recover PDB filename for the model hovered over.
+        pdbfilename = viewer.getModelFileName(new Integer(mdlId).intValue()-1);
+      } catch (Exception e) {};
+    }
     if (lastMessage == null || !lastMessage.equals(strInfo))
     {
-      ssm.mouseOverStructure(pdbResNum, chainId, pdbentry.getFile());
+      ssm.mouseOverStructure(pdbResNum, chainId, pdbfilename);
     }
-    lastMessage = strInfo;
+    lastMessage = strInfo; */
   }
 
   StringBuffer resetLastRes = new StringBuffer();
@@ -596,38 +724,47 @@ 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()))
+    int mdlNum = 1+getModelNum(pdbfile);
+    if (mdlNum==0)
+    {
       return;
+    }
 
+    jmolHistory(false);
+    // if (!pdbfile.equals(pdbentry.getFile()))
+    // return;
     if (resetLastRes.length() > 0)
     {
       viewer.evalStringQuiet(resetLastRes.toString());
     }
 
     eval.setLength(0);
-    eval.append("select " + pdbResNum);
+    eval.append("select " + pdbResNum); // +modelNum
 
     resetLastRes.setLength(0);
-    resetLastRes.append("select " + pdbResNum);
+    resetLastRes.append("select " + pdbResNum); // +modelNum
 
-    eval.append(":");
-    resetLastRes.append(":");
     if (!chain.equals(" "))
     {
+      eval.append(":");
+      resetLastRes.append(":");
       eval.append(chain);
       resetLastRes.append(chain);
     }
-
-    eval.append(";wireframe 100;" + eval.toString() + " and not hetero;"); // ".*;");
+    // if (mdlNum != 0)
+    {
+      eval.append(" /" + (mdlNum));
+      resetLastRes.append(" /" + (mdlNum));
+    }
+    eval.append(";wireframe 100;" + eval.toString() + " and not hetero;");
 
     resetLastRes.append(";wireframe 0;" + resetLastRes.toString()
-    // + ".*;spacefill 0;");
-            + " and not hetero;spacefill 0;");
+            + " and not hetero; spacefill 0;");
 
     eval.append("spacefill 200;select none");
-    // System.out.println("jmol:\n"+eval+"\n");
+
     viewer.evalStringQuiet(eval.toString());
+    jmolHistory(true);
   }
 
   public Color getColour(int atomIndex, int pdbResNum, String chain,
@@ -658,11 +795,8 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     if (!colourBySequence || ap.alignFrame.getCurrentView() != ap.av)
       return;
 
-    StructureMapping[] mapping = ssm.getMapping(pdbentry.getFile());
-
-    if (mapping.length < 1)
-      return;
-
+    String[] files = getPdbFile();
+    
     SequenceRenderer sr = new SequenceRenderer(ap.av);
 
     boolean showFeatures = false;
@@ -679,6 +813,13 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     }
 
     StringBuffer command = new StringBuffer();
+    for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
+    {
+      StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
+
+      if (mapping == null || mapping.length < 1)
+        continue;
+
 
     int lastPos = -1;
     for (int sp, s = 0; s < sequence.length; s++)
@@ -707,36 +848,38 @@ public class AppJmol extends GStructureViewer implements StructureListener,
 
             if (showFeatures)
               col = fr.findFeatureColour(col, asp, r);
-
-            if (command.toString().endsWith(
-                    ":" + mapping[m].getChain() + ";color[" + col.getRed()
-                            + "," + col.getGreen() + "," + col.getBlue()
-                            + "]"))
+            String newSelcom = (mapping[m].getChain() != " " ? ":"
+                    + mapping[m].getChain() : "")
+                    + "/"
+                    + (pdbfnum + 1)
+                    + ".1"
+                    + ";color["
+                    + col.getRed()
+                    + ","
+                    + col.getGreen()
+                    + ","
+                    + col.getBlue() + "]";
+            if (command.toString().endsWith(newSelcom))
             {
               command = condenseCommand(command, pos);
               continue;
             }
 
             command.append(";select " + pos);
-
-            if (!mapping[m].getChain().equals(" "))
-            {
-              command.append(":" + mapping[m].getChain());
-            }
-
-            command.append(";color[" + col.getRed() + "," + col.getGreen()
-                    + "," + col.getBlue() + "]");
-
+            command.append(newSelcom);
           }
           break;
         }
       }
+      }
     }
+    jmolHistory(false);
 
     if (lastCommand == null || !lastCommand.equals(command.toString()))
     {
       viewer.evalStringQuiet(command.toString());
     }
+    jmolHistory(true);
     lastCommand = command.toString();
   }
 
@@ -778,7 +921,7 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     System.out.println("JMOL CREATE IMAGE");
   }
 
-  public void notifyFileLoaded(String fullPathName, String fileName,
+  public void notifyFileLoaded(String fullPathName, String fileName2,
           String modelName, String errorMsg, int modelParts)
   {
     if (errorMsg != null)
@@ -789,29 +932,38 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     }
 
     fileLoadingError = null;
+    modelFileNames = null;
+    
+    String[] modelfilenames = getPdbFile();
+    ssm = StructureSelectionManager.getStructureSelectionManager();
+    boolean modelsloaded=false;
+    for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
+    {
+      String fileName = modelfilenames[modelnum];
 
     if (fileName != null)
     {
-      // TODO: do some checking using the modelPts number of parts against our own estimate of the number of chains
+      modelsloaded=true;
+      // search pdbentries and sequences to find correct pdbentry and sequence[] pair for this filename
+      if (pdbentry.getFile().equals(fileName))
+      {
+      // 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
               .getFile(), AppletFormatAdapter.FILE);
-      ssm.addStructureViewerListener(this);
       Vector chains = new Vector();
       for (int i = 0; i < pdbFile.chains.size(); i++)
       {
         chains
-                .addElement(((MCview.PDBChain) pdbFile.chains.elementAt(i)).id);
+                .addElement(new String(pdbFile.id+":"+((MCview.PDBChain) pdbFile.chains.elementAt(i)).id));
       }
       setChainMenuItems(chains);
 
-      jmolpopup.updateComputedMenus();
-
       if (!loadingFromArchive)
       {
         viewer
-                .evalStringQuiet("select backbone;restrict;cartoon;wireframe off;spacefill off");
+                .evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
 
         colourBySequence(ap);
       }
@@ -820,8 +972,23 @@ public class AppJmol extends GStructureViewer implements StructureListener,
 
       loadingFromArchive = false;
     }
-    else
-      return;
+    else {
+      // this is a foreign pdb file that jalview doesn't know about - add it to the dataset
+      // and try to find a home - either on a matching sequence or as a new sequence.
+      String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
+              "PDB");
+      // parse pdb file into a chain, etc.
+      // locate best match for pdb in associated views and add mapping to
+      // ssm
+      modelsloaded=true;
+    }
+    }
+    }
+    if (modelsloaded)
+    {
+      ssm.addStructureViewerListener(this);
+      jmolpopup.updateComputedMenus();
+    }
   }
 
   public void sendConsoleEcho(String strEcho)
@@ -854,10 +1021,12 @@ public class AppJmol extends GStructureViewer implements StructureListener,
 
   public void notifyAtomPicked(int atomIndex, String strInfo, String strData)
   {
-    if (strData!=null)
+    if (strData != null)
     {
-      Cache.log.info("Non null pick data string: "+strData+" (other info: '"+strInfo+"' pos "+atomIndex+")");
+      Cache.log.info("Non null pick data string: " + strData
+              + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
     }
+    /*
     Matcher matcher = pattern.matcher(strInfo);
     matcher.find();
 
@@ -867,17 +1036,35 @@ public class AppJmol extends GStructureViewer implements StructureListener,
 
     String picked = resnum;
 
+
     if (chainId != null)
       picked += (":" + chainId.substring(1, chainId.length()));
-
-    picked = "(("+picked+".CA" + ")|("+picked+".P"+"))";
-
+*/
+    int chainSeparator = strInfo.indexOf(":");
+    int p=0;
+    if (chainSeparator == -1)
+      chainSeparator = strInfo.indexOf(".");
+
+    String picked = strInfo.substring(strInfo.indexOf("]") + 1,
+            chainSeparator);
+    String mdlString="";
+    if ((p=strInfo.indexOf(":")) > -1)
+      picked += strInfo.substring(p + 1, strInfo
+              .indexOf("."));
+
+    if ((p=strInfo.indexOf("/"))> -1)
+            {
+      mdlString += strInfo.substring(p, strInfo.indexOf(" #"));
+            }
+    picked = "((" + picked + ".CA" + mdlString+")|(" + picked + ".P" + mdlString+"))";
+    jmolHistory(false);
     if (!atomsPicked.contains(picked))
     {
-      if (chainId != null)
+      // TODO: re-instate chain ID separator dependent labelling for both applet and application
+//      if (chainId != null)
         viewer.evalString("select " + picked + ";label %n %r:%c");
-      else
-        viewer.evalString("select " + picked + ";label %n %r");
+//      else
+//        viewer.evalString("select " + picked + ";label %n %r");
       atomsPicked.addElement(picked);
     }
     else
@@ -885,7 +1072,7 @@ public class AppJmol extends GStructureViewer implements StructureListener,
       viewer.evalString("select " + picked + ";label off");
       atomsPicked.removeElement(picked);
     }
-
+    jmolHistory(true);
     if (scriptWindow != null)
     {
       scriptWindow.sendConsoleMessage(strInfo);
@@ -895,9 +1082,10 @@ public class AppJmol extends GStructureViewer implements StructureListener,
 
   public void notifyAtomHovered(int atomIndex, String strInfo, String data)
   {
-    if (data!=null)
+    if (data != null)
     {
-      Cache.log.info("Non null hover data string: "+data+" (other info: '"+strInfo+"' pos "+atomIndex+")");
+      Cache.log.info("Non null hover data string: " + data
+              + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
     }
     mouseOverStructure(atomIndex, strInfo);
   }
@@ -905,11 +1093,12 @@ public class AppJmol extends GStructureViewer implements StructureListener,
   @Override
   public void showUrl(String url)
   {
-    try {
+    try
+    {
       jalview.util.BrowserLauncher.openURL(url);
     } catch (IOException e)
     {
-      Cache.log.error("Failed to launch Jmol-associated url "+url,e);
+      Cache.log.error("Failed to launch Jmol-associated url " + url, e);
       // TODO: 2.6 : warn user if browser was not configured.
     }
   }
@@ -1024,39 +1213,44 @@ public class AppJmol extends GStructureViewer implements StructureListener,
   @Override
   public void notifyCallback(int type, Object[] data)
   {
-    try {
-    switch (type)
+    try
     {
-    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:
+      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);
+        System.err.println("Unhandled callback " + type + " " + data);
         break;
-    }
-    }
-    catch (Exception e)
+      }
+    } catch (Exception e)
     {
-      Cache.log.warn("Squashed Jmol callback handler error: ",e);
+      Cache.log.warn("Squashed Jmol callback handler error: ", e);
     }
   }
 
@@ -1075,7 +1269,7 @@ public class AppJmol extends GStructureViewer implements StructureListener,
     case JmolConstants.CALLBACK_ERROR:
       return true;
     case JmolConstants.CALLBACK_CLICK:
-      case JmolConstants.CALLBACK_ANIMFRAME:
+    case JmolConstants.CALLBACK_ANIMFRAME:
     case JmolConstants.CALLBACK_MINIMIZATION:
     case JmolConstants.CALLBACK_RESIZE:
     case JmolConstants.CALLBACK_SYNC:
@@ -1087,8 +1281,9 @@ public class AppJmol extends GStructureViewer implements StructureListener,
   public void setCallbackFunction(String callbackType,
           String callbackFunction)
   {
-    Cache.log.debug("Ignoring set-callback request to associate "+callbackType+" with function "+callbackFunction);
-    
+    Cache.log.debug("Ignoring set-callback request to associate "
+            + callbackType + " with function " + callbackFunction);
+
   }
 
 }
index 940a782..103c854 100644 (file)
@@ -19,7 +19,7 @@ package jalview.structure;
 
 public interface StructureListener
 {
-  public String getPdbFile();
+  public String[] getPdbFile();
 
   public void mouseOverStructure(int atomIndex, String strInfo);
 
index 483f1a4..d2b336d 100644 (file)
@@ -133,10 +133,12 @@ public class StructureSelectionManager
 
       for (int i = 0; i < pdb.chains.size(); i++)
       {
-        
-        // TODO: correctly determine sequence type for mixed na/peptide structures
+
+        // TODO: correctly determine sequence type for mixed na/peptide
+        // structures
         AlignSeq as = new AlignSeq(sequence[s], ((PDBChain) pdb.chains
-                .elementAt(i)).sequence, ((PDBChain)pdb.chains.elementAt(i)).isNa ? AlignSeq.DNA : AlignSeq.PEP);
+                .elementAt(i)).sequence, ((PDBChain) pdb.chains
+                .elementAt(i)).isNa ? AlignSeq.DNA : AlignSeq.PEP);
         as.calcScoreMatrix();
         as.traceAlignment();
         PDBChain chain = ((PDBChain) pdb.chains.elementAt(i));
@@ -222,32 +224,42 @@ public class StructureSelectionManager
     return pdb;
   }
 
-  public void removeStructureViewerListener(Object svl, String pdbfile)
+  public void removeStructureViewerListener(Object svl, String[] pdbfiles)
   {
     listeners.removeElement(svl);
-
+    if (pdbfiles==null)
+    {
+      return;
+    }
     boolean removeMapping = true;
-
+    String[] handlepdbs;
+    Vector pdbs = new Vector();
+    for (int i = 0; i < pdbfiles.length; pdbs.addElement(pdbfiles[i++]))
+      ;
     StructureListener sl;
     for (int i = 0; i < listeners.size(); i++)
     {
       if (listeners.elementAt(i) instanceof StructureListener)
       {
         sl = (StructureListener) listeners.elementAt(i);
-        if (sl.getPdbFile().equals(pdbfile))
+        handlepdbs = sl.getPdbFile();
+        for (int j = 0; j < handlepdbs.length; j++)
         {
-          removeMapping = false;
-          break;
+          if (pdbs.contains(handlepdbs[j]))
+          {
+            pdbs.removeElement(handlepdbs[j]);
+          }
         }
+
       }
     }
-
-    if (removeMapping && mappings != null)
+    
+    if (pdbs.size()>0  && mappings != null)
     {
       Vector tmp = new Vector();
       for (int i = 0; i < mappings.length; i++)
       {
-        if (!mappings[i].pdbfile.equals(pdbfile))
+        if (!pdbs.contains(mappings[i].pdbfile))
         {
           tmp.addElement(mappings[i]);
         }