X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fdatamodel%2FColumnSelection.java;h=c2327819c81923ce95e11d96da730e9544718cc4;hb=e224b72118c12cd77ae96f0f8d86c123e0416dc7;hp=6fb584ca4774b3ec6a2ab2996d101d567d642af0;hpb=8d44c38e7028bcce53c0370dec67baa5d8d209c9;p=jalview.git diff --git a/src/jalview/datamodel/ColumnSelection.java b/src/jalview/datamodel/ColumnSelection.java index 6fb584c..c232781 100644 --- a/src/jalview/datamodel/ColumnSelection.java +++ b/src/jalview/datamodel/ColumnSelection.java @@ -20,11 +20,13 @@ */ package jalview.datamodel; +import jalview.util.Comparison; import jalview.util.ShiftList; import jalview.viewmodel.annotationfilter.AnnotationFilterParameter; import jalview.viewmodel.annotationfilter.AnnotationFilterParameter.SearchableAnnotationField; import java.util.ArrayList; +import java.util.BitSet; import java.util.Collections; import java.util.List; import java.util.Vector; @@ -34,10 +36,178 @@ import java.util.Vector; */ public class ColumnSelection { - /* - * list of selected columns (not ordered) - */ - Vector selected = new Vector(); + private class IntList + { + /* + * list of selected columns (ordered by selection order, not column order) + */ + private List order = new ArrayList(); + + /** + * bitfield for column selection - allows quick lookup + */ + private BitSet selected = new BitSet(); + + /** + * adds a new column i to the selection - only if i is not already selected + * + * @param i + */ + public void add(int i) + { + if (!selected.get(i)) + { + order.add(Integer.valueOf(i)); + selected.set(i); + } + } + + public void clear() + { + order.clear(); + selected.clear(); + } + + public void remove(int col) + { + + Integer colInt = new Integer(col); + + if (selected.get(col)) + { + // if this ever changes to List.remove(), ensure Integer not int + // argument + // as List.remove(int i) removes the i'th item which is wrong + order.remove(colInt); + selected.clear(col); + } + } + + public boolean contains(Integer colInt) + { + return selected.get(colInt); + } + + public boolean isEmpty() + { + return order.isEmpty(); + } + + public List getList() + { + return order; + } + + public int size() + { + return order.size(); + } + + /** + * gets the column that was selected first, second or i'th + * + * @param i + * @return + */ + public int elementAt(int i) + { + return order.get(i); + } + + protected boolean pruneColumnList(final List shifts) + { + int s = 0, t = shifts.size(); + int[] sr = shifts.get(s++); + boolean pruned = false; + int i = 0, j = order.size(); + while (i < j && s <= t) + { + int c = order.get(i++).intValue(); + if (sr[0] <= c) + { + if (sr[1] + sr[0] >= c) + { // sr[1] -ve means inseriton. + order.remove(--i); + selected.clear(c); + j--; + } + else + { + if (s < t) + { + sr = shifts.get(s); + } + s++; + } + } + } + return pruned; + } + + /** + * shift every selected column at or above start by change + * + * @param start + * - leftmost column to be shifted + * @param change + * - delta for shift + */ + public void compensateForEdits(int start, int change) + { + BitSet mask = new BitSet(); + for (int i = 0; i < order.size(); i++) + { + int temp = order.get(i); + + if (temp >= start) + { + // clear shifted bits and update List of selected columns + selected.clear(temp); + mask.set(temp - change); + order.set(i, new Integer(temp - change)); + } + } + // lastly update the bitfield all at once + selected.or(mask); + } + + public boolean isSelected(int column) + { + return selected.get(column); + } + + public int getMaxColumn() + { + return selected.length() - 1; + } + + public int getMinColumn() + { + return selected.get(0) ? 0 : selected.nextSetBit(0); + } + + /** + * @return a series of selection intervals along the range + */ + public List getRanges() + { + List rlist = new ArrayList(); + if (selected.isEmpty()) + { + return rlist; + } + int next = selected.nextSetBit(0), clear = -1; + while (next != -1) + { + clear = selected.nextClearBit(next); + rlist.add(new int[] { next, clear - 1 }); + next = selected.nextSetBit(clear); + } + return rlist; + } + } + + IntList selected = new IntList(); /* * list of hidden column [start, end] ranges; the list is maintained in @@ -53,11 +223,7 @@ public class ColumnSelection */ public void addElement(int col) { - Integer column = new Integer(col); - if (!selected.contains(column)) - { - selected.addElement(column); - } + selected.add(col); } /** @@ -65,7 +231,7 @@ public class ColumnSelection */ public void clear() { - selected.removeAllElements(); + selected.clear(); } /** @@ -76,14 +242,7 @@ public class ColumnSelection */ public void removeElement(int col) { - Integer colInt = new Integer(col); - - if (selected.contains(colInt)) - { - // if this ever changes to List.remove(), ensure Integer not int argument - // as List.remove(int i) removes the i'th item which is wrong - selected.removeElement(colInt); - } + selected.remove(col); } /** @@ -102,18 +261,28 @@ public class ColumnSelection colInt = new Integer(i); if (selected.contains(colInt)) { - selected.removeElement(colInt); + selected.remove(colInt); } } } /** * Returns a list of selected columns. The list contains no duplicates but is - * not necessarily ordered. + * not necessarily ordered. It also may include columns hidden from the + * current view */ public List getSelected() { - return selected; + return selected.getList(); + } + + /** + * @return list of int arrays containing start and end column position for + * runs of selected columns ordered from right to left. + */ + public List getSelectedRanges() + { + return selected.getRanges(); } /** @@ -121,11 +290,11 @@ public class ColumnSelection * @param col * index to search for in column selection * - * @return true if Integer(col) is in selection. + * @return true if col is selected */ public boolean contains(int col) { - return selected.contains(new Integer(col)); + return (col > -1) ? selected.isSelected(col) : false; } /** @@ -143,17 +312,11 @@ public class ColumnSelection */ public int getMax() { - int max = -1; - - for (int sel : getSelected()) + if (selected.isEmpty()) { - if (sel > max) - { - max = sel; - } + return -1; } - - return max; + return selected.getMaxColumn(); } /** @@ -163,17 +326,11 @@ public class ColumnSelection */ public int getMin() { - int min = 1000000000; - - for (int sel : getSelected()) + if (selected.isEmpty()) { - if (sel < min) - { - min = sel; - } + return 1000000000; } - - return min; + return selected.getMinColumn(); } /** @@ -187,16 +344,7 @@ public class ColumnSelection public List compensateForEdit(int start, int change) { List deletedHiddenColumns = null; - for (int i = 0; i < selected.size(); i++) - { - int temp = selected.get(i); - - if (temp >= start) - { - // if this ever changes to List.set(), swap parameter order!! - selected.setElementAt(new Integer(temp - change), i); - } - } + selected.compensateForEdits(start, change); if (hiddenColumns != null) { @@ -245,16 +393,8 @@ public class ColumnSelection */ private void compensateForDelEdits(int start, int change) { - for (int i = 0; i < selected.size(); i++) - { - int temp = selected.get(i); - if (temp >= start) - { - // if this ever changes to List.set(), must swap parameter order!!! - selected.setElementAt(new Integer(temp - change), i); - } - } + selected.compensateForEdits(start, change); if (hiddenColumns != null) { @@ -409,36 +549,6 @@ public class ColumnSelection // operations. } - private boolean pruneColumnList(final List shifts, - Vector list) - { - int s = 0, t = shifts.size(); - int[] sr = shifts.get(s++); - boolean pruned = false; - int i = 0, j = list.size(); - while (i < j && s <= t) - { - int c = list.elementAt(i++).intValue(); - if (sr[0] <= c) - { - if (sr[1] + sr[0] >= c) - { // sr[1] -ve means inseriton. - list.removeElementAt(--i); - j--; - } - else - { - if (s < t) - { - sr = shifts.get(s); - } - s++; - } - } - } - return pruned; - } - /** * remove any hiddenColumns or selected columns and shift remaining based on a * series of position, range deletions. @@ -463,7 +573,7 @@ public class ColumnSelection } if (selected != null && selected.size() > 0) { - pruneColumnList(shifts, selected); + selected.pruneColumnList(shifts); if (selected != null && selected.size() == 0) { selected = null; @@ -544,6 +654,10 @@ public class ColumnSelection /** * Use this method to determine where the next hiddenRegion starts + * + * @param hiddenRegion + * index of hidden region (counts from 0) + * @return column number in visible view */ public int findHiddenRegionPosition(int hiddenRegion) { @@ -563,7 +677,7 @@ public class ColumnSelection gaps += region[1] + 1 - region[0]; result = region[1] + 1; index++; - } while (index < hiddenRegion + 1); + } while (index <= hiddenRegion); result -= gaps; } @@ -629,10 +743,13 @@ public class ColumnSelection public void hideSelectedColumns() { - while (!selected.isEmpty()) + synchronized (selected) { - int column = selected.get(0).intValue(); - hideColumns(column); + for (int[] selregions : selected.getRanges()) + { + hideColumns(selregions[0], selregions[1]); + } + selected.clear(); } } @@ -692,7 +809,7 @@ public class ColumnSelection /* * remaining case is that the new range follows everything else */ - hiddenColumns.addElement(new int[] { start, end }); + hiddenColumns.addElement(new int[] { start, end }); } /** @@ -812,10 +929,10 @@ public class ColumnSelection { if (copy.selected != null) { - selected = new Vector(); + selected = new IntList(); for (int i = 0, j = copy.selected.size(); i < j; i++) { - selected.addElement(copy.selected.elementAt(i)); + selected.add(copy.selected.elementAt(i)); } } if (copy.hiddenColumns != null) @@ -963,6 +1080,76 @@ public class ColumnSelection } /** + * Locate the first and last position visible for this sequence. if seq isn't + * visible then return the position of the left and right of the hidden + * boundary region + * + * @param seq + * @return int[] { visible start, visible end, first seqpos, last seqpos } + */ + public int[] locateVisibleBoundsOfSequence(SequenceI seq) + { + int fpos=seq.getStart(),lpos= seq.getEnd(); + int start = 0; + int end = seq.getLength(); + + if (hiddenColumns == null || hiddenColumns.size() == 0) + { + return new int[] { seq.findIndex(fpos), seq.findIndex(lpos), fpos, + lpos }; + } + + // Simply walk along the sequence whilst watching for hidden column + // boundaries + List regions = getHiddenColumns(); + int spos = fpos, lastvispos = -1, rcount = 0, hideStart = seq + .getLength(), hideEnd = -1; + int visPrev = 0, visNext = 0, base = 0; + boolean foundStart = false; + for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd() + && p < pLen; p++) + { + if (!Comparison.isGap(seq.getCharAt(p))) + { + // update hidden region start/end + while (hideEnd < p && rcount < regions.size()) + { + int[] region = regions.get(rcount++); + visNext += region[1] + 1 - region[0]; + visPrev = visNext-1; + hideStart = region[0]; + hideEnd = region[1]; + } + if (hideEnd < p) + { + hideStart = seq.getLength(); + } + // update visible boundary for sequence + if (p < hideStart) + { + if (!foundStart) + { + fpos = spos; + start = p; + foundStart = true; + } + lastvispos = p; + lpos = spos; + } + // look for next sequence position + spos++; + } + } + if (foundStart) + { + return new int[] { findColumnPosition(start), + findColumnPosition(lastvispos), fpos, lpos }; + } + // otherwise, sequence was completely hidden + return new int[] { visPrev, visNext, 0, 0 }; + } + + /** * delete any columns in alignmentAnnotation that are hidden (including * sequence associated annotation). * @@ -1112,10 +1299,7 @@ public class ColumnSelection { if (hiddenColumns != null && isVisible(col.intValue())) { - if (!selected.contains(col)) - { - selected.addElement(col); - } + selected.add(col); } } } @@ -1129,7 +1313,7 @@ public class ColumnSelection */ public void setElementsFrom(ColumnSelection colsel) { - selected = new Vector(); + selected = new IntList(); if (colsel.selected != null && colsel.selected.size() > 0) { if (hiddenColumns != null && hiddenColumns.size() > 0) @@ -1336,6 +1520,8 @@ public class ColumnSelection public boolean filterAnnotations(Annotation[] annotations, AnnotationFilterParameter filterParams) { + // JBPNote - this method needs to be refactored to become independent of + // viewmodel package this.revealAllHiddenColumns(); this.clear(); int count = 0; @@ -1417,4 +1603,5 @@ public class ColumnSelection } while (count < annotations.length); return false; } + }