JAL-3187 derived peptide variants tweaks and tests
[jalview.git] / src / jalview / gui / SeqPanel.java
index 11ee700..75bf0cc 100644 (file)
@@ -29,6 +29,7 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.MappedFeatures;
 import jalview.datamodel.SearchResultMatchI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResultsI;
@@ -50,6 +51,7 @@ import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
+import jalview.viewmodel.seqfeatures.FeatureRendererModel;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
@@ -61,6 +63,7 @@ import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -255,11 +258,6 @@ public class SeqPanel extends JPanel
 
   int wrappedBlock = -1;
 
-  MousePos findMousePosition(MouseEvent evt)
-  {
-    return findMousePosition(evt, null);
-  }
-
   /**
    * Computes the column and sequence row (and possibly annotation row when in
    * wrapped mode) for the given mouse position
@@ -267,22 +265,15 @@ public class SeqPanel extends JPanel
    * @param evt
    * @return
    */
-  MousePos findMousePosition(MouseEvent evt, String debug)
+  MousePos findMousePosition(MouseEvent evt)
   {
-    int col = findColumn(evt, debug);
+    int col = findColumn(evt);
     int seqIndex = -1;
     int annIndex = -1;
     int y = evt.getY();
 
     int charHeight = av.getCharHeight();
     int alignmentHeight = av.getAlignment().getHeight();
-    if (debug != null)
-    {
-      System.out.println(String.format(
-              "%s: charHeight %d alHeight %d canvasWidth %d canvasHeight %d",
-              debug, charHeight, alignmentHeight, seqCanvas.getWidth(),
-              seqCanvas.getHeight()));
-    }
     if (av.getWrapAlignment())
     {
       seqCanvas.calculateWrappedGeometry(seqCanvas.getWidth(),
@@ -343,11 +334,6 @@ public class SeqPanel extends JPanel
    */
   int findColumn(MouseEvent evt)
   {
-    return findColumn(evt, null);
-  }
-
-  int findColumn(MouseEvent evt, String debug)
-  {
     int res = 0;
     int x = evt.getX();
 
@@ -368,12 +354,6 @@ public class SeqPanel extends JPanel
       int y = evt.getY();
       y = Math.max(0, y - hgap);
       x -= seqCanvas.getLabelWidthWest();
-      if (debug != null)
-      {
-        System.out.println(
-                String.format("%s: x %d labelWest %d charWidth %d ", debug,
-                x, seqCanvas.getLabelWidthWest(), charWidth));
-      }
       if (x < 0)
       {
         // mouse is over left scale
@@ -387,10 +367,6 @@ public class SeqPanel extends JPanel
       }
       if (x >= cwidth * charWidth)
       {
-        if (debug != null)
-        {
-          System.out.println(debug + ": cwidth = " + cwidth);
-        }
         // mouse is over right scale
         return -1;
       }
@@ -859,11 +835,11 @@ public class SeqPanel extends JPanel
    * the start of the highlighted region.
    */
   @Override
-  public void highlightSequence(SearchResultsI results)
+  public String highlightSequence(SearchResultsI results)
   {
     if (results == null || results.equals(lastSearchResults))
     {
-      return;
+      return null;
     }
     lastSearchResults = results;
 
@@ -889,6 +865,77 @@ public class SeqPanel extends JPanel
     {
       setStatusMessage(results);
     }
+    return results.isEmpty() ? null : getHighlightInfo(results);
+  }
+
+  /**
+   * temporary hack: answers a message suitable to show on structure hover
+   * label. This is normally null. It is a peptide variation description if
+   * <ul>
+   * <li>results are a single residue in a protein alignment</li>
+   * <li>there is a mapping to a coding sequence (codon)</li>
+   * <li>there are one or more SNP variant features on the codon</li>
+   * </ul>
+   * in which case the answer is of the format (e.g.) "p.Glu388Asp"
+   * 
+   * @param results
+   * @return
+   */
+  private String getHighlightInfo(SearchResultsI results)
+  {
+    /*
+     * ideally, just find mapped CDS (as we don't care about render style here);
+     * for now, go via split frame complement's FeatureRenderer
+     */
+    AlignViewportI complement = ap.getAlignViewport().getCodingComplement();
+    if (complement == null)
+    {
+      return null;
+    }
+    AlignFrame af = Desktop.getAlignFrameFor(complement);
+    FeatureRendererModel fr2 = af.getFeatureRenderer();
+
+    int j = results.getSize();
+    List<String> infos = new ArrayList<>();
+    for (int i = 0; i < j; i++)
+    {
+      SearchResultMatchI match = results.getResults().get(i);
+      int pos = match.getStart();
+      if (pos == match.getEnd())
+      {
+        SequenceI seq = match.getSequence();
+        SequenceI ds = seq.getDatasetSequence() == null ? seq
+                : seq.getDatasetSequence();
+        MappedFeatures mf = fr2
+                .findComplementFeaturesAtResidue(ds, pos);
+        if (mf != null)
+        {
+          for (SequenceFeature sf : mf.features)
+          {
+            String pv = mf.findProteinVariants(sf);
+            if (pv.length() > 0 && !infos.contains(pv))
+            {
+              infos.add(pv);
+            }
+          }
+        }
+      }
+    }
+
+    if (infos.isEmpty())
+    {
+      return null;
+    }
+    StringBuilder sb = new StringBuilder();
+    for (String info : infos)
+    {
+      if (sb.length() > 0)
+      {
+        sb.append("|");
+      }
+      sb.append(info);
+    }
+    return sb.toString();
   }
 
   @Override
@@ -1001,6 +1048,27 @@ public class SeqPanel extends JPanel
               .findFeaturesAtColumn(sequence, column + 1);
       seqARep.appendFeatures(tooltipText, pos, features,
               this.ap.getSeqPanel().seqCanvas.fr);
+
+      /*
+       * add features in CDS/protein complement at the corresponding
+       * position if configured to do so
+       */
+      if (av.isShowComplementFeatures())
+      {
+        if (!Comparison.isGap(sequence.getCharAt(column)))
+        {
+          AlignViewportI complement = ap.getAlignViewport()
+                  .getCodingComplement();
+          AlignFrame af = Desktop.getAlignFrameFor(complement);
+          FeatureRendererModel fr2 = af.getFeatureRenderer();
+          MappedFeatures mf = fr2.findComplementFeaturesAtResidue(sequence,
+                  pos);
+          if (mf != null)
+          {
+            seqARep.appendFeatures(tooltipText, pos, mf, fr2);
+          }
+        }
+      }
     }
     if (tooltipText.length() == 6) // <html>
     {
@@ -2186,11 +2254,11 @@ public class SeqPanel extends JPanel
     final int column = pos.column;
     final int seq = pos.seqIndex;
     SequenceI sequence = av.getAlignment().getSequenceAt(seq);
-    List<SequenceFeature> features = ap.getFeatureRenderer()
-            .findFeaturesAtColumn(sequence, column + 1);
-
-    PopupMenu pop = new PopupMenu(ap, null, features);
-    pop.show(this, evt.getX(), evt.getY());
+    if (sequence != null)
+    {
+      PopupMenu pop = new PopupMenu(ap, sequence, column);
+      pop.show(this, evt.getX(), evt.getY());
+    }
   }
 
   /**