/* * 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 { // absolute position of first hidden column private int firstColumn; private List hiddenColumns = new ArrayList<>(); private HiddenCursorPosition cursorPos = new HiddenCursorPosition(0, 0); protected HiddenColumnsCursor() { } protected HiddenColumnsCursor(List hiddenCols) { resetCursor(hiddenCols, 0, 0); } protected HiddenColumnsCursor(List hiddenCols, int index, int hiddencount) { resetCursor(hiddenCols, index, hiddencount); } /** * 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 hiddenCols * new hidden columns collection * @param index * cursor index to reset to * @param hiddencount * hidden columns count to reset to */ private void resetCursor(List hiddenCols, int index, int hiddencount) { hiddenColumns = hiddenCols; if (!hiddenCols.isEmpty()) { firstColumn = hiddenColumns.get(0)[0]; cursorPos = new HiddenCursorPosition(index, hiddencount); } } /** * 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 * @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, boolean useVisible) { if (hiddenColumns.isEmpty()) { return null; } // used to add in hiddenColumns offset when working with visible columns int offset = (useVisible ? 1 : 0); HiddenCursorPosition pos = cursorPos; int index = pos.getRegionIndex(); int hiddenCount = pos.getHiddenSoFar(); if (column < firstColumn) { pos = new HiddenCursorPosition(0, 0); } // column is after current region 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 pos = searchForward(pos, column, useVisible); } // column is before current region else { 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()) { 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); while ((i > 0) && (hiddenColumns.get(i - 1)[1] >= column + offset * h)) { i--; int[] region = hiddenColumns.get(i); h -= region[1] - region[0] + 1; } return new HiddenCursorPosition(i, h); } }