JAL-2759 Rationalising hidden cols cursor, and sorting out coverage
authorkiramt <k.mourao@dundee.ac.uk>
Tue, 30 Jan 2018 14:45:24 +0000 (14:45 +0000)
committerkiramt <k.mourao@dundee.ac.uk>
Tue, 30 Jan 2018 14:45:24 +0000 (14:45 +0000)
src/jalview/datamodel/HiddenColumns.java
src/jalview/datamodel/HiddenColumnsCursor.java
test/jalview/datamodel/HiddenColumnsCursorTest.java

index 6c08cdc..0b66b07 100644 (file)
@@ -395,7 +395,7 @@ public class HiddenColumns
             hiddenColumns.remove(regionIndex);
             numColumns -= colsToRemove;
 
-            cursor.updateForDeletedRegion(hiddenColumns);
+            cursor.updateForDeletedRegion(hiddenColumns, colsToRemove);
           }
         }
       }
index 89c4f99..572f999 100644 (file)
@@ -80,29 +80,21 @@ public class HiddenColumnsCursor
    * require a writeLock the lock should already exist.
    *
    * @param hiddenCols
+   *          replacement list of hidden column regions
+   * @param remove
+   *          number of columns which were deleted
    */
-  protected void updateForDeletedRegion(List<int[]> hiddenCols)
+  protected void updateForDeletedRegion(List<int[]> hiddenCols, int remove)
   {
-
+    hiddenColumns = hiddenCols;
     if (!hiddenCols.isEmpty())
     {
-      // if there is a region to the right of the current region,
-      // nothing changes; otherwise
-      // we deleted the last region (index=hiddenCols.size()-1)
-      // or the index was at the end of the alignment (index=hiddenCols.size())
-      HiddenCursorPosition oldpos = cursorPos;
-
-      int index = oldpos.getRegionIndex();
-      if (index >= hiddenColumns.size() - 1)
+      if (cursorPos.getRegionIndex() >= hiddenCols.size())
       {
-        // deleted last region, index is now end of alignment
-        index = hiddenCols.size();
-
-        cursorPos = new HiddenCursorPosition(index,
-                oldpos.getHiddenSoFar());
+        cursorPos = new HiddenCursorPosition(hiddenCols.size(),
+                cursorPos.getHiddenSoFar() - remove);
       }
     }
-    hiddenColumns = hiddenCols;
   }
 
   /**
@@ -114,37 +106,6 @@ public class HiddenColumnsCursor
    * If hidden columns is empty returns null.
    * 
    * @param column
-   *          absolute position of a column in the alignment
-   * @return cursor pointing to hidden region containing the column (if hidden)
-   *         or to the right of the column (if visible)
-   */
-  /*protected HiddenCursorPosition findRegionForColumn(int column)
-  {
-    return findRegionForColumn(column, false);
-  }*/
-
-  /**
-   * Get the cursor pointing to the hidden region just after a visible column
-   * 
-   * @param column
-   *          index of column in *visible* alignment (therefore by definition
-   *          column is visible)
-   * @return cursor pointing to hidden region to the right of the column
-   */
-  /* protected HiddenCursorPosition findRegionForVisColumn(int column)
-  {
-    return findRegionForColumn(column, true);
-  }*/
-
-  /**
-   * Get the cursor pointing to the hidden region that column is within (if
-   * column is hidden) or which is to the right of column (if column is
-   * visible). If no hidden columns are to the right, returns a cursor pointing
-   * to an imaginary hidden region beyond the end of the hidden columns
-   * collection (this ensures the count of previous hidden columns is correct).
-   * If hidden columns is empty returns null.
-   * 
-   * @param column
    *          index of column in visible or absolute coordinates
    * @param useVisible
    *          true if column is in visible coordinates, false if absolute
@@ -162,14 +123,13 @@ public class HiddenColumnsCursor
     // used to add in hiddenColumns offset when working with visible columns
     int offset = (useVisible ? 1 : 0);
 
-    HiddenCursorPosition oldpos = cursorPos;
-    int index = oldpos.getRegionIndex();
-    int hiddenCount = oldpos.getHiddenSoFar();
+    HiddenCursorPosition pos = cursorPos;
+    int index = pos.getRegionIndex();
+    int hiddenCount = pos.getHiddenSoFar();
 
     if (column < firstColumn)
     {
-      index = 0;
-      hiddenCount = 0;
+      pos = new HiddenCursorPosition(0, 0);
     }
 
     // column is after current region
@@ -181,37 +141,99 @@ public class HiddenColumnsCursor
       // (but still better than iterating from 0)
       // stop when we find the region *before* column
       // i.e. the next region starts after column or if not, ends after column
-      while ((index < hiddenColumns.size())
-              && (((useVisible && hiddenColumns.get(index)[0] <= column
-                      + offset * hiddenCount))
-                      || (!useVisible
-                              && hiddenColumns.get(index)[1] < column)))
-      {
-        int[] region = hiddenColumns.get(index);
-        hiddenCount += region[1] - region[0] + 1;
-        index++;
-      }
+      pos = searchForward(pos, column, useVisible);
     }
 
     // column is before current region
     else
     {
-      // column is before or in the previous region
-      while ((index > 0) && (hiddenColumns.get(index - 1)[1] >= column
-              + offset * hiddenCount))
+      pos = searchBackward(pos, column, useVisible);
+    }
+    cursorPos = pos;
+    return pos;
+  }
+
+  /**
+   * Search forwards through the hidden columns collection to find the hidden
+   * region immediately before a column
+   * 
+   * @param pos
+   *          current position
+   * @param column
+   *          column to locate
+   * @param useVisible
+   *          whether using visible or absolute coordinates
+   * @return position of region before column
+   */
+  private HiddenCursorPosition searchForward(HiddenCursorPosition pos,
+          int column, boolean useVisible)
+  {
+    HiddenCursorPosition p = pos;
+    if (useVisible)
+    {
+      while ((p.getRegionIndex() < hiddenColumns.size())
+              && hiddenColumns.get(p.getRegionIndex())[0] <= column
+                      + p.getHiddenSoFar())
       {
-        index--;
-        int[] region = hiddenColumns.get(index);
-        hiddenCount -= region[1] - region[0] + 1;
+        p = stepForward(p);
       }
     }
+    else
+    {
+      while ((p.getRegionIndex() < hiddenColumns.size())
+              && hiddenColumns.get(p.getRegionIndex())[1] < column)
+      {
+        p = stepForward(p);
+      }
+    }
+    return p;
+  }
+
+  /**
+   * Move to the next (rightwards) hidden region after a given cursor position
+   * 
+   * @param p
+   *          current position of cursor
+   * @return new position of cursor at next region
+   */
+  private HiddenCursorPosition stepForward(HiddenCursorPosition p)
+  {
+    int[] region = hiddenColumns.get(p.getRegionIndex());
+
+    // increment the index, and add this region's hidden columns to the hidden
+    // column count
+    return new HiddenCursorPosition(p.getRegionIndex() + 1,
+            p.getHiddenSoFar() + region[1] - region[0] + 1);
+  }
+
+  /**
+   * Search backwards through the hidden columns collection to find the hidden
+   * region immediately before (left of) a given column
+   * 
+   * @param pos
+   *          current position
+   * @param column
+   *          column to locate
+   * @param useVisible
+   *          whether using visible or absolute coordinates
+   * @return position of region immediately to left of column
+   */
+  private HiddenCursorPosition searchBackward(HiddenCursorPosition p,
+          int column, boolean useVisible)
+  {
+    int i = p.getRegionIndex();
+    int h = p.getHiddenSoFar();
+
+    // used to add in hiddenColumns offset when working with visible columns
+    int offset = (useVisible ? 1 : 0);
 
-    if (index != oldpos.getRegionIndex()
-            || hiddenCount != oldpos.getHiddenSoFar())
+    while ((i > 0) && (hiddenColumns.get(i - 1)[1] >= column + offset * h))
     {
-      return new HiddenCursorPosition(index, hiddenCount);
+      i--;
+      int[] region = hiddenColumns.get(i);
+      h -= region[1] - region[0] + 1;
     }
-    return oldpos;
+    return new HiddenCursorPosition(i, h);
   }
 
 }
index 3b1bc55..dc627bc 100644 (file)
@@ -30,6 +30,31 @@ import org.testng.annotations.Test;
 
 public class HiddenColumnsCursorTest
 {
+
+  @Test(groups = { "Functional" })
+  public void testConstructor()
+  {
+    HiddenColumnsCursor cursor = new HiddenColumnsCursor();
+    assertNull(cursor.findRegionForColumn(0, false));
+
+    List<int[]> hlist = new ArrayList<>();
+    cursor = new HiddenColumnsCursor(hlist);
+    assertNull(cursor.findRegionForColumn(0, false));
+
+    cursor = new HiddenColumnsCursor(hlist, 3, 12);
+    assertNull(cursor.findRegionForColumn(0, false));
+
+    hlist.add(new int[] { 3, 7 });
+    hlist.add(new int[] { 15, 25 });
+    cursor = new HiddenColumnsCursor(hlist);
+    HiddenCursorPosition p = cursor.findRegionForColumn(8, false);
+    assertEquals(1, p.getRegionIndex());
+
+    cursor = new HiddenColumnsCursor(hlist, 1, 5);
+    p = cursor.findRegionForColumn(8, false);
+    assertEquals(1, p.getRegionIndex());
+  }
+
   /**
    * Test the method which finds the corresponding region given a column
    */
@@ -92,7 +117,7 @@ public class HiddenColumnsCursorTest
    * Test the method which counts the number of hidden columns before a column
    */
   @Test(groups = { "Functional" })
-  public void testGetHiddenOffset()
+  public void testFindRegionForColumn_Visible()
   {
     HiddenColumnsCursor cursor = new HiddenColumnsCursor();
 
@@ -130,4 +155,30 @@ public class HiddenColumnsCursorTest
     assertEquals(46, offset);
   }
 
+  /**
+   * Test the method which updates for a deleted region
+   */
+  @Test(groups = { "Functional" })
+  public void testUpdateForDeletedRegion()
+  {
+    List<int[]> hlist = new ArrayList<>();
+    HiddenColumnsCursor cursor = new HiddenColumnsCursor(hlist, 1, 5);
+    cursor.updateForDeletedRegion(hlist, 0);
+    assertNull(cursor.findRegionForColumn(30, false));
+
+    hlist.add(new int[] { 3, 7 });
+    hlist.add(new int[] { 15, 25 });
+
+    cursor = new HiddenColumnsCursor(hlist, 1, 5);
+
+    HiddenCursorPosition p = cursor.findRegionForColumn(30, false);
+    assertEquals(16, p.getHiddenSoFar());
+
+    List<int[]> hlist2 = new ArrayList<>();
+    hlist2.add(new int[] { 3, 7 });
+    cursor.updateForDeletedRegion(hlist2, 11);
+    p = cursor.findRegionForColumn(30, false);
+    assertEquals(5, p.getHiddenSoFar());
+  }
+
 }