X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fjalview%2Fdatamodel%2FHiddenColumns.java;h=c0a43eea64ba09df70ed8e5686e58334ecb772f0;hb=refs%2Fheads%2Fbug%2FJAL-2842;hp=96fff971d97c44dd4115c3994437785b93cabfbb;hpb=ce3d87d456ac70e1677909dc527eb548275e6daa;p=jalview.git
diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java
index 96fff97..c0a43ee 100644
--- a/src/jalview/datamodel/HiddenColumns.java
+++ b/src/jalview/datamodel/HiddenColumns.java
@@ -1,3 +1,23 @@
+/*
+ * 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 jalview.util.Comparison;
@@ -8,85 +28,158 @@ import java.util.BitSet;
import java.util.Collections;
import java.util.List;
import java.util.Vector;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
public class HiddenColumns
{
+ private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();
+
/*
* list of hidden column [start, end] ranges; the list is maintained in
* ascending start column order
*/
- private Vector hiddenColumns;
+ private ArrayList hiddenColumns;
+
+ /**
+ * Constructor
+ */
+ public HiddenColumns()
+ {
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param copy
+ */
+ public HiddenColumns(HiddenColumns copy)
+ {
+ try
+ {
+ LOCK.writeLock().lock();
+ if (copy != null)
+ {
+ if (copy.hiddenColumns != null)
+ {
+ hiddenColumns = copy.copyHiddenRegionsToArrayList();
+ }
+ }
+ } finally
+ {
+ LOCK.writeLock().unlock();
+ }
+ }
/**
- * This Method is used to return all the HiddenColumn regions
+ * This method is used to return all the HiddenColumn regions and is intended
+ * to remain private. External callers which need a copy of the regions can
+ * call getHiddenColumnsCopyAsList.
*
* @return empty list or List of hidden column intervals
*/
- public List getHiddenRegions()
+ private List getHiddenRegions()
{
return hiddenColumns == null ? Collections. emptyList()
: hiddenColumns;
}
/**
- * Find the number of hidden columns
+ * Output regions data as a string. String is in the format:
+ * reg0[0]reg0[1]reg1[0]reg1[1] ... regn[1]
*
- * @return number of hidden columns
+ * @param delimiter
+ * string to delimit regions
+ * @param betweenstring
+ * to put between start and end region values
+ * @return regions formatted according to delimiter and between strings
*/
- public int getSize()
+ public String regionsToString(String delimiter, String between)
{
- int size = 0;
- if (hasHidden())
+ try
{
- for (int[] range : hiddenColumns)
+ LOCK.readLock().lock();
+ StringBuilder regionBuilder = new StringBuilder();
+ if (hiddenColumns != null)
{
- size += range[1] - range[0] + 1;
+ for (int[] range : hiddenColumns)
+ {
+ regionBuilder.append(delimiter).append(range[0]).append(between)
+ .append(range[1]);
+ }
+
+ regionBuilder.deleteCharAt(0);
}
+ return regionBuilder.toString();
+ } finally
+ {
+ LOCK.readLock().unlock();
}
- return size;
}
/**
- * Answers if there are any hidden columns
+ * Find the number of hidden columns
*
- * @return true if there are hidden columns
+ * @return number of hidden columns
*/
- public boolean hasHidden()
+ public int getSize()
{
- return (hiddenColumns != null) && (!hiddenColumns.isEmpty());
+ try
+ {
+ LOCK.readLock().lock();
+ int size = 0;
+ if (hasHiddenColumns())
+ {
+ for (int[] range : hiddenColumns)
+ {
+ size += range[1] - range[0] + 1;
+ }
+ }
+ return size;
+ } finally
+ {
+ LOCK.readLock().unlock();
+ }
}
@Override
public boolean equals(Object obj)
{
- if (!(obj instanceof HiddenColumns))
+ try
{
- return false;
- }
- HiddenColumns that = (HiddenColumns) obj;
+ LOCK.readLock().lock();
- /*
- * check hidden columns are either both null, or match
- */
- if (this.hiddenColumns == null)
- {
- return (that.hiddenColumns == null);
- }
- if (that.hiddenColumns == null
- || that.hiddenColumns.size() != this.hiddenColumns.size())
- {
- return false;
- }
- int i = 0;
- for (int[] thisRange : hiddenColumns)
- {
- int[] thatRange = that.hiddenColumns.get(i++);
- if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1])
+ if (!(obj instanceof HiddenColumns))
{
return false;
}
+ HiddenColumns that = (HiddenColumns) obj;
+
+ /*
+ * check hidden columns are either both null, or match
+ */
+ if (this.hiddenColumns == null)
+ {
+ return (that.hiddenColumns == null);
+ }
+ if (that.hiddenColumns == null
+ || that.hiddenColumns.size() != this.hiddenColumns.size())
+ {
+ return false;
+ }
+ int i = 0;
+ for (int[] thisRange : hiddenColumns)
+ {
+ int[] thatRange = that.hiddenColumns.get(i++);
+ if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1])
+ {
+ return false;
+ }
+ }
+ return true;
+ } finally
+ {
+ LOCK.readLock().unlock();
}
- return true;
}
/**
@@ -98,19 +191,26 @@ public class HiddenColumns
*/
public int adjustForHiddenColumns(int column)
{
- int result = column;
- if (hiddenColumns != null)
+ try
{
- for (int i = 0; i < hiddenColumns.size(); i++)
+ LOCK.readLock().lock();
+ int result = column;
+ if (hiddenColumns != null)
{
- int[] region = hiddenColumns.elementAt(i);
- if (result >= region[0])
+ for (int i = 0; i < hiddenColumns.size(); i++)
{
- result += region[1] - region[0] + 1;
+ int[] region = hiddenColumns.get(i);
+ if (result >= region[0])
+ {
+ result += region[1] - region[0] + 1;
+ }
}
}
+ return result;
+ } finally
+ {
+ LOCK.readLock().unlock();
}
- return result;
}
/**
@@ -124,42 +224,52 @@ public class HiddenColumns
*/
public int findColumnPosition(int hiddenColumn)
{
- int result = hiddenColumn;
- if (hiddenColumns != null)
+ try
{
- int index = 0;
- int[] region;
- do
+ LOCK.readLock().lock();
+ int result = hiddenColumn;
+ if (hiddenColumns != null)
{
- region = hiddenColumns.elementAt(index++);
- if (hiddenColumn > region[1])
+ int index = 0;
+ int[] region;
+ do
{
- result -= region[1] + 1 - region[0];
- }
- } while ((hiddenColumn > region[1]) && (index < hiddenColumns.size()));
+ region = hiddenColumns.get(index++);
+ if (hiddenColumn > region[1])
+ {
+ result -= region[1] + 1 - region[0];
+ }
+ } while ((hiddenColumn > region[1])
+ && (index < hiddenColumns.size()));
- if (hiddenColumn >= region[0] && hiddenColumn <= region[1])
- {
- // Here the hidden column is within a region, so
- // we want to return the position of region[0]-1, adjusted for any
- // earlier hidden columns.
- // Calculate the difference between the actual hidden col position
- // and region[0]-1, and then subtract from result to convert result from
- // the adjusted hiddenColumn value to the adjusted region[0]-1 value
-
- // However, if the region begins at 0 we cannot return region[0]-1
- // just return 0
- if (region[0] == 0)
- {
- return 0;
- }
- else
+ if (hiddenColumn >= region[0] && hiddenColumn <= region[1])
{
- return result - (hiddenColumn - region[0] + 1);
+ // Here the hidden column is within a region, so
+ // we want to return the position of region[0]-1, adjusted for any
+ // earlier hidden columns.
+ // Calculate the difference between the actual hidden col position
+ // and region[0]-1, and then subtract from result to convert result
+ // from
+ // the adjusted hiddenColumn value to the adjusted region[0]-1 value
+
+ // However, if the region begins at 0 we cannot return region[0]-1
+ // just return 0
+ if (region[0] == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return result - (hiddenColumn - region[0] + 1);
+ }
}
}
+ return result; // return the shifted position after removing hidden
+ // columns.
+ } finally
+ {
+ LOCK.readLock().unlock();
}
- return result; // return the shifted position after removing hidden columns.
}
/**
@@ -175,81 +285,106 @@ public class HiddenColumns
*/
public int subtractVisibleColumns(int visibleDistance, int startColumn)
{
- int distance = visibleDistance;
+ try
+ {
- // in case startColumn is in a hidden region, move it to the left
- int start = adjustForHiddenColumns(findColumnPosition(startColumn));
+ LOCK.readLock().lock();
+ int distance = visibleDistance;
- // get index of hidden region to left of start
- int index = getHiddenIndexLeft(start);
- if (index == -1)
- {
- // no hidden regions to left of startColumn
- return start - distance;
- }
+ // in case startColumn is in a hidden region, move it to the left
+ int start = adjustForHiddenColumns(findColumnPosition(startColumn));
- // walk backwards through the alignment subtracting the counts of visible
- // columns from distance
- int[] region;
- int gap = 0;
- int nextstart = start;
+ // get index of hidden region to left of start
+ int index = getHiddenIndexLeft(start);
+ if (index == -1)
+ {
+ // no hidden regions to left of startColumn
+ return start - distance;
+ }
- while ((index > -1) && (distance - gap > 0))
- {
- // subtract the gap to right of region from distance
- distance -= gap;
- start = nextstart;
+ // walk backwards through the alignment subtracting the counts of visible
+ // columns from distance
+ int[] region;
+ int gap = 0;
+ int nextstart = start;
- // calculate the next gap
- region = hiddenColumns.get(index);
- gap = start - region[1];
+ while ((index > -1) && (distance - gap > 0))
+ {
+ // subtract the gap to right of region from distance
+ distance -= gap;
+ start = nextstart;
- // set start to just to left of current region
- nextstart = region[0] - 1;
- index--;
- }
+ // calculate the next gap
+ region = hiddenColumns.get(index);
+ gap = start - region[1];
+
+ // set start to just to left of current region
+ nextstart = region[0] - 1;
+ index--;
+ }
- if (distance - gap > 0)
+ if (distance - gap > 0)
+ {
+ // fell out of loop because there are no more hidden regions
+ distance -= gap;
+ return nextstart - distance;
+ }
+ return start - distance;
+ } finally
{
- // fell out of loop because there are no more hidden regions
- distance -= gap;
- return nextstart - distance;
+ LOCK.readLock().unlock();
}
- return start - distance;
}
/**
- * Use this method to determine where the next hiddenRegion starts
+ * Use this method to determine the set of hiddenRegion start positions
*
- * @param hiddenRegion
- * index of hidden region (counts from 0)
- * @return column number in visible view
+ * @return list of column number in visible view where hidden regions start
*/
- public int findHiddenRegionPosition(int hiddenRegion)
+ public List findHiddenRegionPositions()
{
- int result = 0;
- if (hiddenColumns != null)
+ try
{
- int index = 0;
- int gaps = 0;
- do
+ LOCK.readLock().lock();
+ List positions = null;
+
+ if (hiddenColumns != null)
{
- int[] region = hiddenColumns.elementAt(index);
- if (hiddenRegion == 0)
+ positions = new ArrayList<>(hiddenColumns.size());
+
+ positions.add(hiddenColumns.get(0)[0]);
+ for (int i = 1; i < hiddenColumns.size(); ++i)
{
- return region[0];
- }
- gaps += region[1] + 1 - region[0];
- result = region[1] + 1;
- index++;
- } while (index <= hiddenRegion);
+ int result = 0;
+ if (hiddenColumns != null)
+ {
+ int index = 0;
+ int gaps = 0;
+ do
+ {
+ int[] region = hiddenColumns.get(index);
+ gaps += region[1] + 1 - region[0];
+ result = region[1] + 1;
+ index++;
+ } while (index <= i);
- result -= gaps;
- }
+ result -= gaps;
+ }
+ positions.add(result);
+ }
+ }
+ else
+ {
+ positions = new ArrayList<>();
+ }
- return result;
+ return positions;
+ } finally
+ {
+ LOCK.readLock().unlock();
+ }
}
/**
@@ -261,22 +396,29 @@ public class HiddenColumns
*/
public int getHiddenBoundaryRight(int alPos)
{
- if (hiddenColumns != null)
+ try
{
- int index = 0;
- do
+ LOCK.readLock().lock();
+ if (hiddenColumns != null)
{
- int[] region = hiddenColumns.elementAt(index);
- if (alPos < region[0])
+ int index = 0;
+ do
{
- return region[0];
- }
+ int[] region = hiddenColumns.get(index);
+ if (alPos < region[0])
+ {
+ return region[0];
+ }
- index++;
- } while (index < hiddenColumns.size());
- }
+ index++;
+ } while (index < hiddenColumns.size());
+ }
- return alPos;
+ return alPos;
+ } finally
+ {
+ LOCK.readLock().unlock();
+ }
}
@@ -289,23 +431,30 @@ public class HiddenColumns
*/
public int getHiddenBoundaryLeft(int alPos)
{
- if (hiddenColumns != null)
+ try
{
- int index = hiddenColumns.size() - 1;
- do
+ LOCK.readLock().lock();
+
+ if (hiddenColumns != null)
{
- int[] region = hiddenColumns.elementAt(index);
- if (alPos > region[1])
+ int index = hiddenColumns.size() - 1;
+ do
{
- return region[1];
- }
-
- index--;
- } while (index > -1);
- }
+ int[] region = hiddenColumns.get(index);
+ if (alPos > region[1])
+ {
+ return region[1];
+ }
- return alPos;
+ index--;
+ } while (index > -1);
+ }
+ return alPos;
+ } finally
+ {
+ LOCK.readLock().unlock();
+ }
}
/**
@@ -318,22 +467,30 @@ public class HiddenColumns
*/
private int getHiddenIndexLeft(int pos)
{
- if (hiddenColumns != null)
+ try
{
- int index = hiddenColumns.size() - 1;
- do
+
+ LOCK.readLock().lock();
+ if (hiddenColumns != null)
{
- int[] region = hiddenColumns.elementAt(index);
- if (pos > region[1])
+ int index = hiddenColumns.size() - 1;
+ do
{
- return index;
- }
+ int[] region = hiddenColumns.get(index);
+ if (pos > region[1])
+ {
+ return index;
+ }
- index--;
- } while (index > -1);
- }
+ index--;
+ } while (index > -1);
+ }
- return -1;
+ return -1;
+ } finally
+ {
+ LOCK.readLock().unlock();
+ }
}
@@ -345,121 +502,161 @@ public class HiddenColumns
*/
public void hideColumns(int start, int end)
{
- if (hiddenColumns == null)
+ boolean wasAlreadyLocked = false;
+ try
{
- hiddenColumns = new Vector();
- }
-
- /*
- * traverse existing hidden ranges and insert / amend / append as
- * appropriate
- */
- for (int i = 0; i < hiddenColumns.size(); i++)
- {
- int[] region = hiddenColumns.elementAt(i);
-
- if (end < region[0] - 1)
+ // check if the write lock was already locked by this thread,
+ // as this method can be called internally in loops within HiddenColumns
+ if (!LOCK.isWriteLockedByCurrentThread())
{
- /*
- * insert discontiguous preceding range
- */
- hiddenColumns.insertElementAt(new int[] { start, end }, i);
- return;
+ LOCK.writeLock().lock();
+ }
+ else
+ {
+ wasAlreadyLocked = true;
}
- if (end <= region[1])
+ if (hiddenColumns == null)
{
- /*
- * new range overlaps existing, or is contiguous preceding it - adjust
- * start column
- */
- region[0] = Math.min(region[0], start);
- return;
+ hiddenColumns = new ArrayList<>();
}
- if (start <= region[1] + 1)
+ /*
+ * traverse existing hidden ranges and insert / amend / append as
+ * appropriate
+ */
+ for (int i = 0; i < hiddenColumns.size(); i++)
{
- /*
- * new range overlaps existing, or is contiguous following it - adjust
- * start and end columns
- */
- region[0] = Math.min(region[0], start);
- region[1] = Math.max(region[1], end);
-
- /*
- * also update or remove any subsequent ranges
- * that are overlapped
- */
- while (i < hiddenColumns.size() - 1)
+ int[] region = hiddenColumns.get(i);
+
+ if (end < region[0] - 1)
+ {
+ /*
+ * insert discontiguous preceding range
+ */
+ hiddenColumns.add(i, new int[] { start, end });
+ return;
+ }
+
+ if (end <= region[1])
+ {
+ /*
+ * new range overlaps existing, or is contiguous preceding it - adjust
+ * start column
+ */
+ region[0] = Math.min(region[0], start);
+ return;
+ }
+
+ if (start <= region[1] + 1)
{
- int[] nextRegion = hiddenColumns.get(i + 1);
- if (nextRegion[0] > end + 1)
+ /*
+ * new range overlaps existing, or is contiguous following it - adjust
+ * start and end columns
+ */
+ region[0] = Math.min(region[0], start);
+ region[1] = Math.max(region[1], end);
+
+ /*
+ * also update or remove any subsequent ranges
+ * that are overlapped
+ */
+ while (i < hiddenColumns.size() - 1)
{
- /*
- * gap to next hidden range - no more to update
- */
- break;
+ int[] nextRegion = hiddenColumns.get(i + 1);
+ if (nextRegion[0] > end + 1)
+ {
+ /*
+ * gap to next hidden range - no more to update
+ */
+ break;
+ }
+ region[1] = Math.max(nextRegion[1], end);
+ hiddenColumns.remove(i + 1);
}
- region[1] = Math.max(nextRegion[1], end);
- hiddenColumns.remove(i + 1);
+ return;
}
- return;
}
- }
- /*
- * remaining case is that the new range follows everything else
- */
- hiddenColumns.addElement(new int[] { start, end });
+ /*
+ * remaining case is that the new range follows everything else
+ */
+ hiddenColumns.add(new int[] { start, end });
+ } finally
+ {
+ if (!wasAlreadyLocked)
+ {
+ LOCK.writeLock().unlock();
+ }
+ }
}
public boolean isVisible(int column)
{
- if (hiddenColumns != null)
+ try
{
- for (int[] region : hiddenColumns)
+ LOCK.readLock().lock();
+
+ if (hiddenColumns != null)
{
- if (column >= region[0] && column <= region[1])
+ for (int[] region : hiddenColumns)
{
- return false;
+ if (column >= region[0] && column <= region[1])
+ {
+ return false;
+ }
}
}
- }
- return true;
+ return true;
+ } finally
+ {
+ LOCK.readLock().unlock();
+ }
}
- /**
- * ColumnSelection
- */
- public HiddenColumns()
+ private ArrayList copyHiddenRegionsToArrayList()
{
+ int size = 0;
+ if (hiddenColumns != null)
+ {
+ size = hiddenColumns.size();
+ }
+ ArrayList copy = new ArrayList<>(size);
+
+ for (int i = 0, j = size; i < j; i++)
+ {
+ int[] rh;
+ int[] cp;
+ rh = hiddenColumns.get(i);
+ if (rh != null)
+ {
+ cp = new int[rh.length];
+ System.arraycopy(rh, 0, cp, 0, rh.length);
+ copy.add(cp);
+ }
+ }
+
+ return copy;
}
/**
- * Copy constructor
+ * Returns a copy of the vector of hidden regions, as an ArrayList. Before
+ * using this method please consider if you really need access to the hidden
+ * regions - a new (or existing!) method on HiddenColumns might be more
+ * appropriate.
*
- * @param copy
+ * @return hidden regions as an ArrayList of [start,end] pairs
*/
- public HiddenColumns(HiddenColumns copy)
+ public ArrayList getHiddenColumnsCopy()
{
- if (copy != null)
+ try
{
- if (copy.hiddenColumns != null)
- {
- hiddenColumns = new Vector(copy.hiddenColumns.size());
- for (int i = 0, j = copy.hiddenColumns.size(); i < j; i++)
- {
- int[] rh, cp;
- rh = copy.hiddenColumns.elementAt(i);
- if (rh != null)
- {
- cp = new int[rh.length];
- System.arraycopy(rh, 0, cp, 0, rh.length);
- hiddenColumns.addElement(cp);
- }
- }
- }
+ LOCK.readLock().lock();
+ return copyHiddenRegionsToArrayList();
+ } finally
+ {
+ LOCK.readLock().unlock();
}
}
@@ -474,42 +671,49 @@ public class HiddenColumns
public List compensateForEdit(int start, int change,
ColumnSelection sel)
{
- List deletedHiddenColumns = null;
-
- if (hiddenColumns != null)
+ try
{
- deletedHiddenColumns = new ArrayList();
- int hSize = hiddenColumns.size();
- for (int i = 0; i < hSize; i++)
+ LOCK.writeLock().lock();
+ List deletedHiddenColumns = null;
+
+ if (hiddenColumns != null)
{
- int[] region = hiddenColumns.elementAt(i);
- if (region[0] > start && start + change > region[1])
+ deletedHiddenColumns = new ArrayList<>();
+ int hSize = hiddenColumns.size();
+ for (int i = 0; i < hSize; i++)
{
- deletedHiddenColumns.add(region);
+ int[] region = hiddenColumns.get(i);
+ if (region[0] > start && start + change > region[1])
+ {
+ deletedHiddenColumns.add(region);
- hiddenColumns.removeElementAt(i);
- i--;
- hSize--;
- continue;
- }
+ hiddenColumns.remove(i);
+ i--;
+ hSize--;
+ continue;
+ }
- if (region[0] > start)
- {
- region[0] -= change;
- region[1] -= change;
- }
+ if (region[0] > start)
+ {
+ region[0] -= change;
+ region[1] -= change;
+ }
+
+ if (region[0] < 0)
+ {
+ region[0] = 0;
+ }
- if (region[0] < 0)
- {
- region[0] = 0;
}
+ this.revealHiddenColumns(0, sel);
}
- this.revealHiddenColumns(0, sel);
+ return deletedHiddenColumns;
+ } finally
+ {
+ LOCK.writeLock().unlock();
}
-
- return deletedHiddenColumns;
}
/**
@@ -523,33 +727,40 @@ public class HiddenColumns
*/
public void compensateForDelEdits(int start, int change)
{
- if (hiddenColumns != null)
+ try
{
- for (int i = 0; i < hiddenColumns.size(); i++)
+ LOCK.writeLock().lock();
+ if (hiddenColumns != null)
{
- int[] region = hiddenColumns.elementAt(i);
- if (region[0] >= start)
+ for (int i = 0; i < hiddenColumns.size(); i++)
{
- region[0] -= change;
- }
- if (region[1] >= start)
- {
- region[1] -= change;
- }
- if (region[1] < region[0])
- {
- hiddenColumns.removeElementAt(i--);
- }
+ int[] region = hiddenColumns.get(i);
+ if (region[0] >= start)
+ {
+ region[0] -= change;
+ }
+ if (region[1] >= start)
+ {
+ region[1] -= change;
+ }
+ if (region[1] < region[0])
+ {
+ hiddenColumns.remove(i--);
+ }
- if (region[0] < 0)
- {
- region[0] = 0;
- }
- if (region[1] < 0)
- {
- region[1] = 0;
+ if (region[0] < 0)
+ {
+ region[0] = 0;
+ }
+ if (region[1] < 0)
+ {
+ region[1] = 0;
+ }
}
}
+ } finally
+ {
+ LOCK.writeLock().unlock();
}
}
@@ -565,111 +776,128 @@ public class HiddenColumns
*/
public int[] getVisibleContigs(int start, int end)
{
- if (hiddenColumns != null && hiddenColumns.size() > 0)
+ try
{
- List visiblecontigs = new ArrayList();
- List regions = getHiddenRegions();
+ LOCK.readLock().lock();
+ if (hiddenColumns != null && hiddenColumns.size() > 0)
+ {
+ List visiblecontigs = new ArrayList<>();
+ List regions = getHiddenRegions();
- int vstart = start;
- int[] region;
- int hideStart, hideEnd;
+ int vstart = start;
+ int[] region;
+ int hideStart;
+ int hideEnd;
- for (int j = 0; vstart < end && j < regions.size(); j++)
- {
- region = regions.get(j);
- hideStart = region[0];
- hideEnd = region[1];
+ for (int j = 0; vstart < end && j < regions.size(); j++)
+ {
+ region = regions.get(j);
+ hideStart = region[0];
+ hideEnd = region[1];
+
+ if (hideEnd < vstart)
+ {
+ continue;
+ }
+ if (hideStart > vstart)
+ {
+ visiblecontigs.add(new int[] { vstart, hideStart - 1 });
+ }
+ vstart = hideEnd + 1;
+ }
- if (hideEnd < vstart)
+ if (vstart < end)
{
- continue;
+ visiblecontigs.add(new int[] { vstart, end - 1 });
}
- if (hideStart > vstart)
+ int[] vcontigs = new int[visiblecontigs.size() * 2];
+ for (int i = 0, j = visiblecontigs.size(); i < j; i++)
{
- visiblecontigs.add(new int[] { vstart, hideStart - 1 });
+ int[] vc = visiblecontigs.get(i);
+ visiblecontigs.set(i, null);
+ vcontigs[i * 2] = vc[0];
+ vcontigs[i * 2 + 1] = vc[1];
}
- vstart = hideEnd + 1;
- }
-
- if (vstart < end)
- {
- visiblecontigs.add(new int[] { vstart, end - 1 });
+ visiblecontigs.clear();
+ return vcontigs;
}
- int[] vcontigs = new int[visiblecontigs.size() * 2];
- for (int i = 0, j = visiblecontigs.size(); i < j; i++)
+ else
{
- int[] vc = visiblecontigs.get(i);
- visiblecontigs.set(i, null);
- vcontigs[i * 2] = vc[0];
- vcontigs[i * 2 + 1] = vc[1];
+ return new int[] { start, end - 1 };
}
- visiblecontigs.clear();
- return vcontigs;
- }
- else
+ } finally
{
- return new int[] { start, end - 1 };
+ LOCK.readLock().unlock();
}
}
public String[] getVisibleSequenceStrings(int start, int end,
SequenceI[] seqs)
{
- int i, iSize = seqs.length;
- String selections[] = new String[iSize];
- if (hiddenColumns != null && hiddenColumns.size() > 0)
+ try
{
- for (i = 0; i < iSize; i++)
+ LOCK.readLock().lock();
+ int iSize = seqs.length;
+ String[] selections = new String[iSize];
+ if (hiddenColumns != null && hiddenColumns.size() > 0)
{
- StringBuffer visibleSeq = new StringBuffer();
- List regions = getHiddenRegions();
-
- int blockStart = start, blockEnd = end;
- int[] region;
- int hideStart, hideEnd;
-
- for (int j = 0; j < regions.size(); j++)
+ for (int i = 0; i < iSize; i++)
{
- region = regions.get(j);
- hideStart = region[0];
- hideEnd = region[1];
+ StringBuffer visibleSeq = new StringBuffer();
+ List regions = getHiddenRegions();
- if (hideStart < start)
+ int blockStart = start;
+ int blockEnd = end;
+ int[] region;
+ int hideStart;
+ int hideEnd;
+
+ for (int j = 0; j < regions.size(); j++)
{
- continue;
- }
+ region = regions.get(j);
+ hideStart = region[0];
+ hideEnd = region[1];
- blockStart = Math.min(blockStart, hideEnd + 1);
- blockEnd = Math.min(blockEnd, hideStart);
+ if (hideStart < start)
+ {
+ continue;
+ }
- if (blockStart > blockEnd)
- {
- break;
+ blockStart = Math.min(blockStart, hideEnd + 1);
+ blockEnd = Math.min(blockEnd, hideStart);
+
+ if (blockStart > blockEnd)
+ {
+ break;
+ }
+
+ visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
+
+ blockStart = hideEnd + 1;
+ blockEnd = end;
}
- visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
+ if (end > blockStart)
+ {
+ visibleSeq.append(seqs[i].getSequence(blockStart, end));
+ }
- blockStart = hideEnd + 1;
- blockEnd = end;
+ selections[i] = visibleSeq.toString();
}
-
- if (end > blockStart)
+ }
+ else
+ {
+ for (int i = 0; i < iSize; i++)
{
- visibleSeq.append(seqs[i].getSequence(blockStart, end));
+ selections[i] = seqs[i].getSequenceAsString(start, end);
}
-
- selections[i] = visibleSeq.toString();
}
- }
- else
+
+ return selections;
+ } finally
{
- for (i = 0; i < iSize; i++)
- {
- selections[i] = seqs[i].getSequenceAsString(start, end);
- }
+ LOCK.readLock().unlock();
}
-
- return selections;
}
/**
@@ -684,70 +912,85 @@ public class HiddenColumns
*/
public int[] locateVisibleBoundsOfSequence(SequenceI seq)
{
- int fpos = seq.getStart(), lpos = seq.getEnd();
- int start = 0;
-
- if (hiddenColumns == null || hiddenColumns.size() == 0)
+ try
{
- int ifpos = seq.findIndex(fpos) - 1, ilpos = seq.findIndex(lpos) - 1;
- return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos };
- }
+ LOCK.readLock().lock();
+ int fpos = seq.getStart();
+ int lpos = seq.getEnd();
+ int start = 0;
- // Simply walk along the sequence whilst watching for hidden column
- // boundaries
- List regions = getHiddenRegions();
- int spos = fpos, lastvispos = -1, rcount = 0, hideStart = seq
- .getLength(), hideEnd = -1;
- int visPrev = 0, visNext = 0, firstP = -1, lastP = -1;
- boolean foundStart = false;
- for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
- && p < pLen; p++)
- {
- if (!Comparison.isGap(seq.getCharAt(p)))
+ if (hiddenColumns == null || hiddenColumns.size() == 0)
{
- // keep track of first/last column
- // containing sequence data regardless of visibility
- if (firstP == -1)
- {
- firstP = p;
- }
- lastP = p;
- // update hidden region start/end
- while (hideEnd < p && rcount < regions.size())
- {
- int[] region = regions.get(rcount++);
- visPrev = visNext;
- visNext += region[0] - visPrev;
- hideStart = region[0];
- hideEnd = region[1];
- }
- if (hideEnd < p)
- {
- hideStart = seq.getLength();
- }
- // update visible boundary for sequence
- if (p < hideStart)
+ int ifpos = seq.findIndex(fpos) - 1;
+ int ilpos = seq.findIndex(lpos) - 1;
+ return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos };
+ }
+
+ // Simply walk along the sequence whilst watching for hidden column
+ // boundaries
+ List regions = getHiddenRegions();
+ int spos = fpos;
+ int lastvispos = -1;
+ int rcount = 0;
+ int hideStart = seq.getLength();
+ int hideEnd = -1;
+ int visPrev = 0;
+ int visNext = 0;
+ int firstP = -1;
+ int lastP = -1;
+ boolean foundStart = false;
+ for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd()
+ && p < pLen; p++)
+ {
+ if (!Comparison.isGap(seq.getCharAt(p)))
{
- if (!foundStart)
+ // keep track of first/last column
+ // containing sequence data regardless of visibility
+ if (firstP == -1)
+ {
+ firstP = p;
+ }
+ lastP = p;
+ // update hidden region start/end
+ while (hideEnd < p && rcount < regions.size())
+ {
+ int[] region = regions.get(rcount++);
+ visPrev = visNext;
+ visNext += region[0] - visPrev;
+ hideStart = region[0];
+ hideEnd = region[1];
+ }
+ if (hideEnd < p)
+ {
+ hideStart = seq.getLength();
+ }
+ // update visible boundary for sequence
+ if (p < hideStart)
{
- fpos = spos;
- start = p;
- foundStart = true;
+ if (!foundStart)
+ {
+ fpos = spos;
+ start = p;
+ foundStart = true;
+ }
+ lastvispos = p;
+ lpos = spos;
}
- lastvispos = p;
- lpos = spos;
+ // look for next sequence position
+ spos++;
}
- // look for next sequence position
- spos++;
}
- }
- if (foundStart)
+ if (foundStart)
+ {
+ return new int[] { findColumnPosition(start),
+ findColumnPosition(lastvispos), fpos, lpos, firstP, lastP };
+ }
+ // otherwise, sequence was completely hidden
+ return new int[] { visPrev, visNext, 0, 0, firstP, lastP };
+ } finally
{
- return new int[] { findColumnPosition(start),
- findColumnPosition(lastvispos), fpos, lpos, firstP, lastP };
+ LOCK.readLock().unlock();
}
- // otherwise, sequence was completely hidden
- return new int[] { visPrev, visNext, 0, 0, firstP, lastP };
}
/**
@@ -775,88 +1018,99 @@ public class HiddenColumns
public void makeVisibleAnnotation(int start, int end,
AlignmentAnnotation alignmentAnnotation)
{
- if (alignmentAnnotation.annotations == null)
+ try
{
- return;
- }
- if (start == end && end == -1)
- {
- start = 0;
- end = alignmentAnnotation.annotations.length;
- }
- if (hiddenColumns != null && hiddenColumns.size() > 0)
- {
- // then mangle the alignmentAnnotation annotation array
- Vector annels = new Vector();
- Annotation[] els = null;
- List regions = getHiddenRegions();
- int blockStart = start, blockEnd = end;
- int[] region;
- int hideStart, hideEnd, w = 0;
-
- for (int j = 0; j < regions.size(); j++)
+ LOCK.readLock().lock();
+ if (alignmentAnnotation.annotations == null)
{
- region = regions.get(j);
- hideStart = region[0];
- hideEnd = region[1];
+ return;
+ }
+ if (start == end && end == -1)
+ {
+ start = 0;
+ end = alignmentAnnotation.annotations.length;
+ }
+ if (hiddenColumns != null && hiddenColumns.size() > 0)
+ {
+ // then mangle the alignmentAnnotation annotation array
+ Vector annels = new Vector<>();
+ Annotation[] els = null;
+ List regions = getHiddenRegions();
+ int blockStart = start;
+ int blockEnd = end;
+ int[] region;
+ int hideStart;
+ int hideEnd;
+ int w = 0;
- if (hideStart < start)
+ for (int j = 0; j < regions.size(); j++)
{
- continue;
- }
+ region = regions.get(j);
+ hideStart = region[0];
+ hideEnd = region[1];
- blockStart = Math.min(blockStart, hideEnd + 1);
- blockEnd = Math.min(blockEnd, hideStart);
+ if (hideStart < start)
+ {
+ continue;
+ }
- if (blockStart > blockEnd)
- {
- break;
- }
+ blockStart = Math.min(blockStart, hideEnd + 1);
+ blockEnd = Math.min(blockEnd, hideStart);
- annels.addElement(els = new Annotation[blockEnd - blockStart]);
- System.arraycopy(alignmentAnnotation.annotations, blockStart, els,
- 0, els.length);
- w += els.length;
- blockStart = hideEnd + 1;
- blockEnd = end;
- }
+ if (blockStart > blockEnd)
+ {
+ break;
+ }
- if (end > blockStart)
- {
- annels.addElement(els = new Annotation[end - blockStart + 1]);
- if ((els.length + blockStart) <= alignmentAnnotation.annotations.length)
+ annels.addElement(els = new Annotation[blockEnd - blockStart]);
+ System.arraycopy(alignmentAnnotation.annotations, blockStart, els,
+ 0, els.length);
+ w += els.length;
+ blockStart = hideEnd + 1;
+ blockEnd = end;
+ }
+
+ if (end > blockStart)
{
- // copy just the visible segment of the annotation row
- System.arraycopy(alignmentAnnotation.annotations, blockStart,
- els, 0, els.length);
+ annels.addElement(els = new Annotation[end - blockStart + 1]);
+ if ((els.length
+ + blockStart) <= alignmentAnnotation.annotations.length)
+ {
+ // copy just the visible segment of the annotation row
+ System.arraycopy(alignmentAnnotation.annotations, blockStart,
+ els, 0, els.length);
+ }
+ else
+ {
+ // copy to the end of the annotation row
+ System.arraycopy(alignmentAnnotation.annotations, blockStart,
+ els, 0,
+ (alignmentAnnotation.annotations.length - blockStart));
+ }
+ w += els.length;
}
- else
+ if (w == 0)
{
- // copy to the end of the annotation row
- System.arraycopy(alignmentAnnotation.annotations, blockStart,
- els, 0,
- (alignmentAnnotation.annotations.length - blockStart));
+ return;
}
- w += els.length;
- }
- if (w == 0)
- {
- return;
- }
- alignmentAnnotation.annotations = new Annotation[w];
- w = 0;
+ alignmentAnnotation.annotations = new Annotation[w];
+ w = 0;
- for (Annotation[] chnk : annels)
+ for (Annotation[] chnk : annels)
+ {
+ System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w,
+ chnk.length);
+ w += chnk.length;
+ }
+ }
+ else
{
- System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w,
- chnk.length);
- w += chnk.length;
+ alignmentAnnotation.restrict(start, end);
}
- }
- else
+ } finally
{
- alignmentAnnotation.restrict(start, end);
+ LOCK.readLock().unlock();
}
}
@@ -866,7 +1120,14 @@ public class HiddenColumns
*/
public boolean hasHiddenColumns()
{
- return hiddenColumns != null && hiddenColumns.size() > 0;
+ try
+ {
+ LOCK.readLock().lock();
+ return hiddenColumns != null && hiddenColumns.size() > 0;
+ } finally
+ {
+ LOCK.readLock().unlock();
+ }
}
/**
@@ -875,7 +1136,14 @@ public class HiddenColumns
*/
public boolean hasManyHiddenColumns()
{
- return hiddenColumns != null && hiddenColumns.size() > 1;
+ try
+ {
+ LOCK.readLock().lock();
+ return hiddenColumns != null && hiddenColumns.size() > 1;
+ } finally
+ {
+ LOCK.readLock().unlock();
+ }
}
/**
@@ -886,10 +1154,17 @@ public class HiddenColumns
*/
public void hideInsertionsFor(SequenceI sr)
{
- List inserts = sr.getInsertions();
- for (int[] r : inserts)
+ try
+ {
+ LOCK.writeLock().lock();
+ List inserts = sr.getInsertions();
+ for (int[] r : inserts)
+ {
+ hideColumns(r[0], r[1]);
+ }
+ } finally
{
- hideColumns(r[0], r[1]);
+ LOCK.writeLock().unlock();
}
}
@@ -898,19 +1173,26 @@ public class HiddenColumns
*/
public void revealAllHiddenColumns(ColumnSelection sel)
{
- if (hiddenColumns != null)
+ try
{
- for (int i = 0; i < hiddenColumns.size(); i++)
+ LOCK.writeLock().lock();
+ if (hiddenColumns != null)
{
- int[] region = hiddenColumns.elementAt(i);
- for (int j = region[0]; j < region[1] + 1; j++)
+ for (int i = 0; i < hiddenColumns.size(); i++)
{
- sel.addElement(j);
+ int[] region = hiddenColumns.get(i);
+ for (int j = region[0]; j < region[1] + 1; j++)
+ {
+ sel.addElement(j);
+ }
}
}
- }
- hiddenColumns = null;
+ hiddenColumns = null;
+ } finally
+ {
+ LOCK.writeLock().unlock();
+ }
}
/**
@@ -921,23 +1203,30 @@ public class HiddenColumns
*/
public void revealHiddenColumns(int start, ColumnSelection sel)
{
- for (int i = 0; i < hiddenColumns.size(); i++)
+ try
{
- int[] region = hiddenColumns.elementAt(i);
- if (start == region[0])
+ LOCK.writeLock().lock();
+ for (int i = 0; i < hiddenColumns.size(); i++)
{
- for (int j = region[0]; j < region[1] + 1; j++)
+ int[] region = hiddenColumns.get(i);
+ if (start == region[0])
{
- sel.addElement(j);
- }
+ for (int j = region[0]; j < region[1] + 1; j++)
+ {
+ sel.addElement(j);
+ }
- hiddenColumns.removeElement(region);
- break;
+ hiddenColumns.remove(region);
+ break;
+ }
}
- }
- if (hiddenColumns.size() == 0)
+ if (hiddenColumns.size() == 0)
+ {
+ hiddenColumns = null;
+ }
+ } finally
{
- hiddenColumns = null;
+ LOCK.writeLock().unlock();
}
}
@@ -949,13 +1238,16 @@ public class HiddenColumns
* @param intervals
* @return
*/
- private boolean pruneIntervalVector(final List shifts,
- Vector intervals)
+ private boolean pruneIntervalList(final List shifts,
+ ArrayList intervals)
{
boolean pruned = false;
- int i = 0, j = intervals.size() - 1, s = 0, t = shifts.size() - 1;
- int hr[] = intervals.elementAt(i);
- int sr[] = shifts.get(s);
+ int i = 0;
+ int j = intervals.size() - 1;
+ int s = 0;
+ int t = shifts.size() - 1;
+ int[] hr = intervals.get(i);
+ int[] sr = shifts.get(s);
while (i <= j && s <= t)
{
boolean trailinghn = hr[1] >= sr[0];
@@ -963,7 +1255,7 @@ public class HiddenColumns
{
if (i < j)
{
- hr = intervals.elementAt(++i);
+ hr = intervals.get(++i);
}
else
{
@@ -991,12 +1283,12 @@ public class HiddenColumns
{
if (trailinghc)
{ // deleted hidden region.
- intervals.removeElementAt(i);
+ intervals.remove(i);
pruned = true;
j--;
if (i <= j)
{
- hr = intervals.elementAt(i);
+ hr = intervals.get(i);
}
continue;
}
@@ -1044,14 +1336,21 @@ public class HiddenColumns
*/
public void pruneDeletions(List shifts)
{
- // delete any intervals intersecting.
- if (hiddenColumns != null)
+ try
{
- pruneIntervalVector(shifts, hiddenColumns);
- if (hiddenColumns != null && hiddenColumns.size() == 0)
+ LOCK.writeLock().lock();
+ // delete any intervals intersecting.
+ if (hiddenColumns != null)
{
- hiddenColumns = null;
+ pruneIntervalList(shifts, hiddenColumns);
+ if (hiddenColumns != null && hiddenColumns.size() == 0)
+ {
+ hiddenColumns = null;
+ }
}
+ } finally
+ {
+ LOCK.writeLock().unlock();
}
}
@@ -1098,8 +1397,7 @@ public class HiddenColumns
// recover mapping between sequence's non-gap positions and positions
// mapping to view.
pruneDeletions(ShiftList.parseMap(origseq.gapMap()));
- int[] viscontigs = al.getHiddenColumns().getVisibleContigs(0,
- profileseq.getLength());
+ int[] viscontigs = getVisibleContigs(0, profileseq.getLength());
int spos = 0;
int offset = 0;
@@ -1148,9 +1446,8 @@ public class HiddenColumns
}
else
{
- al.getSequenceAt(s).setSequence(
- sq.substring(0, spos + offset) + sb.toString()
- + sq.substring(spos + offset));
+ al.getSequenceAt(s).setSequence(sq.substring(0, spos + offset)
+ + sb.toString() + sq.substring(spos + offset));
}
}
}
@@ -1162,7 +1459,8 @@ public class HiddenColumns
{
// pad the final region with gaps.
StringBuffer sb = new StringBuffer();
- for (int s = 0, ns = profileseq.getLength() - spos - offset; s < ns; s++)
+ for (int s = 0, ns = profileseq.getLength() - spos
+ - offset; s < ns; s++)
{
sb.append(gc);
}
@@ -1251,16 +1549,23 @@ public class HiddenColumns
@Override
public int hashCode()
{
- int hashCode = 1;
- if (hiddenColumns != null)
+ try
{
- for (int[] hidden : hiddenColumns)
+ LOCK.readLock().lock();
+ int hashCode = 1;
+ if (hiddenColumns != null)
{
- hashCode = 31 * hashCode + hidden[0];
- hashCode = 31 * hashCode + hidden[1];
+ for (int[] hidden : hiddenColumns)
+ {
+ hashCode = 31 * hashCode + hidden[0];
+ hashCode = 31 * hashCode + hidden[1];
+ }
}
+ return hashCode;
+ } finally
+ {
+ LOCK.readLock().unlock();
}
- return hashCode;
}
/**
@@ -1271,11 +1576,131 @@ public class HiddenColumns
*/
public void hideMarkedBits(BitSet inserts)
{
- for (int firstSet = inserts.nextSetBit(0), lastSet = 0; firstSet >= 0; firstSet = inserts
- .nextSetBit(lastSet))
+ try
+ {
+ LOCK.writeLock().lock();
+ for (int firstSet = inserts
+ .nextSetBit(0), lastSet = 0; firstSet >= 0; firstSet = inserts
+ .nextSetBit(lastSet))
+ {
+ lastSet = inserts.nextClearBit(firstSet);
+ hideColumns(firstSet, lastSet - 1);
+ }
+ } finally
+ {
+ LOCK.writeLock().unlock();
+ }
+ }
+
+ /**
+ *
+ * @param inserts
+ * BitSet where hidden columns will be marked
+ */
+ public void markHiddenRegions(BitSet inserts)
+ {
+ try
+ {
+ LOCK.readLock().lock();
+ if (hiddenColumns == null)
+ {
+ return;
+ }
+ for (int[] range : hiddenColumns)
+ {
+ inserts.set(range[0], range[1] + 1);
+ }
+ } finally
+ {
+ LOCK.readLock().unlock();
+ }
+ }
+
+ /**
+ * Calculate the visible start and end index of an alignment.
+ *
+ * @param width
+ * full alignment width
+ * @return integer array where: int[0] = startIndex, and int[1] = endIndex
+ */
+ public int[] getVisibleStartAndEndIndex(int width)
+ {
+ try
+ {
+ LOCK.readLock().lock();
+ int[] alignmentStartEnd = new int[] { 0, width - 1 };
+ int startPos = alignmentStartEnd[0];
+ int endPos = alignmentStartEnd[1];
+
+ int[] lowestRange = new int[] { -1, -1 };
+ int[] higestRange = new int[] { -1, -1 };
+
+ if (hiddenColumns == null)
+ {
+ return new int[] { startPos, endPos };
+ }
+
+ for (int[] hiddenCol : hiddenColumns)
+ {
+ lowestRange = (hiddenCol[0] <= startPos) ? hiddenCol : lowestRange;
+ higestRange = (hiddenCol[1] >= endPos) ? hiddenCol : higestRange;
+ }
+
+ if (lowestRange[0] == -1 && lowestRange[1] == -1)
+ {
+ startPos = alignmentStartEnd[0];
+ }
+ else
+ {
+ startPos = lowestRange[1] + 1;
+ }
+
+ if (higestRange[0] == -1 && higestRange[1] == -1)
+ {
+ endPos = alignmentStartEnd[1];
+ }
+ else
+ {
+ endPos = higestRange[0] - 1;
+ }
+ return new int[] { startPos, endPos };
+ } finally
+ {
+ LOCK.readLock().unlock();
+ }
+
+ }
+
+ /**
+ * Finds the hidden region (if any) which starts or ends at res
+ *
+ * @param res
+ * visible residue position, unadjusted for hidden columns
+ * @return region as [start,end] or null if no matching region is found
+ */
+ public int[] getRegionWithEdgeAtRes(int res)
+ {
+ try
+ {
+ LOCK.readLock().lock();
+ int adjres = adjustForHiddenColumns(res);
+
+ int[] reveal = null;
+ if (hiddenColumns != null)
+ {
+ for (int[] region : hiddenColumns)
+ {
+ if (adjres + 1 == region[0] || adjres - 1 == region[1])
+ {
+ reveal = region;
+ break;
+ }
+ }
+ }
+ return reveal;
+ } finally
{
- lastSet = inserts.nextClearBit(firstSet);
- hideColumns(firstSet, lastSet - 1);
+ LOCK.readLock().unlock();
}
}