upgrading structure/sequence binding so that a structure view can contain many pdb...
[jalview.git] / src / jalview / appletgui / AppletJmol.java
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);
+
   }
 
 }