revised sequence/structure binding so one structure associated with x-seuqenceI's...
authorjprocter <Jim Procter>
Fri, 27 Aug 2010 11:35:14 +0000 (11:35 +0000)
committerjprocter <Jim Procter>
Fri, 27 Aug 2010 11:35:14 +0000 (11:35 +0000)
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/gui/AppJmol.java
src/jalview/gui/AppJmolBinding.java
src/jalview/gui/Jalview2XML.java
src/jalview/jbgui/GStructureViewer.java

index c2eceed..8831bd6 100644 (file)
@@ -77,7 +77,10 @@ public abstract class JalviewJmolBinding implements StructureListener,
 
   public Vector chainNames;
 
-  String[] chains;
+  /**
+   * array of target chains for seuqences - tied to pdbentry and sequence[]
+   */
+  protected String[][] chains;
 
   boolean colourBySequence = true;
 
@@ -113,20 +116,26 @@ public abstract class JalviewJmolBinding implements StructureListener,
 
   StringBuffer resetLastRes = new StringBuffer();
 
-  public SequenceI[] sequence;
+  /**
+   * sequences mapped to each pdbentry
+   */
+  public SequenceI[][] sequence;
 
   StructureSelectionManager ssm;
 
   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 = seq;
+    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(),
@@ -156,7 +165,7 @@ public abstract class JalviewJmolBinding implements StructureListener,
     {
       return ("Jalview Jmol Window");
     }
-    StringBuffer title = new StringBuffer(sequence[0].getName() + ":"
+    StringBuffer title = new StringBuffer(sequence[0][0].getName() + ":"
             + pdbentry[0].getId());
 
     if (pdbentry[0].getProperty() != null)
@@ -236,12 +245,55 @@ public abstract class JalviewJmolBinding implements StructureListener,
    */
   public void superposeStructures(AlignmentI alignment)
   {
-    String[] files = getPdbFile();
+    superposeStructures(alignment, -1, null);
+  }
 
-    StringBuffer command = new StringBuffer();
+  /**
+   * 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()];
-    String commonpositions[][] = new String[files.length][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]);
@@ -250,60 +302,156 @@ 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)
           {
+            if (refStructure == -1)
+            {
+              refStructure = pdbfnum;
+            }
             SequenceI asp = alignment.getSequenceAt(sp);
-            for (int r = 0; r < asp.getLength(); r++)
+            for (int r = 0; r < matched.length; r++)
             {
-              // no mapping to gaps in sequence
+              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)))
               {
-                matched[r] = false; // exclude from common set
+                // no mapping to gaps in sequence
                 continue;
               }
-              int pos = mapping[m].getPDBResNum(asp.findPosition(r));
+              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;
-
-              commonpositions[m][r] = (mapping[m].getChain() != " " ? ":"
-                      + mapping[m].getChain() : "")
-                      + "/" + (pdbfnum + 1) + ".1";
+              // 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;
           }
         }
       }
     }
-    command.append("select ");
-    // form the matched pair selection strings
-    String sep = "";
-    for (int r = 0; r < matched.length; r++)
+    StringBuffer selcom[] = new StringBuffer[files.length];
+    // generate select statements to select regions to superimpose structures
     {
-      if (matched[r])
+      for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
       {
-        command.append(sep);
-        command.append("(");
-        for (int s = 0; s < commonpositions.length; s++)
+        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 (s > 0)
+          if (matched[r])
           {
-            command.append(" | ");
+
+            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);
           }
-          command.append(commonpositions[s][r]);
         }
-        command.append(")");
-        sep = " | ";
+        // 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)
@@ -349,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++)
@@ -371,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() : "")
                       + "/"
@@ -896,7 +1044,7 @@ public abstract class JalviewJmolBinding implements StructureListener,
               if (loadedInline)
               {
                 // TODO: replace with getData ?
-                pdb = ssm.setMapping(sequence, chains,
+                pdb = ssm.setMapping(sequence[pe], chains[pe],
                         pdbentry[pe].getFile(), AppletFormatAdapter.PASTE);
                 pdbentry[pe].setFile("INLINE" + pdb.id);
               }
@@ -921,7 +1069,7 @@ public abstract class JalviewJmolBinding implements StructureListener,
                 {
                 }
                 ;
-                pdb = ssm.setMapping(sequence, chains,
+                pdb = ssm.setMapping(sequence[pe], chains[pe],
                         pdbentry[pe].getFile(), protocol);
 
               }
@@ -1066,21 +1214,23 @@ public abstract class JalviewJmolBinding implements StructureListener,
    */
   public abstract void refreshGUI();
 
-
   /**
    * @param renderPanel
-   * @param jmolfileio - when true will initialise jmol's file IO system (should be false in applet context)
+   * @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)
+  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,
+            (jmolfileio ? new SmarterJmolAdapter() : null), htmlName
+                    + ((Object) this).toString(), documentBase, codeBase,
             commandOptions, this);
   }
 
index 6312cb1..df4efd9 100644 (file)
@@ -73,7 +73,7 @@ public class AppJmol extends GStructureViewer implements Runnable,
     // / TODO: check if protocol is needed to be set, and if chains are
     // autodiscovered.
     jmb = new AppJmolBinding(this, new PDBEntry[]
-    { pdbentry }, seq, null, null);
+    { pdbentry }, new SequenceI[][] { seq }, null, null);
 
     jmb.setLoadingFromArchive(true);
     this.ap = ap;
@@ -141,7 +141,7 @@ public class AppJmol extends GStructureViewer implements Runnable,
             {
               if (topJmol.jmb.pdbentry[pe].getFile().equals(alreadyMapped))
               {
-                topJmol.jmb.addSequence(seq);
+                topJmol.jmb.addSequence(pe, seq);
                 break;
               }
             }
@@ -152,9 +152,33 @@ public class AppJmol extends GStructureViewer implements Runnable,
       }
     }
     // /////////////////////////////////
+    // Check if there are other Jmol views involving this alignment
+    // and prompt user about adding this molecule to one of them
+    Vector existingViews = getJmolsFor(ap);
+    if (existingViews.size()>0)
+    {
+      Enumeration jm = existingViews.elements();
+      while (jm.hasMoreElements()) {
+        AppJmol topJmol = (AppJmol) jm.nextElement();
+        // TODO: highlight topJmol in view somehow
+        int option = JOptionPane
+        .showInternalConfirmDialog(
+              Desktop.desktop, "Do you want to add "+
+              pdbentry.getId()+" to the view called\n'"+topJmol.getTitle()
+                      + "'\n",
+              "Align to existing structure view"
+                      , JOptionPane.YES_NO_OPTION);
+        if (option == JOptionPane.YES_OPTION)
+        {
+          topJmol.jmb.addStructure(pdbentry, seq, chains,true);
+          return;
+        }
+      }
+    }
+    // /////////////////////////////////
 
     jmb = new AppJmolBinding(this, new PDBEntry[]
-    { pdbentry }, seq, null, null);
+    { pdbentry }, new SequenceI[][]{seq}, null, null);
     this.ap = ap;
     setSize(400, 400); // probably should be a configurable/dynamic default here
 
@@ -178,6 +202,27 @@ public class AppJmol extends GStructureViewer implements Runnable,
 
   }
 
+  private Vector getJmolsFor(AlignmentPanel ap2)
+  {
+    Vector otherJmols= new Vector();
+    // Now this AppJmol is mapped to new sequences. We must add them to
+    // the exisiting array
+    JInternalFrame[] frames = Desktop.instance.getAllFrames();
+
+    for (int i = 0; i < frames.length; i++)
+    {
+      if (frames[i] instanceof AppJmol)
+      {
+        AppJmol topJmol = ((AppJmol) frames[i]);
+        if (topJmol.ap==ap2)
+        {
+          otherJmols.addElement(topJmol);
+        }
+      }
+    }
+    return otherJmols;
+  }
+
   void initJmol(String command)
   {
     jmb.setFinishedInit(false);
@@ -617,8 +662,27 @@ public class AppJmol extends GStructureViewer implements Runnable,
     }
     setChainMenuItems(jmb.chainNames);
     jmb.colourBySequence(ap.av.getShowSequenceFeatures(), ap.av.alignment);
-
+    
     this.setTitle(jmb.getViewerTitle());
+    if (jmb.getPdbFile().length>1 && jmb.sequence.length>1) {
+       jmolActionMenu.setVisible(true);
+    }
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.jbgui.GStructureViewer#alignStructs_actionPerformed(java.awt.event.ActionEvent)
+   */
+  @Override
+  protected void alignStructs_actionPerformed(ActionEvent actionEvent)
+  {
+    
+    try {
+      jmb.superposeStructures(ap.av.getAlignment(), -1, ap.av.getColumnSelection());
+    } catch (Exception e)
+    {
+      Cache.log.info("Couldn't align structures in alignframe "+ap.alignFrame.getTitle(),e);
+      
+    }
   }
 
   public void setJalviewColourScheme(ColourSchemeI ucs)
index 39d198d..d6535e3 100644 (file)
@@ -21,12 +21,14 @@ class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
   private AppJmol appJmolWindow;
 
   public AppJmolBinding(AppJmol appJmol, PDBEntry[] pdbentry,
-          SequenceI[] seq, String[] chains, String protocol)
+          SequenceI[][] sequenceIs, String[][] chains, String protocol)
   {
-    super(pdbentry, seq, chains, protocol);
+    super(pdbentry, sequenceIs, chains, protocol);
     appJmolWindow = appJmol;
   }
-  FeatureRenderer fr=null;
+
+  FeatureRenderer fr = null;
+
   @Override
   public jalview.api.FeatureRenderer getFeatureRenderer()
   {
@@ -38,7 +40,7 @@ class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
       }
 
       fr.transferSettings(appJmolWindow.ap.seqPanel.seqCanvas
-                      .getFeatureRenderer());
+              .getFeatureRenderer());
     }
 
     return fr;
@@ -60,10 +62,9 @@ class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
 
   public void sendConsoleMessage(String strStatus)
   {
-    if (appJmolWindow.scriptWindow!=null && strStatus != null
-            )
-      //      && !strStatus.equals("Script completed"))
-      // should we squash the script completed string ?
+    if (appJmolWindow.scriptWindow != null && strStatus != null)
+    // && !strStatus.equals("Script completed"))
+    // should we squash the script completed string ?
     {
       appJmolWindow.scriptWindow.sendConsoleMessage(strStatus);
     }
@@ -72,9 +73,11 @@ class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
   @Override
   public void showUrl(String url, String target)
   {
-    try {
+    try
+    {
       jalview.util.BrowserLauncher.openURL(url);
-    } catch (Exception e) {
+    } catch (Exception e)
+    {
       Cache.log.error("Failed to launch Jmol-associated url " + url, e);
       // TODO: 2.6 : warn user if browser was not configured.
     }
@@ -90,21 +93,22 @@ class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
   public void updateColours(Object source)
   {
     AlignmentPanel ap = (AlignmentPanel) source;
-    if (appJmolWindow.ap.alignFrame.getCurrentView()!=ap.av)
+    if (appJmolWindow.ap.alignFrame.getCurrentView() != ap.av)
       return;
-    
+
     colourBySequence(ap.av.getShowSequenceFeatures(), ap.av.alignment);
   }
 
   public void notifyScriptTermination(String strStatus, int msWalltime)
   {
     if (appJmolWindow.scriptWindow != null)
-      appJmolWindow.scriptWindow.notifyScriptTermination(strStatus, msWalltime);
+      appJmolWindow.scriptWindow.notifyScriptTermination(strStatus,
+              msWalltime);
   }
 
   public void showUrl(String url)
   {
-    showUrl(url,"jmol");
+    showUrl(url, "jmol");
   }
 
   public void newJmolPopup(boolean translateLocale, String menuName,
@@ -114,30 +118,228 @@ class AppJmolBinding extends jalview.ext.jmol.JalviewJmolBinding
     jmolpopup = JmolPopup.newJmolPopup(viewer, translateLocale, menuName,
             asPopup);
   }
-  public synchronized void addSequence(SequenceI[] seq)
+
+  /**
+   * add structures and any known sequence associations
+   * 
+   * @returns the pdb entries added to the current set.
+   */
+  private PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
+          SequenceI[][] seq, String[][] chns)
   {
+    int pe = -1;
     Vector v = new Vector();
-    for (int i = 0; i < sequence.length; i++)
-      v.addElement(sequence[i]);
+    Vector rtn = new Vector();
+    for (int i = 0; i < pdbentry.length; i++)
+    {
+      v.addElement(pdbentry[i]);
+    }
+    for (int i = 0; i < pdbe.length; i++)
+    {
+      int r = v.indexOf(pdbe[i]);
+      if (r == -1 || r >= pdbentry.length)
+      {
+        rtn.addElement(new int[]
+        { v.size(), i });
+        v.addElement(pdbe[i]);
+      }
+      else
+      {
+        // just make sure the sequence/chain entries are all up to date
+        addSequenceAndChain(r, seq[i], chns[i]);
+      }
+    }
+    pdbe = new PDBEntry[v.size()];
+    v.copyInto(pdbe);
+    pdbentry = pdbe;
+    if (rtn.size() > 0)
+    {
+      // expand the tied seuqence[] and string[] arrays
+      SequenceI[][] sqs = new SequenceI[pdbentry.length][];
+      String[][] sch = new String[pdbentry.length][];
+      System.arraycopy(sequence, 0, sqs, 0, sequence.length);
+      System.arraycopy(chains, 0, sch, 0, this.chains.length);
+      sequence = sqs;
+      chains = sch;
+      pdbe = new PDBEntry[rtn.size()];
+      for (int r = 0; r < pdbe.length; r++)
+      {
+        int[] stri = ((int[]) rtn.elementAt(r));
+        // record the pdb file as a new addition
+        pdbe[r] = pdbentry[stri[0]];
+        // and add the new sequence/chain entries
+        addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
+      }
+    }
+    else
+    {
+      pdbe = null;
+    }
+    return pdbe;
+  }
 
-    for (int i = 0; i < seq.length; i++)
-      if (!v.contains(seq[i]))
-        v.addElement(seq[i]);
+  void addSequence(int pe, SequenceI[] seq)
+  {
+    // add sequences to the pe'th pdbentry's seuqence set.
+    addSequenceAndChain(pe, seq, null);
+  }
 
-    SequenceI[] tmp = new SequenceI[v.size()];
-    v.copyInto(tmp);
-    sequence = tmp;
+  private void addSequenceAndChain(int pe, SequenceI[] seq, String[] tchain)
+  {
+    if (pe < 0 || pe >= pdbentry.length)
+    {
+      throw new Error(
+              "Implementation error - no corresponding pdbentry (for index "
+                      + pe + ") to add sequences mappings to");
+    }
+    final String nullChain = "TheNullChain";
+    Vector s = new Vector();
+    Vector c = new Vector();
+    if (chains == null)
+    {
+      chains = new String[pdbentry.length][];
+    }
+    if (sequence[pe] != null)
+    {
+      for (int i = 0; i < sequence[pe].length; i++)
+      {
+        s.addElement(sequence[pe][i]);
+        if (chains[pe] != null)
+        {
+          if (i < chains[pe].length)
+          {
+            c.addElement(chains[pe][i]);
+          }
+          else
+          {
+            c.addElement(nullChain);
+          }
+        }
+        else
+        {
+          if (tchain != null && tchain.length > 0)
+          {
+            c.addElement(nullChain);
+          }
+        }
+      }
+    }
+    for (int i = 0; i < seq.length; i++)
+    {
+      if (!s.contains(seq[i]))
+      {
+        s.addElement(seq[i]);
+        if (tchain != null && i < tchain.length)
+        {
+          c.addElement(tchain[i] == null ? nullChain : tchain[i]);
+        }
+      }
+    }
+    SequenceI[] tmp = new SequenceI[s.size()];
+    s.copyInto(tmp);
+    sequence[pe] = tmp;
+    if (c.size() > 0)
+    {
+      String[] tch = new String[c.size()];
+      c.copyInto(tch);
+      for (int i = 0; i < tch.length; i++)
+      {
+        if (tch[i] == nullChain)
+        {
+          tch[i] = null;
+        }
+      }
+      chains[pe] = tch;
+    }
+    else
+    {
+      chains[pe] = null;
+    }
   }
 
   public void selectionChanged(BitSet arg0)
   {
     // TODO Auto-generated method stub
-    
+
   }
 
   public void refreshPdbEntries()
   {
     // TODO Auto-generated method stub
-    
+
   }
+
+  /**
+   * add another pdb entry into the view, with associated sequences and chains
+   * 
+   * @param pdbentry
+   * @param seq
+   * @param chains
+   * @param align
+   *          if true, new structure(s) will be align using associated alignment
+   */
+  public synchronized void addStructure(PDBEntry pdbentry, SequenceI[] seq,
+          String[] chains, final boolean align)
+  {
+    PDBEntry[] pe = addSequenceAndChain(new PDBEntry[]
+    { pdbentry }, new SequenceI[][]
+    { seq }, new String[][]
+    { chains });
+    if (pe != null)
+    {
+      StringBuffer cmd = new StringBuffer();
+      cmd.append("load APPEND");
+      for (int p = 0; p < pe.length; p++)
+      {
+        cmd.append(" \"");
+        cmd.append(pe[p].getFile());
+        cmd.append("\"");
+      }
+      cmd.append("\n");
+      final String command = cmd.toString();
+      cmd = null;
+      new Thread(new Runnable()
+      {
+        public void run()
+        {
+          evalStateCommand(command);
+          if (align)
+          {
+            // may need to wait around until script has finished
+            while (viewer.isScriptExecuting())
+            {
+              try
+              {
+                Thread.sleep(20);
+              } catch (Exception e)
+              {
+              }
+              ;
+            }
+            superposeStructures(appJmolWindow.ap.av.getAlignment(), -1, null);
+          }
+        }
+      }).start();
+    }
+  }
+
+  /**
+   * add the given sequences to the mapping scope for the given pdb file handle
+   * 
+   * @param pdbFile
+   *          - pdbFile identifier
+   * @param seq
+   *          - set of sequences it can be mapped to
+   */
+  public void addSequenceForStructFile(String pdbFile, SequenceI[] seq)
+  {
+    for (int pe = 0; pe < pdbentry.length; pe++)
+    {
+      if (pdbentry[pe].getFile().equals(pdbFile))
+      {
+        addSequence(pe, seq);
+      }
+    }
+  }
+
 }
\ No newline at end of file
index fd93d7f..c9e8bdd 100755 (executable)
@@ -604,7 +604,8 @@ public class Jalview2XML
               }
               for (int s = 0; s < jmol.jmb.sequence.length; s++)
               {
-                if (jal.findIndex(jmol.jmb.sequence[s]) > -1)
+                for (int smap=0;smap<jmol.jmb.sequence[s].length; smap++)
+                if (jal.findIndex(jmol.jmb.sequence[s][smap]) > -1)
                 {
                   pdb.addStructureState(state);
                 }
@@ -2587,8 +2588,8 @@ public class Jalview2XML
                 StructureSelectionManager.getStructureSelectionManager()
                         .setMapping(seq, null, pdbFile,
                                 jalview.io.AppletFormatAdapter.FILE);
-
-                ((AppJmol) comp).jmb.addSequence(seq);
+                
+                ((AppJmol) comp).jmb.addSequenceForStructFile(pdbFile, seq);
               }
             }
           }
index f7fa6db..bfaee67 100644 (file)
@@ -181,9 +181,20 @@ public class GStructureViewer extends JInternalFrame
         jmolHelp_actionPerformed(actionEvent);
       }
     });
+    alignStructs.setText("Align structures");
+    alignStructs.addActionListener(new ActionListener()
+    {
+      public void actionPerformed(ActionEvent actionEvent)
+      {
+        alignStructs_actionPerformed(actionEvent);
+      }
+    });
+    jmolActionMenu.setText("Jmol");
     menuBar.add(fileMenu);
     menuBar.add(viewMenu);
     menuBar.add(colourMenu);
+    menuBar.add(jmolActionMenu);
+    jmolActionMenu.setVisible(false);
     menuBar.add(helpMenu);
     fileMenu.add(savemenu);
     fileMenu.add(viewMapping);
@@ -218,6 +229,11 @@ public class GStructureViewer extends JInternalFrame
     colourButtons.add(userColour);
     
     helpMenu.add(jmolHelp);
+    jmolActionMenu.add(alignStructs);
+  }
+
+  protected void alignStructs_actionPerformed(ActionEvent actionEvent)
+  {
   }
 
   JMenuBar menuBar = new JMenuBar();
@@ -242,6 +258,10 @@ public class GStructureViewer extends JInternalFrame
 
   JMenu colourMenu = new JMenu();
 
+  protected JMenu jmolActionMenu = new JMenu();
+
+  JMenuItem alignStructs = new JMenuItem();
+
   JMenuItem backGround = new JMenuItem();
 
   protected JRadioButtonMenuItem seqColour = new JRadioButtonMenuItem();