Merge branch 'develop' into feature/JAL-2611
authorkiramt <k.mourao@dundee.ac.uk>
Sat, 22 Jul 2017 09:18:41 +0000 (11:18 +0200)
committerkiramt <k.mourao@dundee.ac.uk>
Sat, 22 Jul 2017 09:18:41 +0000 (11:18 +0200)
Conflicts:
src/jalview/gui/OverviewPanel.java
src/jalview/viewmodel/OverviewDimensionsHideHidden.java
src/jalview/viewmodel/OverviewDimensionsShowHidden.java

1  2 
src/jalview/appletgui/OverviewPanel.java
src/jalview/datamodel/HiddenSequences.java
src/jalview/gui/OverviewPanel.java
src/jalview/viewmodel/OverviewDimensions.java
src/jalview/viewmodel/OverviewDimensionsHideHidden.java
src/jalview/viewmodel/OverviewDimensionsShowHidden.java

@@@ -29,7 -29,6 +29,7 @@@ import jalview.viewmodel.ViewportListen
  
  import java.awt.BorderLayout;
  import java.awt.CheckboxMenuItem;
 +import java.awt.Cursor;
  import java.awt.Dimension;
  import java.awt.Panel;
  import java.awt.PopupMenu;
@@@ -58,8 -57,6 +58,8 @@@ public class OverviewPanel extends Pane
  
    private boolean updateRunning = false;
  
 +  private boolean draggingBox = false;
 +
    public OverviewPanel(AlignmentPanel alPanel)
    {
      this.av = alPanel.av;
    @Override
    public void mouseMoved(MouseEvent evt)
    {
 +    if (od.isPositionInBox(evt.getX(), evt.getY()))
 +    {
 +      // display drag cursor at mouse position
 +      setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
 +    }
 +    else
 +    {
 +      // reset cursor
 +      setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
 +    }
    }
  
    @Override
    public void mousePressed(MouseEvent evt)
    {
 -    mouseAction(evt);
 +    if ((evt.getModifiers()
 +            & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
 +    {
 +      if (!Platform.isAMac())
 +      {
 +        showPopupMenu(evt);
 +      }
 +    }
 +    else
 +    {
 +      if (!od.isPositionInBox(evt.getX(), evt.getY()))
 +      {
 +        // don't do anything if the mouse press is in the overview's box
 +        // (wait to see if it's a drag instead)
 +        // otherwise update the viewport
 +        od.updateViewportFromMouse(evt.getX(), evt.getY(),
 +                av.getAlignment().getHiddenSequences(),
 +                av.getAlignment().getHiddenColumns());
 +      }
 +      else
 +      {
 +        draggingBox = true;
 +        od.setDragPoint(evt.getX(), evt.getY(),
 +                av.getAlignment().getHiddenSequences(),
 +                av.getAlignment().getHiddenColumns());
 +      }
 +    }
    }
  
    @Override
    public void mouseReleased(MouseEvent evt)
    {
 -    mouseAction(evt);
 +    if (draggingBox)
 +    {
 +      draggingBox = false;
 +    }
    }
  
    @Override
    public void mouseDragged(MouseEvent evt)
    {
 -    mouseAction(evt);
 -  }
 -
 -  private void mouseAction(MouseEvent evt)
 -  {
      if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK)
      {
        if (!Platform.isAMac())
      }
      else
      {
 -      od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment()
 -              .getHiddenSequences(), av.getAlignment().getHiddenColumns());
 +      if (draggingBox)
 +      {
 +        // set the mouse position as a fixed point in the box
 +        // and drag relative to that position
 +        od.adjustViewportFromMouse(evt.getX(), evt.getY(),
 +                av.getAlignment().getHiddenSequences(),
 +                av.getAlignment().getHiddenColumns());
 +      }
 +      else
 +      {
 +        od.updateViewportFromMouse(evt.getX(), evt.getY(),
 +                av.getAlignment().getHiddenSequences(),
 +                av.getAlignment().getHiddenColumns());
 +      }
        ap.paintAlignment(false);
      }
    }
     */
    public void updateOverviewImage()
    {
+     if (oviewCanvas == null)
+     {
+       /*
+        * panel has been disposed
+        */
+       return;
+     }
      if ((getSize().width > 0) && (getSize().height > 0))
      {
        od.setWidth(getSize().width);
      oviewCanvas.resetOviewDims(od);
      updateOverviewImage();
    }
+   /**
+    * Removes this object as a property change listener, and nulls references
+    */
+   protected void dispose()
+   {
+     try
+     {
+       av.getRanges().removePropertyChangeListener(this);
+     } finally
+     {
+       av = null;
+       oviewCanvas = null;
+       ap = null;
+       od = null;
+     }
+   }
  }
@@@ -157,9 -157,10 +157,10 @@@ public class HiddenSequence
      int absAlignmentIndex = alignment.findIndex(sequence);
      int alignmentIndex = adjustForHiddenSeqs(absAlignmentIndex);
  
-     if (hiddenSequences[alignmentIndex] != null)
+     if (alignmentIndex < 0 || hiddenSequences[alignmentIndex] != null)
      {
        System.out.println("ERROR!!!!!!!!!!!");
+       return;
      }
  
      hiddenSequences[alignmentIndex] = sequence;
    }
  
    /**
-    * Convert absolute alignment index to visible alignment index
+    * Convert absolute alignment index to visible alignment index (or -1 if
+    * before the first visible sequence)
     * 
     * @param alignmentIndex
     * @return
        return startRow - visibleDistance;
      }
  
 -    int index = startRow;
 +    int index = Math.min(startRow, hiddenSequences.length - 1);
      int count = 0;
      while ((index > -1) && (count < visibleDistance))
      {
@@@ -28,7 -28,6 +28,7 @@@ import jalview.viewmodel.OverviewDimens
  import jalview.viewmodel.ViewportListenerI;
  
  import java.awt.BorderLayout;
 +import java.awt.Cursor;
  import java.awt.Dimension;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
@@@ -66,8 -65,6 +66,8 @@@ public class OverviewPanel extends JPan
  
    private boolean showHidden = true;
  
 +  private boolean draggingBox = false;
 +
    /**
     * Creates a new OverviewPanel object.
     * 
        @Override
        public void mouseDragged(MouseEvent evt)
        {
-         if (!SwingUtilities.isRightMouseButton(evt)
-                 && !av.getWrapAlignment())
+         if (!SwingUtilities.isRightMouseButton(evt))
          {
 -          od.updateViewportFromMouse(evt.getX(), evt.getY(), av
 +          if (draggingBox)
 +          {
 +            // set the mouse position as a fixed point in the box
 +            // and drag relative to that position
 +            od.adjustViewportFromMouse(evt.getX(),
 +                    evt.getY(), av.getAlignment().getHiddenSequences(),
 +                    av.getAlignment().getHiddenColumns());
 +          }
 +          else
 +          {
 +            od.updateViewportFromMouse(evt.getX(), evt.getY(), av
                    .getAlignment().getHiddenSequences(), av.getAlignment()
                    .getHiddenColumns());
 +          }
 +        }
 +      }
 +
 +      @Override
 +      public void mouseMoved(MouseEvent evt)
 +      {
 +        if (od.isPositionInBox(evt.getX(), evt.getY()))
 +        {
 +          // display drag cursor at mouse position
 +          setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
 +        }
 +        else
 +        {
 +          // reset cursor
 +          setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
          }
        }
      });
              showPopupMenu(evt);
            }
          }
-         else if (!av.getWrapAlignment())
+         else
+         // if (!av.getWrapAlignment())
          {
 -          od.updateViewportFromMouse(evt.getX(), evt.getY(), av
 -                  .getAlignment().getHiddenSequences(), av.getAlignment()
 -                  .getHiddenColumns());
 +          if (!od.isPositionInBox(evt.getX(), evt.getY()))
 +          {
 +            // don't do anything if the mouse press is in the overview's box
 +            // (wait to see if it's a drag instead)
 +            // otherwise update the viewport
 +            od.updateViewportFromMouse(evt.getX(), evt.getY(),
 +                    av.getAlignment().getHiddenSequences(),
 +                    av.getAlignment().getHiddenColumns());
 +          }
 +          else
 +          {
 +            draggingBox = true;
 +            od.setDragPoint(evt.getX(), evt.getY(),
 +                    av.getAlignment().getHiddenSequences(),
 +                    av.getAlignment().getHiddenColumns());
 +          }
 +        }
 +      }
 +
 +      @Override
 +      public void mouseReleased(MouseEvent evt)
 +      {
 +        if (draggingBox)
 +        {
 +          draggingBox = false;
          }
        }
  
            showPopupMenu(evt);
          }
        }
      });
  
      updateOverviewImage();
     */
    public void updateOverviewImage()
    {
+     if (oviewCanvas == null)
+     {
+       /*
+        * panel has been disposed
+        */
+       return;
+     }
      if ((getWidth() > 0) && (getHeight() > 0))
      {
        od.setWidth(getWidth());
      Thread thread = new Thread(this);
      thread.start();
      repaint();
    }
  
    @Override
    {
      setBoxPosition();
    }
+   /**
+    * Removes this object as a property change listener, and nulls references
+    */
+   protected void dispose()
+   {
+     try
+     {
+       av.getRanges().removePropertyChangeListener(this);
+     } finally
+     {
+       av = null;
+       oviewCanvas = null;
+       ap = null;
+       od = null;
+     }
+   }
  }
@@@ -192,44 -192,6 +192,44 @@@ public abstract class OverviewDimension
            HiddenSequences hiddenSeqs, HiddenColumns hiddenCols);
  
    /**
 +   * Update the viewport location from a mouse drag within the overview's box
 +   * 
 +   * @param mousex
 +   *          x location of mouse
 +   * @param mousey
 +   *          y location of mouse
 +   * @param hiddenSeqs
 +   *          the alignment's hidden sequences
 +   * @param hiddenCols
 +   *          the alignment's hidden columns
 +   */
 +  public abstract void adjustViewportFromMouse(int mousex, int mousey,
 +          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols);
 +
 +  /**
 +   * Initialise dragging from the mouse - must be called on initial mouse click
 +   * before using adjustViewportFromMouse in drag operations
 +   * 
 +   * @param mousex
 +   *          x location of mouse
 +   * @param mousey
 +   *          y location of mouse
 +   * @param hiddenSeqs
 +   *          the alignment's hidden sequences
 +   * @param hiddenCols
 +   *          the alignment's hidden columns
 +   */
 +  public abstract void setDragPoint(int x, int y,
 +          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols);
 +
 +  /*
 +   * Move the viewport so that the top left corner of the overview's box 
 +   * is at the mouse position (leftx, topy)
 +   */
 +  protected abstract void updateViewportFromTopLeft(int leftx, int topy,
 +          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols);
 +
 +  /**
     * Set the overview panel's box position to match the viewport
     * 
     * @param hiddenSeqs
     */
    protected abstract void resetAlignmentDims();
  
 +  /*
 +   * Given the box coordinates in residues and sequences, set the box dimensions in the overview window
 +   */
    protected void setBoxPosition(int startRes, int startSeq, int vpwidth,
            int vpheight)
    {
      resetAlignmentDims();
  
      // boxX, boxY is the x,y location equivalent to startRes, startSeq
-     boxX = Math.round((float) startRes * width / alwidth);
+     int xPos = Math.min(startRes, alwidth - vpwidth + 1);
+     boxX = Math.round((float) xPos * width / alwidth);
      boxY = Math.round((float) startSeq * sequencesHeight / alheight);
  
      // boxWidth is the width in residues translated to pixels
      // boxHeight is the height in sequences translated to pixels
      boxHeight = Math.round((float) vpheight * sequencesHeight / alheight);
    }
 +
 +  /**
 +   * Answers if a mouse position is in the overview's red box
 +   * 
 +   * @param x
 +   *          mouse x position
 +   * @param y
 +   *          mouse y position
 +   * @return true if (x,y) is inside the box
 +   */
 +  public boolean isPositionInBox(int x, int y)
 +  {
 +    return (x > boxX && y > boxY && x < boxX + boxWidth
 +            && y < boxY + boxHeight);
 +  }
 +
 +  /*
 +   * Given the centre x position, calculate the box's left x position
 +   */
 +  protected abstract int getLeftXFromCentreX(int mousex, HiddenColumns hidden);
 +
 +  /*
 +   * Given the centre y position, calculate the box's top y position
 +   */
 +  protected abstract int getTopYFromCentreY(int mousey,
 +          HiddenSequences hidden);
 +
  }
@@@ -12,12 -12,6 +12,12 @@@ public class OverviewDimensionsHideHidd
  {
    private ViewportRanges ranges;
  
 +  private int xdiff; // when dragging, difference in alignment units between
 +                     // start residue and original mouse click position
 +
 +  private int ydiff; // when dragging, difference in alignment units between
 +                     // start sequence and original mouse click position
 +
    public OverviewDimensionsHideHidden(ViewportRanges vpranges,
            boolean showAnnotationPanel)
    {
    public void updateViewportFromMouse(int mousex, int mousey,
            HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
    {
 -    resetAlignmentDims();
 +    int xAsRes = getLeftXFromCentreX(mousex, hiddenCols);
 +    int yAsSeq = getTopYFromCentreY(mousey, hiddenSeqs);
 +
 +    updateViewportFromTopLeft(xAsRes, yAsSeq, hiddenSeqs, hiddenCols);
 +
 +  }
 +
 +  @Override
 +  public void adjustViewportFromMouse(int mousex, int mousey,
 +          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
 +  {
 +    // calculate translation in pixel terms:
 +    // get mouse location in viewport coords, add translation in viewport
 +    // coords, and update viewport as usual
 +    int vpx = Math.round((float) mousex * alwidth / width);
 +    int vpy = Math.round((float) mousey * alheight / sequencesHeight);
  
 -    int x = mousex;
 -    int y = mousey;
 +    updateViewportFromTopLeft(vpx + xdiff, vpy + ydiff, hiddenSeqs,
 +            hiddenCols);
  
 -    if (x < 0)
 +  }
 +
 +  @Override
 +  protected void updateViewportFromTopLeft(int leftx, int topy,
 +          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
 +  {
 +    int xAsRes = leftx;
 +    int yAsSeq = topy;
 +    resetAlignmentDims();
 +
 +    if (xAsRes < 0)
      {
 -      x = 0;
 +      xAsRes = 0;
      }
  
 -    if (y < 0)
 +    if (yAsSeq < 0)
      {
 -      y = 0;
 +      yAsSeq = 0;
      }
  
-     // Determine where scrollCol should be, given visXAsRes
+     if (ranges.isWrappedMode())
+     {
 -      y = 0; // sorry, no vertical scroll when wrapped
++      yAsSeq = 0; // sorry, no vertical scroll when wrapped
+     }
  
 -    //
 -    // Convert x value to residue position
 -    //
 -
 -    // need to determine where scrollCol should be, given x
 -    // to do this also need to know width of viewport, and some hidden column
 -    // correction
 -
 -    // convert x to residues - this is an absolute position
 -    int xAsRes = Math.round((float) x * alwidth / width);
 -
      // get viewport width in residues
      int vpwidth = ranges.getViewportWidth();
  
        }
      }
  
 -
 -    //
 -    // Convert y value to sequence position
 -    //
 -
 -    // convert y to residues
 -    int yAsSeq = Math.round((float) y * alheight / sequencesHeight);
 +    // Determine where scrollRow should be, given visYAsSeq
  
      // get viewport height in sequences
      // add 1 because height includes both endSeq and startSeq
      // update viewport
      ranges.setStartRes(xAsRes);
      ranges.setStartSeq(yAsSeq);
 -
    }
  
    @Override
      alwidth = ranges.getVisibleAlignmentWidth();
      alheight = ranges.getVisibleAlignmentHeight();
    }
 +
 +  @Override
 +  protected int getLeftXFromCentreX(int mousex, HiddenColumns hidden)
 +  {
 +    int vpx = Math.round((float) mousex * alwidth / width);
 +    return vpx - ranges.getViewportWidth() / 2;
 +  }
 +
 +  @Override
 +  protected int getTopYFromCentreY(int mousey, HiddenSequences hidden)
 +  {
 +    int vpy = Math.round((float) mousey * alheight / sequencesHeight);
 +    return vpy - ranges.getViewportHeight() / 2;
 +  }
 +
 +  @Override
 +  public void setDragPoint(int x, int y, HiddenSequences hiddenSeqs,
 +          HiddenColumns hiddenCols)
 +  {
 +    // get alignment position of x and box (can get directly from vpranges) and
 +    // calculate difference between the positions
 +    int vpx = Math.round((float) x * alwidth / width);
 +    int vpy = Math.round((float) y * alheight / sequencesHeight);
 +
 +    xdiff = ranges.getStartRes() - vpx;
 +    ydiff = ranges.getStartSeq() - vpy;
 +  }
 +
  }
@@@ -32,12 -32,6 +32,12 @@@ public class OverviewDimensionsShowHidd
  {
    private ViewportRanges ranges;
  
 +  private int xdiff; // when dragging, difference in alignment units between
 +                     // start residue and original mouse click position
 +
 +  private int ydiff; // when dragging, difference in alignment units between
 +                     // start sequence and original mouse click position
 +
    /**
     * Create an OverviewDimensions object
     * 
    public void updateViewportFromMouse(int mousex, int mousey,
            HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
    {
 -    int x = mousex;
 -    int y = mousey;
 +    // convert mousex and mousey to alignment units as well as
 +    // translating to top left corner of viewport - this is an absolute position
 +    int xAsRes = getLeftXFromCentreX(mousex, hiddenCols);
 +    int yAsSeq = getTopYFromCentreY(mousey, hiddenSeqs);
  
 -    resetAlignmentDims();
 +    // convert to visible positions
 +    int visXAsRes = hiddenCols.findColumnPosition(xAsRes);
 +    yAsSeq = hiddenSeqs.adjustForHiddenSeqs(
 +            hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq));
++    yAsSeq = Math.max(yAsSeq, 0); // -1 if before first visible sequence
 +    int visYAsSeq = hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq);
++    visYAsSeq = Math.max(visYAsSeq, 0); // -1 if before first visible sequence
  
 -    if (x < 0)
 -    {
 -      x = 0;
 -    }
 +    // update viewport accordingly
 +    updateViewportFromTopLeft(visXAsRes, visYAsSeq, hiddenSeqs, hiddenCols);
 +  }
 +
 +  @Override
 +  public void adjustViewportFromMouse(int mousex, int mousey,
 +          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
 +  {
 +    // calculate translation in pixel terms:
 +    // get mouse location in viewport coords, add translation in viewport
 +    // coords,
 +    // convert back to pixel coords
 +    int vpx = Math.round((float) mousex * alwidth / width);
 +    int visXAsRes = hiddenCols.findColumnPosition(vpx) + xdiff;
 +
 +    int vpy = Math.round((float) mousey * alheight / sequencesHeight);
 +    int visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(vpy) + ydiff;
 +
 +    // update viewport accordingly
 +    updateViewportFromTopLeft(visXAsRes, visYAsRes,
 +            hiddenSeqs,
 +            hiddenCols);
 +  }
 +
 +  @Override
 +  protected void updateViewportFromTopLeft(int leftx, int topy,
 +          HiddenSequences hiddenSeqs, HiddenColumns hiddenCols)
 +  {
 +    int visXAsRes = leftx;
 +    int visYAsSeq = topy;
 +    resetAlignmentDims();
  
 -    if (y < 0)
 +    if (visXAsRes < 0)
      {
 -      y = 0;
 +      visXAsRes = 0;
      }
  
 -    if (ranges.isWrappedMode())
 +    if (visYAsSeq < 0)
      {
 -      y = 0; // sorry, no vertical scroll when wrapped
 +      visYAsSeq = 0;
      }
  
 -    //
 -    // Convert x value to residue position
 -    //
 -
 -    // need to determine where scrollCol should be, given x
 -    // to do this also need to know width of viewport, and some hidden column
 -    // correction
 -
 -    // convert x to residues - this is an absolute position
 -    int xAsRes = Math.round((float) x * alwidth / width);
 +    // Determine where scrollCol should be, given visXAsRes
  
      // get viewport width in residues
      int vpwidth = ranges.getViewportWidth();
  
 -    // get where x should be when accounting for hidden cols
 -    // if x is in a hidden col region, shift to left - but we still need
 -    // absolute position
 -    // so convert back after getting visible region position
 -    int visXAsRes = hiddenCols.findColumnPosition(xAsRes);
 -
      // check in case we went off the edge of the alignment
      int visAlignWidth = hiddenCols.findColumnPosition(alwidth - 1);
      if (visXAsRes + vpwidth - 1 > visAlignWidth)
        }
      }
  
 -    //
 -    // Convert y value to sequence position
 -    //
 -
 -    // convert y to residues
 -    int yAsSeq = Math.round((float) y * alheight / sequencesHeight);
 +    // Determine where scrollRow should be, given visYAsSeq
  
      // get viewport height in sequences
      int vpheight = ranges.getViewportHeight();
  
 -    // get where y should be when accounting for hidden rows
 -    // if y is in a hidden row region, shift up - but we still need absolute
 -    // position,
 -    // so convert back after getting visible region position
 -    yAsSeq = hiddenSeqs.adjustForHiddenSeqs(hiddenSeqs
 -            .findIndexWithoutHiddenSeqs(yAsSeq));
 -    yAsSeq = Math.max(yAsSeq, 0); // -1 if before first visible sequence
 -
      // check in case we went off the edge of the alignment
      int visAlignHeight = hiddenSeqs.findIndexWithoutHiddenSeqs(alheight);
 -    int visYAsSeq = hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq);
 -    visYAsSeq = Math.max(visYAsSeq, 0); // -1 if before first visible sequence
 +
      if (visYAsSeq + vpheight - 1 > visAlignHeight)
      {
        // went past the end of the alignment, adjust backwards
      alwidth = ranges.getAbsoluteAlignmentWidth();
      alheight = ranges.getAbsoluteAlignmentHeight();
    }
 +
 +  @Override
 +  protected int getLeftXFromCentreX(int mousex, HiddenColumns hidden)
 +  {
 +    int vpx = Math.round((float) mousex * alwidth / width);
 +    return hidden.subtractVisibleColumns(ranges.getViewportWidth() / 2,
 +            vpx);
 +  }
 +
 +  @Override
 +  protected int getTopYFromCentreY(int mousey, HiddenSequences hidden)
 +  {
 +    int vpy = Math.round((float) mousey * alheight / sequencesHeight);
 +    return hidden.subtractVisibleRows(ranges.getViewportHeight() / 2, vpy);
 +  }
 +
 +  @Override
 +  public void setDragPoint(int x, int y, HiddenSequences hiddenSeqs,
 +          HiddenColumns hiddenCols)
 +  {
 +    // get alignment position of x and box (can get directly from vpranges) and
 +    // calculate difference between the positions
 +    int vpx = Math.round((float) x * alwidth / width);
 +    int vpy = Math.round((float) y * alheight / sequencesHeight);
 +
 +    xdiff = ranges.getStartRes() - hiddenCols.findColumnPosition(vpx);
 +    ydiff = ranges.getStartSeq()
 +            - hiddenSeqs.findIndexWithoutHiddenSeqs(vpy);
 +  }
 +
  }