Merge branch 'develop' into features/JAL-2446NCList
[jalview.git] / src / jalview / appletgui / SeqPanel.java
index ab6dd9a..c57f88a 100644 (file)
@@ -54,7 +54,9 @@ import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
+import java.util.Collections;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Vector;
 
 public class SeqPanel extends Panel implements MouseMotionListener,
@@ -564,8 +566,14 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         av.setSelectionGroup(null);
       }
 
+      int column = findRes(evt);
+      boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
       List<SequenceFeature> features = findFeaturesAtRes(sequence,
-              sequence.findPosition(findRes(evt)));
+              sequence.findPosition(column));
+      if (isGapped)
+      {
+        removeAdjacentFeatures(features, column + 1, sequence);
+      }
 
       if (!features.isEmpty())
       {
@@ -573,11 +581,8 @@ public class SeqPanel extends Panel implements MouseMotionListener,
         highlight.addResult(sequence, features.get(0).getBegin(), features
                 .get(0).getEnd());
         seqCanvas.highlightSearchResults(highlight);
-        SequenceFeature[] featuresArray = features
-                .toArray(new SequenceFeature[features.size()]);
         seqCanvas.getFeatureRenderer().amendFeatures(
-                new SequenceI[] { sequence }, featuresArray, false, ap);
-
+                Collections.singletonList(sequence), features, false, ap);
         seqCanvas.highlightSearchResults(null);
       }
     }
@@ -802,9 +807,11 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
 
     final char ch = sequence.getCharAt(column);
-    int respos = Comparison.isGap(ch) ? -1 : sequence.findPosition(column);
+    boolean isGapped = Comparison.isGap(ch);
+    // find residue at column (or nearest if at a gap)
+    int respos = sequence.findPosition(column);
 
-    if (ssm != null && respos != -1)
+    if (ssm != null && !isGapped)
     {
       mouseOverSequence(sequence, column, respos);
     }
@@ -813,30 +820,21 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     text.append("Sequence ").append(Integer.toString(seq + 1))
             .append(" ID: ").append(sequence.getName());
 
-    String obj = null;
-    if (respos != -1)
+    if (!isGapped)
     {
       if (av.getAlignment().isNucleotide())
       {
-        obj = ResidueProperties.nucleotideName.get(ch);
-        if (obj != null)
-        {
-          text.append(" Nucleotide: ").append(obj);
-        }
+        String base = ResidueProperties.nucleotideName.get(ch);
+        text.append(" Nucleotide: ").append(base == null ? ch : base);
       }
       else
       {
-        obj = (ch == 'x' || ch == 'X') ? "X" : ResidueProperties.aa2Triplet
+        String residue = (ch == 'x' || ch == 'X') ? "X"
+                : ResidueProperties.aa2Triplet
                 .get(String.valueOf(ch));
-        if (obj != null)
-        {
-          text.append(" Residue: ").append(obj);
-        }
-      }
-      if (obj != null)
-      {
-        text.append(" (").append(Integer.toString(respos)).append(")");
+        text.append(" Residue: ").append(residue == null ? ch : residue);
       }
+      text.append(" (").append(Integer.toString(respos)).append(")");
     }
 
     ap.alignFrame.statusBar.setText(text.toString());
@@ -864,12 +862,17 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     }
 
     /*
-     * add feature details to tooltip if over one or more features
+     * add feature details to tooltip, including any that straddle
+     * a gapped position
      */
-    if (respos != -1)
+    if (av.isShowSequenceFeatures())
     {
       List<SequenceFeature> allFeatures = findFeaturesAtRes(sequence,
               respos);
+      if (isGapped)
+      {
+        removeAdjacentFeatures(allFeatures, column + 1, sequence);
+      }
       for (SequenceFeature sf : allFeatures)
       {
         tooltipText.append(sf.getType() + " " + sf.begin + ":" + sf.end);
@@ -906,6 +909,32 @@ public class SeqPanel extends Panel implements MouseMotionListener,
     return seqCanvas.getFeatureRenderer().findFeaturesAtRes(sequence, res);
   }
 
+  /**
+   * Removes from the list of features any that start after, or end before, the
+   * given column position. This allows us to retain only those features
+   * adjacent to a gapped position that straddle the position.
+   * 
+   * @param features
+   * @param column
+   *          alignment column (1..)
+   * @param sequence
+   */
+  protected void removeAdjacentFeatures(List<SequenceFeature> features,
+          int column, SequenceI sequence)
+  {
+    // TODO should this be an AlignViewController method (shared by gui)?
+    ListIterator<SequenceFeature> it = features.listIterator();
+    while (it.hasNext())
+    {
+      SequenceFeature sf = it.next();
+      if (sequence.findIndex(sf.getBegin()) > column
+              || sequence.findIndex(sf.getEnd()) < column)
+      {
+        it.remove();
+      }
+    }
+  }
+
   Tooltip tooltip;
 
   /**
@@ -1433,9 +1462,8 @@ public class SeqPanel extends Panel implements MouseMotionListener,
               sequence.findPosition(res));
 
       Vector<String> links = null;
-      for (int i = 0; i < allFeatures.size(); i++)
+      for (SequenceFeature sf : allFeatures)
       {
-        SequenceFeature sf = allFeatures.get(i);
         if (sf.links != null)
         {
           if (links == null)