Merge branch 'develop' into features/JAL-2446NCList
[jalview.git] / src / jalview / gui / SeqPanel.java
index 7651eb4..1f3bf67 100644 (file)
@@ -62,7 +62,6 @@ import java.awt.event.MouseWheelListener;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.ListIterator;
 
 import javax.swing.JPanel;
 import javax.swing.SwingUtilities;
@@ -85,6 +84,16 @@ public class SeqPanel extends JPanel implements MouseListener,
   /** DOCUMENT ME!! */
   public AlignmentPanel ap;
 
+  /*
+   * last column position for mouseMoved event
+   */
+  private int lastMouseColumn;
+
+  /*
+   * last sequence offset for mouseMoved event
+   */
+  private int lastMouseSeq;
+
   protected int lastres;
 
   protected int startseq;
@@ -171,6 +180,9 @@ public class SeqPanel extends JPanel implements MouseListener,
       ssm.addStructureViewerListener(this);
       ssm.addSelectionListener(this);
     }
+
+    lastMouseColumn = -1;
+    lastMouseSeq = -1;
   }
 
   int startWrapBlock = -1;
@@ -203,7 +215,7 @@ public class SeqPanel extends JPanel implements MouseListener,
 
       int y = evt.getY();
       y -= hgap;
-      x -= seqCanvas.LABEL_WEST;
+      x -= seqCanvas.labelWidthWest;
 
       int cwidth = seqCanvas.getWrappedCanvasWidth(this.getWidth());
       if (cwidth < 1)
@@ -682,8 +694,10 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
       ap.setToScrollComplementPanel(true);
     }
-    setStatusMessage(results);
-    seqCanvas.highlightSearchResults(results);
+    if (seqCanvas.highlightSearchResults(results))
+    {
+      setStatusMessage(results);
+    }
   }
 
   @Override
@@ -719,8 +733,18 @@ public class SeqPanel extends JPanel implements MouseListener,
     int seq = findSeq(evt);
     if (column < 0 || seq < 0 || seq >= av.getAlignment().getHeight())
     {
+      lastMouseSeq = -1;
+      return;
+    }
+    if (column == lastMouseColumn && seq == lastMouseSeq)
+    {
+      /*
+       * just a pixel move without change of residue
+       */
       return;
     }
+    lastMouseColumn = column;
+    lastMouseSeq = seq;
 
     SequenceI sequence = av.getAlignment().getSequenceAt(seq);
 
@@ -771,11 +795,7 @@ public class SeqPanel extends JPanel implements MouseListener,
     if (av.isShowSequenceFeatures())
     {
       List<SequenceFeature> features = ap.getFeatureRenderer()
-              .findFeaturesAtRes(sequence.getDatasetSequence(), pos);
-      if (isGapped)
-      {
-        removeAdjacentFeatures(features, column + 1, sequence);
-      }
+              .findFeaturesAtColumn(sequence, column + 1);
       seqARep.appendFeatures(tooltipText, pos, features,
               this.ap.getSeqPanel().seqCanvas.fr.getMinMax());
     }
@@ -786,45 +806,13 @@ public class SeqPanel extends JPanel implements MouseListener,
     }
     else
     {
-      if (lastTooltip == null
-              || !lastTooltip.equals(tooltipText.toString()))
-      {
-        String formatedTooltipText = JvSwingUtils.wrapTooltip(true,
-                tooltipText.toString());
-        // String formatedTooltipText = tooltipText.toString();
-        setToolTipText(formatedTooltipText);
-        lastTooltip = tooltipText.toString();
-      }
-
-    }
-
-  }
-
-  /**
-   * 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. Contact features
-   * that 'straddle' the position are also removed, since they are not 'at' the
-   * position.
-   * 
-   * @param features
-   * @param column
-   *          alignment column (1..)
-   * @param sequence
-   */
-  protected void removeAdjacentFeatures(List<SequenceFeature> features,
-          final int column, SequenceI sequence)
-  {
-    // TODO should this be an AlignViewController method (and reused by applet)?
-    ListIterator<SequenceFeature> it = features.listIterator();
-    while (it.hasNext())
-    {
-      SequenceFeature sf = it.next();
-      if (sf.isContactFeature()
-              || sequence.findIndex(sf.getBegin()) > column
-              || sequence.findIndex(sf.getEnd()) < column)
+      String textString = tooltipText.toString();
+      if (lastTooltip == null || !lastTooltip.equals(textString))
       {
-        it.remove();
+        String formattedTooltipText = JvSwingUtils.wrapTooltip(true,
+                textString);
+        setToolTipText(formattedTooltipText);
+        lastTooltip = textString;
       }
     }
   }
@@ -882,19 +870,48 @@ public class SeqPanel extends JPanel implements MouseListener,
    *          aligned sequence object
    * @param column
    *          alignment column
-   * @param seq
+   * @param seqIndex
    *          index of sequence in alignment
    * @return sequence position of residue at column, or adjacent residue if at a
    *         gap
    */
-  int setStatusMessage(SequenceI sequence, final int column, int seq)
+  int setStatusMessage(SequenceI sequence, final int column, int seqIndex)
+  {
+    char sequenceChar = sequence.getCharAt(column);
+    int pos = sequence.findPosition(column);
+    setStatusMessage(sequence, seqIndex, sequenceChar, pos);
+
+    return pos;
+  }
+
+  /**
+   * Builds the status message for the current cursor location and writes it to
+   * the status bar, for example
+   * 
+   * <pre>
+   * Sequence 3 ID: FER1_SOLLC
+   * Sequence 5 ID: FER1_PEA Residue: THR (4)
+   * Sequence 5 ID: FER1_PEA Residue: B (3)
+   * Sequence 6 ID: O.niloticus.3 Nucleotide: Uracil (2)
+   * </pre>
+   * 
+   * @param sequence
+   * @param seqIndex
+   *          sequence position in the alignment (1..)
+   * @param sequenceChar
+   *          the character under the cursor
+   * @param residuePos
+   *          the sequence residue position (if not over a gap)
+   */
+  protected void setStatusMessage(SequenceI sequence, int seqIndex,
+          char sequenceChar, int residuePos)
   {
     StringBuilder text = new StringBuilder(32);
 
     /*
      * Sequence number (if known), and sequence name.
      */
-    String seqno = seq == -1 ? "" : " " + (seq + 1);
+    String seqno = seqIndex == -1 ? "" : " " + (seqIndex + 1);
     text.append("Sequence").append(seqno).append(" ID: ")
             .append(sequence.getName());
 
@@ -903,13 +920,12 @@ public class SeqPanel extends JPanel implements MouseListener,
     /*
      * Try to translate the display character to residue name (null for gap).
      */
-    final String displayChar = String.valueOf(sequence.getCharAt(column));
-    boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
-    int pos = sequence.findPosition(column);
+    boolean isGapped = Comparison.isGap(sequenceChar);
 
     if (!isGapped)
     {
       boolean nucleotide = av.getAlignment().isNucleotide();
+      String displayChar = String.valueOf(sequenceChar);
       if (nucleotide)
       {
         residue = ResidueProperties.nucleotideName.get(displayChar);
@@ -923,11 +939,9 @@ public class SeqPanel extends JPanel implements MouseListener,
       text.append(" ").append(nucleotide ? "Nucleotide" : "Residue")
               .append(": ").append(residue == null ? displayChar : residue);
 
-      text.append(" (").append(Integer.toString(pos)).append(")");
+      text.append(" (").append(Integer.toString(residuePos)).append(")");
     }
     ap.alignFrame.statusBar.setText(text.toString());
-
-    return pos;
   }
 
   /**
@@ -955,12 +969,9 @@ public class SeqPanel extends JPanel implements MouseListener,
 
       if (seq == ds)
       {
-        /*
-         * Convert position in sequence (base 1) to sequence character array
-         * index (base 0)
-         */
-        int start = m.getStart() - m.getSequence().getStart();
-        setStatusMessage(seq, start, sequenceIndex);
+        int start = m.getStart();
+        setStatusMessage(seq, sequenceIndex, seq.getCharAt(start - 1),
+                start);
         return;
       }
     }
@@ -1567,19 +1578,13 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
 
       int column = findColumn(evt);
-      boolean isGapped = Comparison.isGap(sequence.getCharAt(column));
 
       /*
        * find features at the position (if not gapped), or straddling
        * the position (if at a gap)
        */
       List<SequenceFeature> features = seqCanvas.getFeatureRenderer()
-              .findFeaturesAtRes(sequence.getDatasetSequence(),
-                      sequence.findPosition(column));
-      if (isGapped)
-      {
-        removeAdjacentFeatures(features, column, sequence);
-      }
+              .findFeaturesAtColumn(sequence, column + 1);
 
       if (!features.isEmpty())
       {
@@ -1756,12 +1761,11 @@ public class SeqPanel extends JPanel implements MouseListener,
    */
   void showPopupMenu(MouseEvent evt)
   {
-    final int res = findColumn(evt);
+    final int column = findColumn(evt);
     final int seq = findSeq(evt);
     SequenceI sequence = av.getAlignment().getSequenceAt(seq);
     List<SequenceFeature> allFeatures = ap.getFeatureRenderer()
-            .findFeaturesAtRes(sequence.getDatasetSequence(),
-                    sequence.findPosition(res));
+            .findFeaturesAtColumn(sequence, column + 1);
     List<String> links = new ArrayList<>();
     for (SequenceFeature sf : allFeatures)
     {