JAL-1691 applet SplitFrame scrolling; pull up of 5 fields to
[jalview.git] / src / jalview / appletgui / AlignmentPanel.java
index c74914f..5a2c5ef 100644 (file)
@@ -32,10 +32,12 @@ import java.awt.event.AdjustmentEvent;
 import java.awt.event.AdjustmentListener;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
+import java.util.List;
 
 import jalview.analysis.AnnotationSorter;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
+import jalview.bin.JalviewLite;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.SequenceI;
@@ -313,7 +315,21 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
   public boolean scrollToPosition(SearchResults results,
           boolean redrawOverview)
   {
+    return scrollToPosition(results, redrawOverview, false);
+  }
 
+  /**
+   * scroll the view to show the position of the highlighted region in results
+   * (if any)
+   * 
+   * @param results
+   * @param redrawOverview
+   *          - when set, the overview will be recalculated (takes longer)
+   * @return false if results were not found
+   */
+  public boolean scrollToPosition(SearchResults results,
+          boolean redrawOverview, boolean centre)
+  {
     // do we need to scroll the panel?
     if (results != null && results.getSize() > 0)
     {
@@ -327,7 +343,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       int[] r = results.getResults(seq, 0, alignment.getWidth());
       if (r == null)
       {
-        if (av.applet.debug)
+        if (JalviewLite.debug)
         {// DEBUG
           System.out
                   .println("DEBUG: scroll didn't happen - results not within alignment : "
@@ -335,7 +351,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
         }
         return false;
       }
-      if (av.applet.debug)
+      if (JalviewLite.debug)
       {
         // DEBUG
         /*
@@ -347,6 +363,18 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
       }
       int start = r[0];
       int end = r[1];
+
+      /*
+       * To centre results, scroll to positions half the visible width
+       * left/right of the start/end positions
+       */
+      if (centre)
+      {
+        int offset = (av.getEndRes() - av.getStartRes() + 1) / 2 - 1;
+        start = Math.max(start - offset, 0);
+        end = Math.min(end + offset, seq.getEnd() - 1);
+      }
+
       if (start < 0)
       {
         return false;
@@ -394,33 +422,64 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
        * av.getStartSeq()) > seqIndex) { setScrollValues(av.getStartRes(),
        * seqIndex); } else if ((ends = av.getEndSeq()) <= seqIndex) {
        * setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1); }
-       * 
-       * /*
        */
-      if ((av.getStartRes() > end)
-              || (av.getEndRes() < start)
-              || ((av.getStartSeq() > seqIndex) || (av.getEndSeq() < seqIndex)))
-      {
-        if (start > av.getAlignment().getWidth() - hextent)
-        {
-          start = av.getAlignment().getWidth() - hextent;
-          if (start < 0)
-          {
-            start = 0;
-          }
 
+      // below is scrolling logic up to Jalview 2.8.2
+      // if ((av.getStartRes() > end)
+      // || (av.getEndRes() < start)
+      // || ((av.getStartSeq() > seqIndex) || (av.getEndSeq() < seqIndex)))
+      // {
+      // if (start > av.getAlignment().getWidth() - hextent)
+      // {
+      // start = av.getAlignment().getWidth() - hextent;
+      // if (start < 0)
+      // {
+      // start = 0;
+      // }
+      //
+      // }
+      // if (seqIndex > av.getAlignment().getHeight() - vextent)
+      // {
+      // seqIndex = av.getAlignment().getHeight() - vextent;
+      // if (seqIndex < 0)
+      // {
+      // seqIndex = 0;
+      // }
+      // }
+      // setScrollValues(start, seqIndex);
+      // }
+      // logic copied from jalview.gui.AlignmentPanel:
+        if ((startv = av.getStartRes()) >= start)
+        {
+          /*
+           * Scroll left to make start of search results visible
+           */
+          setScrollValues(start - 1, seqIndex);
+        }
+        else if ((endv = av.getEndRes()) <= end)
+        {
+          /*
+           * Scroll right to make end of search results visible
+           */
+          setScrollValues(startv + 1 + end - endv, seqIndex);
+        }
+        else if ((starts = av.getStartSeq()) > seqIndex)
+        {
+          /*
+           * Scroll up to make start of search results visible
+           */
+          setScrollValues(av.getStartRes(), seqIndex);
         }
-        if (seqIndex > av.getAlignment().getHeight() - vextent)
+        else if ((ends = av.getEndSeq()) <= seqIndex)
         {
-          seqIndex = av.getAlignment().getHeight() - vextent;
-          if (seqIndex < 0)
-          {
-            seqIndex = 0;
-          }
+          /*
+           * Scroll down to make end of search results visible
+           */
+          setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1);
         }
-        // System.out.println("trying to scroll to: "+start+" "+seqIndex);
-        setScrollValues(start, seqIndex);
-      }/**/
+        /*
+         * Else results are already visible - no need to scroll
+         */
     }
     else
     {
@@ -793,6 +852,95 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     }
     sendViewPosition();
 
+    /*
+     * If there is one, scroll the (Protein/cDNA) complementary alignment to
+     * match, unless we are ourselves doing that.
+     */
+    if (isFollowingComplementScroll())
+    {
+      setFollowingComplementScroll(false);
+    }
+    else
+    {
+      AlignmentPanel ap = getComplementPanel();
+      av.scrollComplementaryAlignment(ap);
+    }
+
+  }
+
+  /**
+   * A helper method to return the AlignmentPanel in the other (complementary)
+   * half of a SplitFrame view. Returns null if not in a SplitFrame.
+   * 
+   * @return
+   */
+  private AlignmentPanel getComplementPanel()
+  {
+    AlignmentPanel ap = null;
+    if (alignFrame != null)
+    {
+      SplitFrame sf = alignFrame.getSplitFrame();
+      if (sf != null)
+      {
+        AlignFrame other = sf.getComplement(alignFrame);
+        if (other != null)
+        {
+          ap = other.alignPanel;
+        }
+      }
+    }
+    return ap;
+  }
+
+  /**
+   * Follow a scrolling change in the (cDNA/Protein) complementary alignment.
+   * The aim is to keep the two alignments 'lined up' on their centre columns.
+   * 
+   * @param sr
+   *          holds mapped region(s) of this alignment that we are scrolling
+   *          'to'; may be modified for sequence offset by this method
+   * @param seqOffset
+   *          the number of visible sequences to show above the mapped region
+   */
+  protected void scrollToCentre(SearchResults sr, int seqOffset)
+  {
+    /*
+     * To avoid jumpy vertical scrolling (if some sequences are gapped or not
+     * mapped), we can make the scroll-to location a sequence above the one
+     * actually mapped.
+     */
+    SequenceI mappedTo = sr.getResultSequence(0);
+    List<SequenceI> seqs = av.getAlignment().getSequences();
+
+    /*
+     * This is like AlignmentI.findIndex(seq) but here we are matching the
+     * dataset sequence not the aligned sequence
+     */
+    int sequenceIndex = 0;
+    boolean matched = false;
+    for (SequenceI seq : seqs)
+    {
+      if (mappedTo == seq.getDatasetSequence())
+      {
+        matched = true;
+        break;
+      }
+      sequenceIndex++;
+    }
+    if (!matched)
+    {
+      return; // failsafe, shouldn't happen
+    }
+    sequenceIndex = Math.max(0, sequenceIndex - seqOffset);
+    sr.getResults().get(0)
+            .setSequence(av.getAlignment().getSequenceAt(sequenceIndex));
+
+    /*
+     * Scroll to position but centring the target residue. Also set a state flag
+     * to prevent adjustmentValueChanged performing this recursively.
+     */
+    setFollowingComplementScroll(true);
+    scrollToPosition(sr, true, true);
   }
 
   private void sendViewPosition()
@@ -884,72 +1032,58 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
   protected Panel seqPanelHolder = new Panel();
 
-  BorderLayout borderLayout1 = new BorderLayout();
-
-  BorderLayout borderLayout3 = new BorderLayout();
-
   protected Panel scalePanelHolder = new Panel();
 
   protected Panel idPanelHolder = new Panel();
 
-  BorderLayout borderLayout5 = new BorderLayout();
-
   protected Panel idSpaceFillerPanel1 = new Panel();
 
   public Panel annotationSpaceFillerHolder = new Panel();
 
-  BorderLayout borderLayout6 = new BorderLayout();
-
-  BorderLayout borderLayout7 = new BorderLayout();
-
-  Panel hscrollHolder = new Panel();
-
-  BorderLayout borderLayout10 = new BorderLayout();
-
   protected Panel hscrollFillerPanel = new Panel();
 
-  BorderLayout borderLayout11 = new BorderLayout();
-
-  BorderLayout borderLayout4 = new BorderLayout();
-
-  BorderLayout borderLayout2 = new BorderLayout();
-
   Panel annotationPanelHolder = new Panel();
 
   protected Scrollbar apvscroll = new Scrollbar();
 
-  BorderLayout borderLayout12 = new BorderLayout();
+  /*
+   * Flag set while scrolling to follow complementary cDNA/protein scroll. When
+   * true, suppresses invoking the same method recursively.
+   */
+  private boolean followingComplementScroll;
 
   private void jbInit() throws Exception
   {
     // idPanelHolder.setPreferredSize(new Dimension(70, 10));
-    this.setLayout(borderLayout7);
+    this.setLayout(new BorderLayout());
 
     // sequenceHolderPanel.setPreferredSize(new Dimension(150, 150));
-    sequenceHolderPanel.setLayout(borderLayout3);
-    seqPanelHolder.setLayout(borderLayout1);
+    sequenceHolderPanel.setLayout(new BorderLayout());
+    seqPanelHolder.setLayout(new BorderLayout());
     scalePanelHolder.setBackground(Color.white);
 
     // scalePanelHolder.setPreferredSize(new Dimension(10, 30));
-    scalePanelHolder.setLayout(borderLayout6);
-    idPanelHolder.setLayout(borderLayout5);
+    scalePanelHolder.setLayout(new BorderLayout());
+    idPanelHolder.setLayout(new BorderLayout());
     idSpaceFillerPanel1.setBackground(Color.white);
 
     // idSpaceFillerPanel1.setPreferredSize(new Dimension(10, 30));
-    idSpaceFillerPanel1.setLayout(borderLayout11);
+    idSpaceFillerPanel1.setLayout(new BorderLayout());
     annotationSpaceFillerHolder.setBackground(Color.white);
 
     // annotationSpaceFillerHolder.setPreferredSize(new Dimension(10, 80));
-    annotationSpaceFillerHolder.setLayout(borderLayout4);
+    annotationSpaceFillerHolder.setLayout(new BorderLayout());
     hscroll.setOrientation(Scrollbar.HORIZONTAL);
-    hscrollHolder.setLayout(borderLayout10);
+
+    Panel hscrollHolder = new Panel();
+    hscrollHolder.setLayout(new BorderLayout());
     hscrollFillerPanel.setBackground(Color.white);
     apvscroll.setOrientation(Scrollbar.VERTICAL);
     apvscroll.setVisible(true);
     apvscroll.addAdjustmentListener(this);
 
     annotationPanelHolder.setBackground(Color.white);
-    annotationPanelHolder.setLayout(borderLayout12);
+    annotationPanelHolder.setLayout(new BorderLayout());
     annotationPanelHolder.add(apvscroll, BorderLayout.EAST);
     // hscrollFillerPanel.setPreferredSize(new Dimension(70, 10));
     hscrollHolder.setBackground(Color.white);
@@ -1020,4 +1154,19 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     error.printStackTrace();
   }
 
+  /**
+   * Set a flag to say we are scrolling to follow a (cDNA/protein) complement.
+   * 
+   * @param b
+   */
+  protected void setFollowingComplementScroll(boolean b)
+  {
+    this.followingComplementScroll = b;
+  }
+
+  protected boolean isFollowingComplementScroll()
+  {
+    return this.followingComplementScroll;
+  }
+
 }