JAL-2295 (unoptimised) write Jalview features as Chimera attributes
[jalview.git] / src / jalview / ext / rbvi / chimera / JalviewChimeraBinding.java
index 1ce0d2b..2534421 100644 (file)
@@ -27,14 +27,17 @@ import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
 import jalview.httpserver.AbstractRequestHandler;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ResidueProperties;
 import jalview.structure.AtomSpec;
+import jalview.structure.StructureMapping;
 import jalview.structure.StructureMappingcommandSet;
 import jalview.structure.StructureSelectionManager;
 import jalview.structures.models.AAStructureBindingModel;
+import jalview.util.Comparison;
 import jalview.util.MessageManager;
 
 import java.awt.Color;
@@ -101,17 +104,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
 
   private String lastCommand;
 
-  private boolean loadedInline;
-
-  /**
-   * current set of model filenames loaded
-   */
-  String[] modelFileNames = null;
-
   String lastHighlightCommand;
 
-  private List<String> lastReply;
-
   /*
    * incremented every time a load notification is successfully handled -
    * lightweight mechanism for other threads to detect when they can start
@@ -617,7 +611,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     if (lastCommand == null || !lastCommand.equals(command))
     {
       // trim command or it may never find a match in the replyLog!!
-      lastReply = viewer.sendChimeraCommand(command.trim(), logResponse);
+      List<String> lastReply = viewer.sendChimeraCommand(command.trim(),
+              logResponse);
       if (logResponse && debug)
       {
         log("Response from command ('" + command + "') was:\n" + lastReply);
@@ -715,17 +710,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   // End StructureListener
   // //////////////////////////
 
-  public Color getColour(int atomIndex, int pdbResNum, String chain,
-          String pdbfile)
-  {
-    if (getModelNum(pdbfile) < 0)
-    {
-      return null;
-    }
-    log("get model / residue colour attribute unimplemented");
-    return null;
-  }
-
   /**
    * returns the current featureRenderer that should be used to colour the
    * structures
@@ -795,15 +779,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
   }
 
   /**
-   * map from string to applet
-   */
-  public Map getRegistryInfo()
-  {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  /**
    * returns the current sequenceRenderer that should be used to colour the
    * structures
    * 
@@ -815,20 +790,18 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
           AlignmentViewPanel alignment);
 
   /**
-   * Construct and send a command to highlight zero, one or more atoms.
-   * 
-   * <pre>
-   * Done by generating a command like (to 'highlight' positions 44 and 46)
-   *   show #0:44,46.C
-   * </pre>
+   * Construct and send a command to highlight zero, one or more atoms. We do
+   * this by sending an "rlabel" command to show the residue label at that
+   * position.
    */
   @Override
   public void highlightAtoms(List<AtomSpec> atoms)
   {
-    if (atoms == null)
+    if (atoms == null || atoms.size() == 0)
     {
       return;
     }
+
     StringBuilder cmd = new StringBuilder(128);
     boolean first = true;
     boolean found = false;
@@ -843,7 +816,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       {
         if (first)
         {
-          cmd.append("show #").append(cms.get(0).getModelNumber())
+          cmd.append("rlabel #").append(cms.get(0).getModelNumber())
                   .append(":");
         }
         else
@@ -851,7 +824,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
           cmd.append(",");
         }
         first = false;
-        cmd.append(cms.get(0).getModelNumber()).append(":");
         cmd.append(pdbResNum);
         if (!chain.equals(" "))
         {
@@ -863,19 +835,24 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
     String command = cmd.toString();
 
     /*
-     * Avoid repeated commands for the same residue
+     * avoid repeated commands for the same residue
      */
     if (command.equals(lastHighlightCommand))
     {
       return;
     }
 
-    viewerCommandHistory(false);
+    /*
+     * unshow the label for the previous residue
+     */
+    if (lastHighlightCommand != null)
+    {
+      viewer.sendChimeraCommand("~" + lastHighlightCommand, false);
+    }
     if (found)
     {
-      viewer.sendChimeraCommand(command.toString(), false);
+      viewer.sendChimeraCommand(command, false);
     }
-    viewerCommandHistory(true);
     this.lastHighlightCommand = command;
   }
 
@@ -1151,4 +1128,87 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel
       sm.highlightStructure(this, seq, positions);
     }
   }
+
+  /**
+   * Constructs and send commands to Chimera to set attributes on residues for
+   * features visible in Jalview
+   * 
+   * @param avp
+   */
+  public void sendFeaturesToChimera(AlignmentViewPanel avp)
+  {
+    // TODO send a command per feature with the range of residues it applies to
+    AlignmentI alignment = avp.getAlignment();
+    FeatureRenderer fr = getFeatureRenderer(avp);
+
+    /*
+     * fr is null if feature display is turned off
+     */
+    if (fr == null)
+    {
+      return;
+    }
+
+    String[] files = getPdbFile();
+    if (files == null)
+    {
+      return;
+    }
+    for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
+    {
+      StructureMapping[] mapping = getSsm().getMapping(files[pdbfnum]);
+
+      if (mapping == null || mapping.length < 1)
+      {
+        continue;
+      }
+
+      int lastPos = -1;
+      for (int seqNo = 0; seqNo < getSequence()[pdbfnum].length; seqNo++)
+      {
+        for (int m = 0; m < mapping.length; m++)
+        {
+          final SequenceI seq = getSequence()[pdbfnum][seqNo];
+          int sp = alignment.findIndex(seq);
+          if (mapping[m].getSequence() == seq && sp > -1)
+          {
+            SequenceI asp = alignment.getSequenceAt(sp);
+            for (int r = 0; r < asp.getLength(); r++)
+            {
+              // no mapping to gaps in sequence
+              if (Comparison.isGap(asp.getCharAt(r)))
+              {
+                continue;
+              }
+              int residuePos = asp.findPosition(r);
+              int pos = mapping[m].getPDBResNum(residuePos);
+
+              if (pos < 1 || pos == lastPos)
+              {
+                continue;
+              }
+              final String chain = mapping[m].getChain();
+              List<SequenceFeature> features = fr.findFeaturesAtRes(asp,
+                      residuePos);
+              for (SequenceFeature feature : features)
+              {
+                String desc = feature.getDescription();
+                float score = feature.getScore();
+                if (score != 0 && score != Float.NaN)
+                {
+                  desc = Float.toString(score);
+                }
+                String attName = "jv:"
+                        + feature.getType().replace(" ", "_");
+                String cmd = "setattr r " + attName + " \""
+                        + desc + "\" #" + pdbfnum + ":" + pos + "." + chain;
+                System.out.println(cmd);
+                sendAsynchronousCommand(cmd, null);
+              }
+            }
+          }
+        }
+      }
+    }
+  }
 }