Merge branch 'develop' into bug/JAL-2837 bug/JAL-2837
authorkiramt <k.mourao@dundee.ac.uk>
Fri, 17 Nov 2017 12:14:59 +0000 (12:14 +0000)
committerkiramt <k.mourao@dundee.ac.uk>
Fri, 17 Nov 2017 12:14:59 +0000 (12:14 +0000)
Conflicts:
src/jalview/gui/SeqPanel.java

1  2 
src/jalview/gui/SeqPanel.java
src/jalview/viewmodel/ViewportRanges.java

@@@ -320,13 -320,13 +320,13 @@@ public class SeqPanel extends JPane
    void setCursorRow()
    {
      seqCanvas.cursorY = getKeyboardNo1() - 1;
-     scrollToVisible();
+     scrollToVisible(true);
    }
  
    void setCursorColumn()
    {
      seqCanvas.cursorX = getKeyboardNo1() - 1;
-     scrollToVisible();
+     scrollToVisible(true);
    }
  
    void setCursorRowAndColumn()
      {
        seqCanvas.cursorX = getKeyboardNo1() - 1;
        seqCanvas.cursorY = getKeyboardNo2() - 1;
-       scrollToVisible();
+       scrollToVisible(true);
      }
    }
  
      SequenceI sequence = av.getAlignment().getSequenceAt(seqCanvas.cursorY);
  
      seqCanvas.cursorX = sequence.findIndex(getKeyboardNo1()) - 1;
-     scrollToVisible();
+     scrollToVisible(true);
    }
  
    void moveCursor(int dx, int dy)
        }
      }
  
-     scrollToVisible();
+     scrollToVisible(false);
    }
  
-   void scrollToVisible()
+   /**
+    * Scroll to make the cursor visible in the viewport.
+    * 
+    * @param jump
+    *          just jump to the location rather than scrolling
+    */
+   void scrollToVisible(boolean jump)
    {
      if (seqCanvas.cursorX < 0)
      {
      }
  
      endEditing();
-     if (av.getWrapAlignment())
+     boolean repaintNeeded = true;
+     if (jump)
      {
-       // scrollToWrappedVisible expects x-value to have hidden cols subtracted
-       int x = av.getAlignment().getHiddenColumns()
-               .findColumnPosition(seqCanvas.cursorX);
-       av.getRanges().scrollToWrappedVisible(x);
+       // only need to repaint if the viewport did not move, as otherwise it will
+       // get a repaint
+       repaintNeeded = !av.getRanges().setViewportLocation(seqCanvas.cursorX,
+               seqCanvas.cursorY);
      }
      else
      {
-       av.getRanges().scrollToVisible(seqCanvas.cursorX, seqCanvas.cursorY);
+       if (av.getWrapAlignment())
+       {
 -        av.getRanges().scrollToWrappedVisible(seqCanvas.cursorX);
++        // scrollToWrappedVisible expects x-value to have hidden cols subtracted
++        int x = av.getAlignment().getHiddenColumns()
++                .findColumnPosition(seqCanvas.cursorX);
++        av.getRanges().scrollToWrappedVisible(x);
+       }
+       else
+       {
+         av.getRanges().scrollToVisible(seqCanvas.cursorX,
+                 seqCanvas.cursorY);
+       }
      }
-     setStatusMessage(av.getAlignment().getSequenceAt(seqCanvas.cursorY),
+     if (av.getAlignment().getHiddenColumns().isVisible(seqCanvas.cursorX))
+     {
+       setStatusMessage(av.getAlignment().getSequenceAt(seqCanvas.cursorY),
              seqCanvas.cursorX, seqCanvas.cursorY);
+     }
  
-     seqCanvas.repaint();
+     if (repaintNeeded)
+     {
+       seqCanvas.repaint();
+     }
    }
  
    void setSelectionAreaAtCursor(boolean topLeft)
    {
      SequenceI sequence = av.getAlignment().getSequenceAt(seqCanvas.cursorY);
@@@ -24,11 -24,10 +24,10 @@@ import jalview.datamodel.AlignmentI
  import jalview.datamodel.HiddenColumns;
  
  /**
-  * Slightly less embryonic class which: Supplies and updates viewport properties
-  * relating to position such as: start and end residues and sequences; ideally
-  * will serve hidden columns/rows too. Intention also to support calculations
-  * for positioning, scrolling etc. such as finding the middle of the viewport,
-  * checking for scrolls off screen
+  * Supplies and updates viewport properties relating to position such as: start
+  * and end residues and sequences; ideally will serve hidden columns/rows too.
+  * Intention also to support calculations for positioning, scrolling etc. such
+  * as finding the middle of the viewport, checking for scrolls off screen
   */
  public class ViewportRanges extends ViewportProperties
  {
  
    public static final String ENDSEQ = "endseq";
  
+   public static final String STARTRESANDSEQ = "startresandseq";
+   public static final String MOVE_VIEWPORT = "move_viewport";
    private boolean wrappedMode = false;
  
    // start residue of viewport
     */
    public void setStartEndRes(int start, int end)
    {
+     int[] oldvalues = updateStartEndRes(start, end);
+     int oldstartres = oldvalues[0];
+     int oldendres = oldvalues[1];
+     changeSupport.firePropertyChange(STARTRES, oldstartres, startRes);
+     if (oldstartres == startRes)
+     {
+       // event won't be fired if start positions are same
+       // fire an event for the end positions in case they changed
+       changeSupport.firePropertyChange(ENDRES, oldendres, endRes);
+     }
+   }
+   /**
+    * Update start and end residue values, adjusting for width constraints if
+    * necessary
+    * 
+    * @param start
+    *          start residue
+    * @param end
+    *          end residue
+    * @return array containing old start and end residue values
+    */
+   private int[] updateStartEndRes(int start, int end)
+   {
      int oldstartres = this.startRes;
  
      /*
      {
        endRes = end;
      }
-     changeSupport.firePropertyChange(STARTRES, oldstartres, startRes);
-     if (oldstartres == startRes)
-     {
-       // event won't be fired if start positions are same
-       // fire an event for the end positions in case they changed
-       changeSupport.firePropertyChange(ENDRES, oldendres, endRes);
-     }
+     return new int[] { oldstartres, oldendres };
    }
  
    /**
     */
    public void setStartEndSeq(int start, int end)
    {
+     int[] oldvalues = updateStartEndSeq(start, end);
+     int oldstartseq = oldvalues[0];
+     int oldendseq = oldvalues[1];
+     changeSupport.firePropertyChange(STARTSEQ, oldstartseq, startSeq);
+     if (oldstartseq == startSeq)
+     {
+       // event won't be fired if start positions are the same
+       // fire in case the end positions changed
+       changeSupport.firePropertyChange(ENDSEQ, oldendseq, endSeq);
+     }
+   }
+   /**
+    * Update start and end sequence values, adjusting for height constraints if
+    * necessary
+    * 
+    * @param start
+    *          start sequence
+    * @param end
+    *          end sequence
+    * @return array containing old start and end sequence values
+    */
+   private int[] updateStartEndSeq(int start, int end)
+   {
      int oldstartseq = this.startSeq;
      int visibleHeight = getVisibleAlignmentHeight();
      if (start > visibleHeight - 1)
      {
        endSeq = end;
      }
-     changeSupport.firePropertyChange(STARTSEQ, oldstartseq, startSeq);
-     if (oldstartseq == startSeq)
-     {
-       // event won't be fired if start positions are the same
-       // fire in case the end positions changed
-       changeSupport.firePropertyChange(ENDSEQ, oldendseq, endSeq);
-     }
+     return new int[] { oldstartseq, oldendseq };
    }
  
    /**
    }
  
    /**
+    * Set start residue and start sequence together (fires single event). The
+    * event supplies a pair of old values and a pair of new values: [old start
+    * residue, old start sequence] and [new start residue, new start sequence]
+    * 
+    * @param res
+    *          the start residue
+    * @param seq
+    *          the start sequence
+    */
+   public void setStartResAndSeq(int res, int seq)
+   {
+     int width = getViewportWidth();
+     int[] oldresvalues = updateStartEndRes(res, res + width - 1);
+     int startseq = seq;
+     int height = getViewportHeight();
+     if (startseq + height - 1 > getVisibleAlignmentHeight() - 1)
+     {
+       startseq = getVisibleAlignmentHeight() - height;
+     }
+     int[] oldseqvalues = updateStartEndSeq(startseq, startseq + height - 1);
+     int[] old = new int[] { oldresvalues[0], oldseqvalues[0] };
+     int[] newresseq = new int[] { startRes, startSeq };
+     changeSupport.firePropertyChange(STARTRESANDSEQ, old, newresseq);
+   }
+   /**
     * Get start residue of viewport
     */
    public int getStartRes()
     * the startRes changed, else false.
     * 
     * @param res
 -   *          residue position to scroll to
 +   *          residue position to scroll to NB visible position not absolute
 +   *          alignment position
     * @return
     */
    public boolean scrollToWrappedVisible(int res)
    {
-     int oldStartRes = startRes;
-     int width = getViewportWidth();
-     if (res >= oldStartRes && res < oldStartRes + width)
+     int newStartRes = calcWrappedStartResidue(res);
+     if (newStartRes == startRes)
      {
        return false;
      }
+     setStartRes(newStartRes);
+     return true;
+   }
+   /**
+    * Calculate wrapped start residue from visible start residue
+    * 
+    * @param res
+    *          visible start residue
+    * @return left column of panel res will be located in
+    */
+   private int calcWrappedStartResidue(int res)
+   {
+     int oldStartRes = startRes;
+     int width = getViewportWidth();
  
      boolean up = res < oldStartRes;
      int widthsToScroll = Math.abs((res - oldStartRes) / width);
      {
        newStartRes = 0;
      }
-     setStartRes(newStartRes);
-     return true;
+     return newStartRes;
    }
  
    /**
     * Scroll so that (x,y) is visible. Fires a property change event.
     * 
     * @param x
 -   *          x position in alignment
 +   *          x position in alignment (absolute position)
     * @param y
 -   *          y position in alignment
 +   *          y position in alignment (absolute position)
     */
    public void scrollToVisible(int x, int y)
    {
      {
        scrollUp(false);
      }
+     
      HiddenColumns hidden = al.getHiddenColumns();
      while (x < hidden.adjustForHiddenColumns(startRes))
      {
    }
  
    /**
+    * Set the viewport location so that a position is visible
+    * 
+    * @param x
+    *          column to be visible: absolute position in alignment
+    * @param y
+    *          row to be visible: absolute position in alignment
+    */
+   public boolean setViewportLocation(int x, int y)
+   {
+     boolean changedLocation = false;
+     // convert the x,y location to visible coordinates
+     int visX = al.getHiddenColumns().findColumnPosition(x);
+     int visY = al.getHiddenSequences().findIndexWithoutHiddenSeqs(y);
+     // if (vis_x,vis_y) is already visible don't do anything
+     if (startRes > visX || visX > endRes
+             || startSeq > visY && visY > endSeq)
+     {
+       int[] old = new int[] { startRes, startSeq };
+       int[] newresseq;
+       if (wrappedMode)
+       {
+         int newstartres = calcWrappedStartResidue(visX);
+         setStartRes(newstartres);
+         newresseq = new int[] { startRes, startSeq };
+       }
+       else
+       {
+         // set the viewport x location to contain vis_x
+         int newstartres = visX;
+         int width = getViewportWidth();
+         if (newstartres + width - 1 > getVisibleAlignmentWidth() - 1)
+         {
+           newstartres = getVisibleAlignmentWidth() - width;
+         }
+         updateStartEndRes(newstartres, newstartres + width - 1);
+         // set the viewport y location to contain vis_y
+         int newstartseq = visY;
+         int height = getViewportHeight();
+         if (newstartseq + height - 1 > getVisibleAlignmentHeight() - 1)
+         {
+           newstartseq = getVisibleAlignmentHeight() - height;
+         }
+         updateStartEndSeq(newstartseq, newstartseq + height - 1);
+         newresseq = new int[] { startRes, startSeq };
+       }
+       changedLocation = true;
+       changeSupport.firePropertyChange(MOVE_VIEWPORT, old, newresseq);
+     }
+     return changedLocation;
+   }
+   /**
     * Adjust sequence position for page up. Fires a property change event.
     */
    public void pageUp()