JAL-1894 update year/version in copyright
[jalview.git] / src / jalview / gui / SeqPanel.java
index 6cd5b70..d1fb7dc 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9.0b1)
+ * Copyright (C) 2015 The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
  */
 package jalview.gui;
 
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Point;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.awt.event.MouseMotionListener;
-import java.awt.event.MouseWheelEvent;
-import java.awt.event.MouseWheelListener;
-import java.util.List;
-import java.util.Vector;
-
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.ToolTipManager;
-
 import jalview.api.AlignViewportI;
 import jalview.commands.EditCommand;
 import jalview.commands.EditCommand.Action;
 import jalview.commands.EditCommand.Edit;
+import jalview.datamodel.AlignmentI;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SearchResults.Match;
@@ -60,6 +44,23 @@ import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Point;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.util.List;
+import java.util.Vector;
+
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.ToolTipManager;
+
 /**
  * DOCUMENT ME!
  * 
@@ -128,6 +129,8 @@ public class SeqPanel extends JPanel implements MouseListener,
 
   StructureSelectionManager ssm;
 
+  SearchResults lastSearchResults;
+
   /**
    * Creates a new SeqPanel object.
    * 
@@ -167,6 +170,13 @@ public class SeqPanel extends JPanel implements MouseListener,
 
   int wrappedBlock = -1;
 
+  /**
+   * Returns the aligned sequence position (base 0) at the mouse position, or
+   * the closest visible one
+   * 
+   * @param evt
+   * @return
+   */
   int findRes(MouseEvent evt)
   {
     int res = 0;
@@ -182,8 +192,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
 
       int cHeight = av.getAlignment().getHeight() * av.getCharHeight()
-              + hgap
-              + seqCanvas.getAnnotationHeight();
+              + hgap + seqCanvas.getAnnotationHeight();
 
       int y = evt.getY();
       y -= hgap;
@@ -203,13 +212,18 @@ public class SeqPanel extends JPanel implements MouseListener,
     }
     else
     {
-      if (x > seqCanvas.getWidth() + seqCanvas.getWidth())
+      if (x > seqCanvas.getX() + seqCanvas.getWidth())
       {
         // make sure we calculate relative to visible alignment, rather than
         // right-hand gutter
         x = seqCanvas.getX() + seqCanvas.getWidth();
       }
       res = (x / av.getCharWidth()) + av.getStartRes();
+      if (res > av.getEndRes())
+      {
+        // moused off right
+        res = av.getEndRes();
+      }
     }
 
     if (av.hasHiddenColumns())
@@ -235,8 +249,7 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
 
       int cHeight = av.getAlignment().getHeight() * av.getCharHeight()
-              + hgap
-              + seqCanvas.getAnnotationHeight();
+              + hgap + seqCanvas.getAnnotationHeight();
 
       y -= hgap;
 
@@ -644,11 +657,30 @@ public class SeqPanel extends JPanel implements MouseListener,
     lastMessage = tmp;
   }
 
+  /**
+   * Highlight the mapped region described by the search results object (unless
+   * unchanged). This supports highlight of protein while mousing over linked
+   * cDNA and vice versa. The status bar is also updated to show the location of
+   * the start of the highlighted region.
+   */
   @Override
   public void highlightSequence(SearchResults results)
   {
+    if (results == null || results.equals(lastSearchResults))
+    {
+      return;
+    }
+    lastSearchResults = results;
+
     if (av.isFollowHighlight())
     {
+      /*
+       * if scrollToPosition requires a scroll adjustment, this flag prevents
+       * another scroll event being propagated back to the originator
+       * 
+       * @see AlignmentPanel#adjustmentValueChanged
+       */
+      ap.setDontScrollComplement(true);
       if (ap.scrollToPosition(results, false))
       {
         seqCanvas.revalidate();
@@ -663,6 +695,7 @@ public class SeqPanel extends JPanel implements MouseListener,
   {
     return this.ap == null ? null : this.ap.av;
   }
+
   @Override
   public void updateColours(SequenceI seq, int index)
   {
@@ -734,9 +767,9 @@ public class SeqPanel extends JPanel implements MouseListener,
     if (av.isShowSequenceFeatures())
     {
       int rpos;
-      List<SequenceFeature> features = ap.getFeatureRenderer().findFeaturesAtRes(
-              sequence.getDatasetSequence(),
-              rpos = sequence.findPosition(res));
+      List<SequenceFeature> features = ap.getFeatureRenderer()
+              .findFeaturesAtRes(sequence.getDatasetSequence(),
+                      rpos = sequence.findPosition(res));
       seqARep.appendFeatures(tooltipText, rpos, features,
               this.ap.getSeqPanel().seqCanvas.fr.getMinMax());
     }
@@ -823,8 +856,9 @@ public class SeqPanel extends JPanel implements MouseListener,
     }
     else
     {
-      residue = "X".equalsIgnoreCase(displayChar) ? "X"
-              : ResidueProperties.aa2Triplet.get(displayChar);
+      residue = "X".equalsIgnoreCase(displayChar) ? "X" : ("*"
+              .equals(displayChar) ? "STOP" : ResidueProperties.aa2Triplet
+              .get(displayChar));
       if (residue != null)
       {
         text.append(" Residue: ").append(residue);
@@ -849,19 +883,31 @@ public class SeqPanel extends JPanel implements MouseListener,
    */
   private void setStatusMessage(SearchResults results)
   {
-    List<Match> matches = results.getResults();
-    if (!matches.isEmpty())
+    AlignmentI al = this.av.getAlignment();
+    int sequenceIndex = al.findIndex(results);
+    if (sequenceIndex == -1)
+    {
+      return;
+    }
+    SequenceI ds = al.getSequenceAt(sequenceIndex).getDatasetSequence();
+    for (Match m : results.getResults())
     {
-      Match m = matches.get(0);
       SequenceI seq = m.getSequence();
-      int sequenceIndex = this.av.getAlignment().findIndex(seq);
+      if (seq.getDatasetSequence() != null)
+      {
+        seq = seq.getDatasetSequence();
+      }
 
-      /*
-       * Convert position in sequence (base 1) to sequence character array index
-       * (base 0)
-       */
-      int start = m.getStart() - 1;
-      setStatusMessage(seq, start, sequenceIndex);
+      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);
+        return;
+      }
     }
   }
 
@@ -988,7 +1034,8 @@ public class SeqPanel extends JPanel implements MouseListener,
       message.append("Edit group:");
       if (editCommand == null)
       {
-        editCommand = new EditCommand(MessageManager.getString("action.edit_group"));
+        editCommand = new EditCommand(
+                MessageManager.getString("action.edit_group"));
       }
     }
     else
@@ -1001,7 +1048,8 @@ public class SeqPanel extends JPanel implements MouseListener,
       }
       if (editCommand == null)
       {
-        editCommand = new EditCommand(MessageManager.formatMessage("label.edit_params", new String[]{label}));
+        editCommand = new EditCommand(MessageManager.formatMessage(
+                "label.edit_params", new String[] { label }));
       }
     }
 
@@ -1239,14 +1287,13 @@ public class SeqPanel extends JPanel implements MouseListener,
         {
           for (int j = lastres; j < startres; j++)
           {
-            insertChar(j, new SequenceI[]
-            { seq }, fixedRight);
+            insertChar(j, new SequenceI[] { seq }, fixedRight);
           }
         }
         else
         {
-          appendEdit(Action.INSERT_GAP, new SequenceI[]
-          { seq }, lastres, startres - lastres);
+          appendEdit(Action.INSERT_GAP, new SequenceI[] { seq }, lastres,
+                  startres - lastres);
         }
       }
       else
@@ -1263,8 +1310,7 @@ public class SeqPanel extends JPanel implements MouseListener,
                 endEditing();
                 break;
               }
-              deleteChar(startres, new SequenceI[]
-              { seq }, fixedRight);
+              deleteChar(startres, new SequenceI[] { seq }, fixedRight);
             }
           }
           else
@@ -1282,8 +1328,8 @@ public class SeqPanel extends JPanel implements MouseListener,
 
             if (max > 0)
             {
-              appendEdit(Action.DELETE_GAP, new SequenceI[]
-              { seq }, startres, max);
+              appendEdit(Action.DELETE_GAP, new SequenceI[] { seq },
+                      startres, max);
             }
           }
         }
@@ -1293,14 +1339,13 @@ public class SeqPanel extends JPanel implements MouseListener,
           {
             for (int j = lastres; j < startres; j++)
             {
-              insertChar(j, new SequenceI[]
-              { seq }, fixedRight);
+              insertChar(j, new SequenceI[] { seq }, fixedRight);
             }
           }
           else
           {
-            appendEdit(Action.INSERT_NUC, new SequenceI[]
-            { seq }, lastres, startres - lastres);
+            appendEdit(Action.INSERT_NUC, new SequenceI[] { seq }, lastres,
+                    startres - lastres);
           }
         }
       }
@@ -1356,8 +1401,7 @@ public class SeqPanel extends JPanel implements MouseListener,
     final Edit edit = new EditCommand().new Edit(action, seq, pos, count,
             av.getAlignment().getGapCharacter());
 
-    editCommand.appendEdit(edit, av.getAlignment(),
-            true, null);
+    editCommand.appendEdit(edit, av.getAlignment(), true, null);
   }
 
   void deleteChar(int j, SequenceI[] seq, int fixedColumn)
@@ -1423,21 +1467,23 @@ public class SeqPanel extends JPanel implements MouseListener,
         av.setSelectionGroup(null);
       }
 
-      List<SequenceFeature> features = seqCanvas.getFeatureRenderer().findFeaturesAtRes(
-              sequence.getDatasetSequence(),
-              sequence.findPosition(findRes(evt)));
+      List<SequenceFeature> features = seqCanvas.getFeatureRenderer()
+              .findFeaturesAtRes(sequence.getDatasetSequence(),
+                      sequence.findPosition(findRes(evt)));
 
-      if (features != null && features.size()> 0)
+      if (features != null && features.size() > 0)
       {
         SearchResults highlight = new SearchResults();
-        highlight.addResult(sequence, features.get(0).getBegin(),
-                features.get(0).getEnd());
+        highlight.addResult(sequence, features.get(0).getBegin(), features
+                .get(0).getEnd());
         seqCanvas.highlightSearchResults(highlight);
       }
-      if (features != null && features.size()> 0)
+      if (features != null && features.size() > 0)
       {
-        seqCanvas.getFeatureRenderer().amendFeatures(new SequenceI[]
-        { sequence }, features.toArray(new SequenceFeature[features.size()]), false, ap);
+        seqCanvas.getFeatureRenderer().amendFeatures(
+                new SequenceI[] { sequence },
+                features.toArray(new SequenceFeature[features.size()]),
+                false, ap);
 
         seqCanvas.highlightSearchResults(null);
       }
@@ -1552,10 +1598,11 @@ public class SeqPanel extends JPanel implements MouseListener,
 
     if (javax.swing.SwingUtilities.isRightMouseButton(evt))
     {
-      List<SequenceFeature> allFeatures = ap.getFeatureRenderer().findFeaturesAtRes(
-              sequence.getDatasetSequence(), sequence.findPosition(res));
+      List<SequenceFeature> allFeatures = ap.getFeatureRenderer()
+              .findFeaturesAtRes(sequence.getDatasetSequence(),
+                      sequence.findPosition(res));
       Vector links = new Vector();
-      for (SequenceFeature sf:allFeatures)
+      for (SequenceFeature sf : allFeatures)
       {
         if (sf.links != null)
         {
@@ -1871,8 +1918,7 @@ public class SeqPanel extends JPanel implements MouseListener,
     // handles selection messages...
     // TODO: extend config options to allow user to control if selections may be
     // shared between viewports.
-    boolean iSentTheSelection = (av == source
-            || (source instanceof AlignViewport && ((AlignmentViewport) source)
+    boolean iSentTheSelection = (av == source || (source instanceof AlignViewport && ((AlignmentViewport) source)
             .getSequenceSetId().equals(av.getSequenceSetId())));
     if (iSentTheSelection || !av.followSelection)
     {
@@ -1988,11 +2034,13 @@ public class SeqPanel extends JPanel implements MouseListener,
   protected boolean selectionFromTranslation(SequenceGroup seqsel,
           ColumnSelection colsel, SelectionSource source)
   {
-    if (!(source instanceof AlignViewportI)) {
+    if (!(source instanceof AlignViewportI))
+    {
       return false;
     }
     final AlignViewportI sourceAv = (AlignViewportI) source;
-    if (sourceAv.getCodingComplement() != av && av.getCodingComplement() != sourceAv)
+    if (sourceAv.getCodingComplement() != av
+            && av.getCodingComplement() != sourceAv)
     {
       return false;
     }