X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fdatamodel%2FHiddenColumnsCursor.java;h=d6b6c10d0059c870af672ea7474d508fca1f7f61;hb=57738a1f3c19b1c3a00bd3ac5108f8cd0af32f99;hp=9efcc0b5d5c1623d1e084de6603f01459e244a0f;hpb=2ae1f76a9c13f23ba553500fea0e58ec920830e5;p=jalview.git diff --git a/src/jalview/datamodel/HiddenColumnsCursor.java b/src/jalview/datamodel/HiddenColumnsCursor.java index 9efcc0b..d6b6c10 100644 --- a/src/jalview/datamodel/HiddenColumnsCursor.java +++ b/src/jalview/datamodel/HiddenColumnsCursor.java @@ -1,5 +1,26 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ package jalview.datamodel; +import java.util.ArrayList; import java.util.List; public class HiddenColumnsCursor @@ -7,180 +28,185 @@ public class HiddenColumnsCursor // absolute position of first hidden column private int firstColumn; - // absolute position of last hidden column - private int lastColumn; + private List hiddenColumns = new ArrayList<>(); - // index of last visited region - private int regionIndex; + private HiddenCursorPosition cursorPos = new HiddenCursorPosition(0, 0); - // number of hidden columns before last visited region - private int hiddenSoFar; + protected HiddenColumnsCursor() + { - private List hiddenColumns; + } - protected HiddenColumnsCursor() + protected HiddenColumnsCursor(List hiddenCols) { + resetCursor(hiddenCols, 0, 0); + } + protected HiddenColumnsCursor(List hiddenCols, int index, + int hiddencount) + { + resetCursor(hiddenCols, index, hiddencount); } /** - * Set the cursor to a position + * Reset the cursor with a new hidden columns collection, where we know in + * advance the index and hidden columns count of a particular location. * - * @param first - * absolute position of first hidden column - * @param last - * absolute position of last hidden column + * @param hiddenCols + * new hidden columns collection * @param index - * index of last visited region - * @param hiddenCount - * number of hidden columns before last visited region + * cursor index to reset to + * @param hiddencount + * hidden columns count to reset to */ - protected void resetCursor(List hiddenCols) - { - synchronized (this) - { - if ((hiddenCols != null) && (!hiddenCols.isEmpty())) - { - hiddenColumns = hiddenCols; - firstColumn = hiddenColumns.get(0)[0]; - lastColumn = hiddenColumns.get(hiddenColumns.size() - 1)[1]; - regionIndex = 0; - hiddenSoFar = 0; - } - } - } - - protected void updateCursor(int index, int hiddenCount) + private void resetCursor(List hiddenCols, int index, + int hiddencount) { - synchronized (this) + hiddenColumns = hiddenCols; + if (!hiddenCols.isEmpty()) { - regionIndex = index; - hiddenSoFar = hiddenCount; + firstColumn = hiddenColumns.get(0)[0]; + cursorPos = new HiddenCursorPosition(index, hiddencount); } } - protected synchronized int getIndex() - { - return regionIndex; - } - - protected synchronized int getHiddenSoFar() - { - return hiddenSoFar; - } - - /** - * Get the index of the 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, will return size of hiddenColumns. If hidden - * columns is empty returns -1. + * 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 - * absolute position of a column in the alignment - * @return region index + * index of column in visible or absolute coordinates + * @param useVisible + * true if column is in visible coordinates, false if absolute + * @return cursor pointing to hidden region containing the column (if hidden) + * or to the right of the column (if visible) */ - protected int findRegionForColumn(int column) + protected HiddenCursorPosition findRegionForColumn(int column, + boolean useVisible) { - if (hiddenColumns == null) + if (hiddenColumns.isEmpty()) { - return -1; + return null; } - int index = regionIndex; - int hiddenCount = hiddenSoFar; + // used to add in hiddenColumns offset when working with visible columns + int offset = (useVisible ? 1 : 0); - if (index == hiddenColumns.size()) - { - // went past the end of hiddenColumns collection last time - index--; - int[] region = hiddenColumns.get(index); - hiddenCount -= region[1] - region[0] + 1; - } + HiddenCursorPosition pos = cursorPos; + int index = pos.getRegionIndex(); + int hiddenCount = pos.getHiddenSoFar(); - if ((hiddenColumns.get(index)[0] <= column) - && hiddenColumns.get(index)[1] >= column) - { - // column is in the current region - // we hit the jackpot - // don't need to move index - } - else if (column < firstColumn) + if (column < firstColumn) { - index = 0; - hiddenCount = 0; + pos = new HiddenCursorPosition(0, 0); } + // column is after current region - else if (column > hiddenColumns.get(index)[1]) // includes if column > - // lastColumn + else if ((index < hiddenColumns.size()) + && (hiddenColumns.get(index)[0] <= column + + offset * hiddenCount)) { // iterate from where we are now, if we're lucky we'll be close by // (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()) - && (column > hiddenColumns.get(index)[1])) - { - int[] region = hiddenColumns.get(index); - hiddenCount += region[1] - region[0] + 1; - index++; - } + pos = searchForward(pos, column, useVisible); } // column is before current region - else if (column < hiddenColumns.get(index)[0]) + else { - while ((index > 0) && (hiddenColumns.get(index)[1] > column)) - { - index--; - int[] region = hiddenColumns.get(index); - hiddenCount -= region[1] - region[0] + 1; - } + pos = searchBackward(pos, column, useVisible); } - updateCursor(index, hiddenCount); - return index; + cursorPos = pos; + return pos; } - protected int getHiddenOffset(int column) + /** + * 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) { - if (hiddenColumns == null) - { - return -1; - } - - int index = getIndex(); - int hiddenCount = getHiddenSoFar(); - - if (column < firstColumn) + HiddenCursorPosition p = pos; + if (useVisible) { - index = 0; - hiddenCount = 0; - } - else if ((index < hiddenColumns.size()) - && (hiddenColumns.get(index)[0] <= column + hiddenCount)) - { - // iterate from where we are now, if we're lucky we'll be close by - // (but still better than iterating from 0) - while ((index < hiddenColumns.size()) - && (hiddenColumns.get(index)[0] <= column + hiddenCount)) + while ((p.getRegionIndex() < hiddenColumns.size()) + && hiddenColumns.get(p.getRegionIndex())[0] <= column + + p.getHiddenSoFar()) { - int[] region = hiddenColumns.get(index); - hiddenCount += region[1] - region[0] + 1; - index++; + p = stepForward(p); } } - else if (index < hiddenColumns.size()) + else { - while ((index > 0) - && (hiddenColumns.get(index - 1)[1] >= column + hiddenCount)) + while ((p.getRegionIndex() < hiddenColumns.size()) + && hiddenColumns.get(p.getRegionIndex())[1] < column) { - index--; - int[] region = hiddenColumns.get(index); - hiddenCount -= region[1] - region[0] + 1; + 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); + + while ((i > 0) && (hiddenColumns.get(i - 1)[1] >= column + offset * h)) + { + i--; + int[] region = hiddenColumns.get(i); + h -= region[1] - region[0] + 1; } - updateCursor(index, hiddenCount); - return hiddenCount; + return new HiddenCursorPosition(i, h); } + }