From bab5165f5108cab3cce5b93b60f9ad83b7031b1c Mon Sep 17 00:00:00 2001 From: kiramt Date: Tue, 30 Jan 2018 14:45:24 +0000 Subject: [PATCH] JAL-2759 Rationalising hidden cols cursor, and sorting out coverage --- src/jalview/datamodel/HiddenColumns.java | 2 +- src/jalview/datamodel/HiddenColumnsCursor.java | 166 +++++++++++--------- .../jalview/datamodel/HiddenColumnsCursorTest.java | 53 ++++++- 3 files changed, 147 insertions(+), 74 deletions(-) diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java index 6c08cdc..0b66b07 100644 --- a/src/jalview/datamodel/HiddenColumns.java +++ b/src/jalview/datamodel/HiddenColumns.java @@ -395,7 +395,7 @@ public class HiddenColumns hiddenColumns.remove(regionIndex); numColumns -= colsToRemove; - cursor.updateForDeletedRegion(hiddenColumns); + cursor.updateForDeletedRegion(hiddenColumns, colsToRemove); } } } diff --git a/src/jalview/datamodel/HiddenColumnsCursor.java b/src/jalview/datamodel/HiddenColumnsCursor.java index 89c4f99..572f999 100644 --- a/src/jalview/datamodel/HiddenColumnsCursor.java +++ b/src/jalview/datamodel/HiddenColumnsCursor.java @@ -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 hiddenCols) + protected void updateForDeletedRegion(List 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); } } diff --git a/test/jalview/datamodel/HiddenColumnsCursorTest.java b/test/jalview/datamodel/HiddenColumnsCursorTest.java index 3b1bc55..dc627bc 100644 --- a/test/jalview/datamodel/HiddenColumnsCursorTest.java +++ b/test/jalview/datamodel/HiddenColumnsCursorTest.java @@ -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 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 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 hlist2 = new ArrayList<>(); + hlist2.add(new int[] { 3, 7 }); + cursor.updateForDeletedRegion(hlist2, 11); + p = cursor.findRegionForColumn(30, false); + assertEquals(5, p.getHiddenSoFar()); + } + } -- 1.7.10.2