revised sequence/structure binding so one structure associated with x-seuqenceI's...
[jalview.git] / src / jalview / ext / jmol / JalviewJmolBinding.java
index fbd7176..8831bd6 100644 (file)
  */
 package jalview.ext.jmol;
 
+import java.io.File;
+import java.net.URL;
 import java.util.*;
+import java.applet.Applet;
 import java.awt.*;
 import java.awt.event.*;
 
@@ -37,9 +40,30 @@ import org.jmol.viewer.JmolConstants;
 import jalview.schemes.*;
 
 public abstract class JalviewJmolBinding implements StructureListener,
-        JmolStatusListener, SequenceStructureBinding
+        JmolStatusListener, SequenceStructureBinding, JmolSelectionListener
 
 {
+  /**
+   * set if Jmol state is being restored from some source - instructs binding
+   * not to apply default display style when structure set is updated for first
+   * time.
+   */
+  private boolean loadingFromArchive = false;
+
+  /**
+   * state flag used to check if the Jmol viewer's paint method can be called
+   */
+  private boolean finishedInit = false;
+
+  public boolean isFinishedInit()
+  {
+    return finishedInit;
+  }
+
+  public void setFinishedInit(boolean finishedInit)
+  {
+    this.finishedInit = finishedInit;
+  }
 
   boolean allChainsSelected = false;
 
@@ -51,15 +75,18 @@ public abstract class JalviewJmolBinding implements StructureListener,
 
   Vector atomsPicked = new Vector();
 
-  private Vector chainNames;
+  public Vector chainNames;
 
-  String[] chains;
+  /**
+   * array of target chains for seuqences - tied to pdbentry and sequence[]
+   */
+  protected String[][] chains;
 
   boolean colourBySequence = true;
 
   StringBuffer eval = new StringBuffer();
 
-  String fileLoadingError;
+  public String fileLoadingError;
 
   /**
    * the default or current model displayed if the model cannot be identified
@@ -67,7 +94,7 @@ public abstract class JalviewJmolBinding implements StructureListener,
    */
   int frameNo = 0;
 
-  JmolPopup jmolpopup;
+  protected JmolPopup jmolpopup;
 
   String lastCommand;
 
@@ -80,7 +107,7 @@ public abstract class JalviewJmolBinding implements StructureListener,
    */
   String[] modelFileNames = null;
 
-  PDBEntry[] pdbentry;
+  public PDBEntry[] pdbentry;
 
   /**
    * datasource protocol for access to PDBEntry
@@ -89,15 +116,26 @@ public abstract class JalviewJmolBinding implements StructureListener,
 
   StringBuffer resetLastRes = new StringBuffer();
 
-  SequenceI[] sequence;
+  /**
+   * sequences mapped to each pdbentry
+   */
+  public SequenceI[][] sequence;
 
   StructureSelectionManager ssm;
 
-  JmolViewer viewer;
+  public JmolViewer viewer;
 
-  public JalviewJmolBinding(PDBEntry[] pdbentry, SequenceI[] seq,
-          String[] chains, String protocol)
+  public JalviewJmolBinding(PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
+          String[][] chains, String protocol)
   {
+    this.sequence = sequenceIs;
+    this.chains = chains;
+    this.pdbentry = pdbentry;
+    this.protocol = protocol;
+    if (chains == null)
+    {
+      this.chains = new String[pdbentry.length][];
+    }
     /*
      * viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
      * "jalviewJmol", ap.av.applet .getDocumentBase(),
@@ -107,6 +145,45 @@ public abstract class JalviewJmolBinding implements StructureListener,
      */
   }
 
+  public JalviewJmolBinding(JmolViewer viewer2)
+  {
+    viewer = viewer2;
+    viewer.setJmolStatusListener(this);
+    viewer.addSelectionListener(this);
+  }
+
+  /**
+   * construct a title string for the viewer window based on the data jalview
+   * knows about
+   * 
+   * @return
+   */
+  public String getViewerTitle()
+  {
+    if (sequence == null || pdbentry == null || sequence.length < 1
+            || pdbentry.length < 1)
+    {
+      return ("Jalview Jmol Window");
+    }
+    StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
+            + pdbentry[0].getId());
+
+    if (pdbentry[0].getProperty() != null)
+    {
+      if (pdbentry[0].getProperty().get("method") != null)
+      {
+        title.append(" Method: ");
+        title.append(pdbentry[0].getProperty().get("method"));
+      }
+      if (pdbentry[0].getProperty().get("chains") != null)
+      {
+        title.append(" Chain:");
+        title.append(pdbentry[0].getProperty().get("chains"));
+      }
+    }
+    return title.toString();
+  }
+
   /**
    * prepare the view for a given set of models/chains. chainList contains
    * strings of the form 'pdbfilename:Chaincode'
@@ -114,7 +191,7 @@ public abstract class JalviewJmolBinding implements StructureListener,
    * @param chainList
    *          list of chains to make visible
    */
-  void centerViewer(Vector chainList)
+  public void centerViewer(Vector chainList)
   {
     StringBuffer cmd = new StringBuffer();
     String lbl;
@@ -133,15 +210,10 @@ public abstract class JalviewJmolBinding implements StructureListener,
     }
     if (cmd.length() > 0)
       cmd.setLength(cmd.length() - 4);
-
-    jmolHistory(false);
-    viewer
-            .evalString("select *;restrict " + cmd + ";cartoon;center "
-                    + cmd);
-    jmolHistory(true);
+    evalStateCommand("select *;restrict " + cmd + ";cartoon;center " + cmd);
   }
 
-  void closeViewer()
+  public void closeViewer()
   {
     viewer.setModeMouse(org.jmol.viewer.JmolConstants.MOUSE_NONE);
     // remove listeners for all structures in viewer
@@ -150,25 +222,247 @@ public abstract class JalviewJmolBinding implements StructureListener,
     // and shut down jmol
     viewer.evalStringQuiet("zap");
     viewer.setJmolStatusListener(null);
-
+    lastCommand = null;
     viewer = null;
   }
 
   public void colourByChain()
   {
-    jmolHistory(false);
     colourBySequence = false;
-    viewer.evalStringQuiet("select *;color chain");
-    jmolHistory(true);
-  } 
+    evalStateCommand("select *;color chain");
+  }
 
   public void colourByCharge()
   {
-    jmolHistory(false);
     colourBySequence = false;
-    viewer.evalStringQuiet("select *;color white;select ASP,GLU;color red;"
+    evalStateCommand("select *;color white;select ASP,GLU;color red;"
             + "select LYS,ARG;color blue;select CYS;color yellow");
+  }
+
+  /**
+   * superpose the structures associated with sequences in the alignment
+   * according to their corresponding positions.
+   */
+  public void superposeStructures(AlignmentI alignment)
+  {
+    superposeStructures(alignment, -1, null);
+  }
+
+  /**
+   * superpose the structures associated with sequences in the alignment
+   * according to their corresponding positions. ded)
+   * 
+   * @param refStructure
+   *          - select which pdb file to use as reference (default is -1 - the
+   *          first structure in the alignment)
+   */
+  public void superposeStructures(AlignmentI alignment, int refStructure)
+  {
+    superposeStructures(alignment, refStructure, null);
+  }
+
+  /**
+   * superpose the structures associated with sequences in the alignment
+   * according to their corresponding positions. ded)
+   * @param refStructure
+   *          - select which pdb file to use as reference (default is -1 - the
+   *          first structure in the alignment)
+   * @param hiddenCols TODO
+   */
+  public void superposeStructures(AlignmentI alignment, int refStructure, ColumnSelection hiddenCols)
+  {
+    String[] files = getPdbFile();
+    if (refStructure>=files.length)
+    {
+      System.err.println("Invalid reference structure value "+refStructure);
+      refStructure= -1;
+    }
+    if (refStructure<-1)
+    {
+      refStructure=-1;
+    }
+    StringBuffer command = new StringBuffer(), selectioncom = new StringBuffer();
+    
+    boolean matched[] = new boolean[alignment.getWidth()];
+    for (int m = 0; m < matched.length; m++)
+    {
+      
+      matched[m] = (hiddenCols!=null) ? hiddenCols.isVisible(m) : true;
+    }
+    
+    int commonrpositions[][] = new int[files.length][alignment.getWidth()];
+    String isel[] = new String[files.length];
+    // reference structure - all others are superposed in it
+    String[] targetC = new String[files.length];
+    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 s = 0; s < sequence[pdbfnum].length; s++)
+      {
+        for (int sp, m = 0; m < mapping.length; m++)
+        {
+          if (mapping[m].getSequence() == sequence[pdbfnum][s]
+                  && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
+          {
+            if (refStructure == -1)
+            {
+              refStructure = pdbfnum;
+            }
+            SequenceI asp = alignment.getSequenceAt(sp);
+            for (int r = 0; r < matched.length; r++)
+            {
+              if (!matched[r])
+              {
+                continue;
+              }
+              matched[r] = false; // assume this is not a good site
+              if (r >= asp.getLength())
+              {
+                continue;
+              }
+
+              if (jalview.util.Comparison.isGap(asp.getCharAt(r)))
+              {
+                // no mapping to gaps in sequence
+                continue;
+              }
+              int t = asp.findPosition(r); // sequence position
+              int apos = mapping[m].getAtomNum(t);
+              int pos = mapping[m].getPDBResNum(t);
+
+              if (pos < 1 || pos == lastPos)
+              {
+                // can't align unmapped sequence
+                continue;
+              }
+              matched[r] = true; // this is a good ite
+              lastPos = pos;
+              // just record this residue position
+              commonrpositions[pdbfnum][r] = pos;
+            }
+            // create model selection suffix
+            isel[pdbfnum] = "/" + (pdbfnum + 1) + ".1";
+            if (mapping[m].getChain() == null
+                    || mapping[m].getChain().trim().length() == 0)
+            {
+              targetC[pdbfnum] = "";
+            }
+            else
+            {
+              targetC[pdbfnum] = ":" + mapping[m].getChain();
+            }
+            // move on to next pdb file
+            s = sequence[pdbfnum].length;
+            break;
+          }
+        }
+      }
+    }
+    StringBuffer selcom[] = new StringBuffer[files.length];
+    // generate select statements to select regions to superimpose structures
+    {
+      for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
+      {
+        String chainCd = targetC[pdbfnum];
+        int lpos = -1;
+        boolean run = false;
+        StringBuffer molsel = (selcom[pdbfnum] = new StringBuffer());
+        molsel.append("{");
+        for (int r = 0; r < matched.length; r++)
+        {
+          if (matched[r])
+          {
+
+            if (lpos != commonrpositions[pdbfnum][r] - 1)
+            {
+              // discontinuity
+              if (lpos != -1)
+              {
+                molsel.append(lpos);
+                molsel.append(chainCd);
+                // molsel.append("} {");
+                molsel.append("|");
+              }
+            }
+            else
+            {
+              // continuous run - and lpos >-1
+              if (!run)
+              {
+                // at the beginning, so add dash
+                molsel.append(lpos);
+                molsel.append("-");
+              }
+              run = true;
+            }
+            lpos = commonrpositions[pdbfnum][r];
+            // molsel.append(lpos);
+          }
+        }
+        // add final selection phrase
+        if (lpos != -1)
+        {
+          molsel.append(lpos);
+          molsel.append(chainCd);
+          molsel.append("}");
+        }
+        selectioncom.append("((");
+        selectioncom.append(molsel.subSequence(1, molsel.length()-1));
+        selectioncom.append(" )& ");
+        selectioncom.append(pdbfnum+1);
+        selectioncom.append(".1)");
+        if (pdbfnum<files.length-1)
+        {
+          selectioncom.append("|");
+        }
+      }
+    }
+
+    for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
+    {
+      if (pdbfnum == refStructure)
+      {
+        continue;
+      }
+      command.append("compare ");
+      command.append("{");
+      command.append(1 + pdbfnum);
+      command.append(".1} {");
+      command.append(1 + refStructure);
+      command.append(".1} SUBSET {*.CA | *.P} ATOMS ");
+
+      // form the matched pair strings
+      String sep = "";
+      for (int s = 0; s < 2; s++)
+      {
+        command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
+      }
+      command.append(" ROTATE TRANSLATE;\n");
+    }
+    System.out.println("Select regions:\n" + selectioncom.toString());
+    evalStateCommand("select *; cartoons off; backbone; select ("+selectioncom.toString()+"); cartoons; ");
+    // selcom.append("; ribbons; ");
+    System.out.println("Superimpose command(s):\n" + command.toString());
+
+    evalStateCommand(command.toString());
+    
+    // evalStateCommand("select *; backbone; select "+selcom.toString()+"; cartoons; center "+selcom.toString());
+  }
+
+  public void evalStateCommand(String command)
+  {
+    jmolHistory(false);
+    if (lastCommand == null || !lastCommand.equals(command))
+    {
+      viewer.evalStringQuiet(command + "\n");
+    }
     jmolHistory(true);
+    lastCommand = command;
   }
 
   /**
@@ -180,6 +474,10 @@ public abstract class JalviewJmolBinding implements StructureListener,
   {
     if (!colourBySequence)
       return;
+    if (ssm == null)
+    {
+      return;
+    }
     String[] files = getPdbFile();
     SequenceRenderer sr = getSequenceRenderer();
 
@@ -199,12 +497,12 @@ public abstract class JalviewJmolBinding implements StructureListener,
         continue;
 
       int lastPos = -1;
-      for (int s = 0; s < sequence.length; s++)
+      for (int s = 0; s < sequence[pdbfnum].length; s++)
       {
         for (int sp, m = 0; m < mapping.length; m++)
         {
-          if (mapping[m].getSequence() == sequence[s]
-                  && (sp = alignment.findIndex(sequence[s])) > -1)
+          if (mapping[m].getSequence() == sequence[pdbfnum][s]
+                  && (sp = alignment.findIndex(sequence[pdbfnum][s])) > -1)
           {
             SequenceI asp = alignment.getSequenceAt(sp);
             for (int r = 0; r < asp.getLength(); r++)
@@ -221,10 +519,10 @@ public abstract class JalviewJmolBinding implements StructureListener,
 
               lastPos = pos;
 
-              Color col = sr.getResidueBoxColour(sequence[s], r);
+              Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r);
 
               if (showFeatures)
-                col = fr.findFeatureColour(col, sequence[s], r);
+                col = fr.findFeatureColour(col, sequence[pdbfnum][s], r);
               String newSelcom = (mapping[m].getChain() != " " ? ":"
                       + mapping[m].getChain() : "")
                       + "/"
@@ -252,21 +550,24 @@ public abstract class JalviewJmolBinding implements StructureListener,
         }
       }
     }
+    evalStateCommand(command.toString());
+  }
 
-    jmolHistory(false);
-    if (lastCommand == null || !lastCommand.equals(command.toString()))
-    {
-      viewer.evalStringQuiet(command.toString());
-    }
-    jmolHistory(true);
-    lastCommand = command.toString();
+  public boolean isColourBySequence()
+  {
+    return colourBySequence;
+  }
+
+  public void setColourBySequence(boolean colourBySequence)
+  {
+    this.colourBySequence = colourBySequence;
   }
 
   StringBuffer condenseCommand(String command, int pos)
   {
 
-    StringBuffer sb = new StringBuffer(command.substring(0, command
-            .lastIndexOf("select") + 7));
+    StringBuffer sb = new StringBuffer(command.substring(0,
+            command.lastIndexOf("select") + 7));
 
     command = command.substring(sb.length());
 
@@ -288,12 +589,13 @@ public abstract class JalviewJmolBinding implements StructureListener,
 
   public void createImage(String file, String type, int quality)
   {
+    System.out.println("JMOL CREATE IMAGE");
   }
 
   public String createImage(String fileName, String type,
           Object textOrBytes, int quality)
   {
-    // TODO Auto-generated method stub
+    System.out.println("JMOL CREATE IMAGE");
     return null;
   }
 
@@ -333,7 +635,14 @@ public abstract class JalviewJmolBinding implements StructureListener,
    * 
    * @return
    */
-  abstract FeatureRenderer getFeatureRenderer();
+  public abstract FeatureRenderer getFeatureRenderer();
+
+  /**
+   * instruct the Jalview binding to update the pdbentries vector if necessary
+   * prior to matching the jmol view's contents to the list of structure files
+   * Jalview knows about.
+   */
+  public abstract void refreshPdbEntries();
 
   private int getModelNum(String modelFileName)
   {
@@ -366,7 +675,10 @@ public abstract class JalviewJmolBinding implements StructureListener,
     return modelFileNames;
   }
 
-  public Hashtable getRegistryInfo()
+  /**
+   * map from string to applet
+   */
+  public Map getRegistryInfo()
   {
     // TODO Auto-generated method stub
     return null;
@@ -378,7 +690,7 @@ public abstract class JalviewJmolBinding implements StructureListener,
    * 
    * @return
    */
-  abstract SequenceRenderer getSequenceRenderer();
+  public abstract SequenceRenderer getSequenceRenderer();
 
   // ///////////////////////////////
   // JmolStatusListener
@@ -449,9 +761,11 @@ public abstract class JalviewJmolBinding implements StructureListener,
 
   }
 
+  boolean debug = true;
+
   private void jmolHistory(boolean enable)
   {
-    viewer.setBooleanProperty("history", enable);
+    viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
   }
 
   public void loadInline(String string)
@@ -481,8 +795,8 @@ public abstract class JalviewJmolBinding implements StructureListener,
     String chainId;
 
     if (strInfo.indexOf(":") > -1)
-      chainId = strInfo.substring(strInfo.indexOf(":") + 1, strInfo
-              .indexOf("."));
+      chainId = strInfo.substring(strInfo.indexOf(":") + 1,
+              strInfo.indexOf("."));
     else
     {
       chainId = " ";
@@ -518,7 +832,8 @@ public abstract class JalviewJmolBinding implements StructureListener,
   {
     if (data != null)
     {
-      System.err.println("Ignoring additional hover info: " + data);
+      System.err.println("Ignoring additional hover info: " + data
+              + " (other info: '" + strInfo + "' pos " + atomIndex + ")");
     }
     mouseOverStructure(atomIndex, strInfo);
   }
@@ -569,6 +884,13 @@ public abstract class JalviewJmolBinding implements StructureListener,
       atomsPicked.removeElement(picked);
     }
     jmolHistory(true);
+    // TODO: in application this happens
+    //
+    // if (scriptWindow != null)
+    // {
+    // scriptWindow.sendConsoleMessage(strInfo);
+    // scriptWindow.sendConsoleMessage("\n");
+    // }
 
   }
 
@@ -580,8 +902,8 @@ public abstract class JalviewJmolBinding implements StructureListener,
       {
       case JmolConstants.CALLBACK_LOADSTRUCT:
         notifyFileLoaded((String) data[1], (String) data[2],
-                (String) data[3], (String) data[4], ((Integer) data[5])
-                        .intValue());
+                (String) data[3], (String) data[4],
+                ((Integer) data[5]).intValue());
 
         break;
       case JmolConstants.CALLBACK_PICK:
@@ -593,8 +915,8 @@ public abstract class JalviewJmolBinding implements StructureListener,
                 (String) data[0]);
         break;
       case JmolConstants.CALLBACK_SCRIPT:
-        notifyScriptTermination((String) data[2], ((Integer) data[3])
-                .intValue());
+        notifyScriptTermination((String) data[2],
+                ((Integer) data[3]).intValue());
         break;
       case JmolConstants.CALLBACK_ECHO:
         sendConsoleEcho((String) data[1]);
@@ -603,10 +925,20 @@ public abstract class JalviewJmolBinding implements StructureListener,
         sendConsoleMessage((data == null) ? ((String) null)
                 : (String) data[1]);
         break;
+      case JmolConstants.CALLBACK_ERROR:
+        // System.err.println("Ignoring error callback.");
+        break;
+      case JmolConstants.CALLBACK_SYNC:
+      case JmolConstants.CALLBACK_RESIZE:
+        refreshGUI();
+        break;
       case JmolConstants.CALLBACK_MEASURE:
+
       case JmolConstants.CALLBACK_CLICK:
+
       default:
-        System.err.println("Unhandled callback " + type + " " + data);
+        System.err.println("Unhandled callback " + type + " "
+                + data[1].toString());
         break;
       }
     } catch (Exception e)
@@ -629,11 +961,11 @@ public abstract class JalviewJmolBinding implements StructureListener,
     case JmolConstants.CALLBACK_HOVER:
     case JmolConstants.CALLBACK_ERROR:
       return true;
+    case JmolConstants.CALLBACK_RESIZE:
+    case JmolConstants.CALLBACK_SYNC:
     case JmolConstants.CALLBACK_CLICK:
     case JmolConstants.CALLBACK_ANIMFRAME:
     case JmolConstants.CALLBACK_MINIMIZATION:
-    case JmolConstants.CALLBACK_RESIZE:
-    case JmolConstants.CALLBACK_SYNC:
     }
     return false;
   }
@@ -644,25 +976,65 @@ public abstract class JalviewJmolBinding implements StructureListener,
     if (errorMsg != null)
     {
       fileLoadingError = errorMsg;
-      updateUI();
+      refreshGUI();
       return;
     }
+    // the rest of this routine ignores the arguments, and simply interrogates
+    // the Jmol view to find out what structures it contains, and adds them to
+    // the structure selection manager.
     fileLoadingError = null;
+    String[] oldmodels = modelFileNames;
     modelFileNames = null;
     chainNames = new Vector();
     boolean notifyLoaded = false;
     String[] modelfilenames = getPdbFile();
     ssm = StructureSelectionManager.getStructureSelectionManager();
+    // first check if we've lost any structures
+    if (oldmodels != null && oldmodels.length > 0)
+    {
+      int oldm = 0;
+      for (int i = 0; i < oldmodels.length; i++)
+      {
+        for (int n = 0; n < modelfilenames.length; n++)
+        {
+          if (modelfilenames[n] == oldmodels[i])
+          {
+            oldmodels[i] = null;
+            break;
+          }
+        }
+        if (oldmodels[i] != null)
+        {
+          oldm++;
+        }
+      }
+      if (oldm > 0)
+      {
+        String[] oldmfn = new String[oldm];
+        oldm = 0;
+        for (int i = 0; i < oldmodels.length; i++)
+        {
+          if (oldmodels[i] != null)
+          {
+            oldmfn[oldm++] = oldmodels[i];
+          }
+        }
+        // deregister the Jmol instance for these structures - we'll add
+        // ourselves again at the end for the current structure set.
+        ssm.removeStructureViewerListener(this, oldmfn);
+      }
+    }
+    refreshPdbEntries();
     for (int modelnum = 0; modelnum < modelfilenames.length; modelnum++)
     {
       String fileName = modelfilenames[modelnum];
       if (fileName != null)
       {
+        boolean foundEntry = false;
         // search pdbentries and sequences to find correct pdbentry and
         // sequence[] pair for this filename
         if (pdbentry != null)
         {
-          boolean foundEntry = false;
           for (int pe = 0; pe < pdbentry.length; pe++)
           {
             if (pdbentry[pe].getFile().equals(fileName))
@@ -672,8 +1044,8 @@ public abstract class JalviewJmolBinding implements StructureListener,
               if (loadedInline)
               {
                 // TODO: replace with getData ?
-                pdb = ssm.setMapping(sequence, chains, pdbentry[pe]
-                        .getFile(), AppletFormatAdapter.PASTE);
+                pdb = ssm.setMapping(sequence[pe], chains[pe],
+                        pdbentry[pe].getFile(), AppletFormatAdapter.PASTE);
                 pdbentry[pe].setFile("INLINE" + pdb.id);
               }
               else
@@ -683,9 +1055,22 @@ public abstract class JalviewJmolBinding implements StructureListener,
                 // needs
                 // to be tested. See mantis bug
                 // https://mantis.lifesci.dundee.ac.uk/view.php?id=36605
-
-                pdb = ssm.setMapping(sequence, chains, pdbentry[pe]
-                        .getFile(), AppletFormatAdapter.URL);
+                String protocol = AppletFormatAdapter.URL;
+                try
+                {
+                  File fl = new java.io.File(pdbentry[pe].getFile());
+                  if (fl.exists())
+                  {
+                    protocol = AppletFormatAdapter.FILE;
+                  }
+                } catch (Exception e)
+                {
+                } catch (Error e)
+                {
+                }
+                ;
+                pdb = ssm.setMapping(sequence[pe], chains[pe],
+                        pdbentry[pe].getFile(), protocol);
 
               }
 
@@ -699,37 +1084,46 @@ public abstract class JalviewJmolBinding implements StructureListener,
               notifyLoaded = true;
             }
           }
-          if (!foundEntry && associateNewStructs)
-          {
-            // 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
-            // if properly registered then notifyLoaded=true;
-          }
+        }
+        if (!foundEntry && associateNewStructs)
+        {
+          // 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
+          // if properly registered then
+          notifyLoaded = true;
+
         }
       }
     }
     // FILE LOADED OK
     // so finally, update the jmol bits and pieces
-    jmolpopup.updateComputedMenus();
-    viewer
-            .evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
+    if (jmolpopup != null)
+    {
+      jmolpopup.updateComputedMenus();
+    }
+    if (!isLoadingFromArchive())
+    {
+      viewer.evalStringQuiet("model 0; select backbone;restrict;cartoon;wireframe off;spacefill off");
+    }
+    setLoadingFromArchive(false);
     // register ourselves as a listener and notify the gui that it needs to
     // update itself.
     ssm.addStructureViewerListener(this);
     if (notifyLoaded)
     {
-      updateUI();
+      FeatureRenderer fr = getFeatureRenderer();
+      if (fr != null)
+      {
+        fr.featuresAdded();
+      }
+      refreshGUI();
     }
-
   }
 
   public void notifyNewPickingModeMeasurement(int iatom, String strMeasure)
@@ -737,9 +1131,8 @@ public abstract class JalviewJmolBinding implements StructureListener,
     notifyAtomPicked(iatom, strMeasure, null);
   }
 
-  public void notifyScriptTermination(String strStatus, int msWalltime)
-  {
-  }
+  public abstract void notifyScriptTermination(String strStatus,
+          int msWalltime);
 
   /**
    * display a message echoed from the jmol viewer
@@ -782,7 +1175,7 @@ public abstract class JalviewJmolBinding implements StructureListener,
     int index;
     Color col;
     jmolHistory(false);
-
+    // TODO: Switch between nucleotide or aa selection expressions
     Enumeration en = ResidueProperties.aa3Hash.keys();
     StringBuffer command = new StringBuffer("select *;color white;");
     while (en.hasMoreElements())
@@ -798,7 +1191,7 @@ public abstract class JalviewJmolBinding implements StructureListener,
               + col.getGreen() + "," + col.getBlue() + "];");
     }
 
-    viewer.evalStringQuiet(command.toString());
+    evalStateCommand(command.toString());
     jmolHistory(true);
   }
 
@@ -819,6 +1212,43 @@ public abstract class JalviewJmolBinding implements StructureListener,
    * state change. this could be because structures were loaded, or because an
    * error has occured.
    */
-  abstract void updateUI();
+  public abstract void refreshGUI();
 
+  /**
+   * @param renderPanel
+   * @param jmolfileio
+   *          - when true will initialise jmol's file IO system (should be false
+   *          in applet context)
+   * @param htmlName
+   * @param documentBase
+   * @param codeBase
+   * @param commandOptions
+   */
+  public void allocateViewer(Component renderPanel, boolean jmolfileio,
+          String htmlName, URL documentBase, URL codeBase,
+          String commandOptions)
+  {
+    viewer = JmolViewer.allocateViewer(renderPanel,
+            (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
+                    + ((Object) this).toString(), documentBase, codeBase,
+            commandOptions, this);
+  }
+
+  public void setLoadingFromArchive(boolean loadingFromArchive)
+  {
+    this.loadingFromArchive = loadingFromArchive;
+  }
+
+  public boolean isLoadingFromArchive()
+  {
+    return loadingFromArchive;
+  }
+
+  public void setBackgroundColour(java.awt.Color col)
+  {
+    jmolHistory(false);
+    viewer.evalStringQuiet("background [" + col.getRed() + ","
+            + col.getGreen() + "," + col.getBlue() + "];");
+    jmolHistory(true);
+  }
 }