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;
}
@Override
public int hashCode()
{
// TODO Auto-generated method stub
return selected.hashCode();
}
@Override
public boolean equals(Object obj)
{
if (obj instanceof IntList)
{
return ((IntList) obj).selected.equals(selected);
}
return false;
}
}
private IntList selection = new IntList();
/**
* Add a column to the selection
*
* @param col
* index of column
*/
public void addElement(int col)
{
selection.add(col);
}
/**
* clears column selection
*/
public void clear()
{
selection.clear();
}
/**
* Removes value 'col' from the selection (not the col'th item)
*
* @param col
* index of column to be removed
*/
public void removeElement(int col)
{
selection.remove(col);
}
/**
* removes a range of columns from the selection
*
* @param start
* int - first column in range to be removed
* @param end
* int - last col
*/
public void removeElements(int start, int end)
{
Integer colInt;
for (int i = start; i < end; i++)
{
colInt = new Integer(i);
if (selection.contains(colInt))
{
selection.remove(colInt);
}
}
}
/**
* Returns a read-only view of the (possibly empty) list of selected columns
*
* The list contains no duplicates but is not necessarily ordered. It also may
* include columns hidden from the current view. To modify (for example sort)
* the list, you should first make a copy.
*
* The list is not thread-safe: iterating over it could result in
* ConcurrentModificationException if it is modified by another thread.
*/
public List getSelected()
{
return selection.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 selection.getRanges();
}
/**
*
* @param col
* index to search for in column selection
*
* @return true if col is selected
*/
public boolean contains(int col)
{
return (col > -1) ? selection.isSelected(col) : false;
}
/**
* Answers true if no columns are selected, else false
*/
public boolean isEmpty()
{
return selection == null || selection.isEmpty();
}
/**
* rightmost selected column
*
* @return rightmost column in alignment that is selected
*/
public int getMax()
{
if (selection.isEmpty())
{
return -1;
}
return selection.getMaxColumn();
}
/**
* Leftmost column in selection
*
* @return column index of leftmost column in selection
*/
public int getMin()
{
if (selection.isEmpty())
{
return 1000000000;
}
return selection.getMinColumn();
}
public void hideSelectedColumns(AlignmentI al)
{
synchronized (selection)
{
for (int[] selregions : selection.getRanges())
{
al.getHiddenColumns().hideColumns(selregions[0], selregions[1]);
}
selection.clear();
}
}
/**
* Hides the specified column and any adjacent selected columns
*
* @param res
* int
*/
public void hideSelectedColumns(int col, HiddenColumns hidden)
{
/*
* deselect column (whether selected or not!)
*/
removeElement(col);
/*
* find adjacent selected columns
*/
int min = col - 1, max = col + 1;
while (contains(min))
{
removeElement(min);
min--;
}
while (contains(max))
{
removeElement(max);
max++;
}
/*
* min, max are now the closest unselected columns
*/
min++;
max--;
if (min > max)
{
min = max;
}
hidden.hideColumns(min, max);
}
/**
* Copy constructor
*
* @param copy
*/
public ColumnSelection(ColumnSelection copy)
{
if (copy != null)
{
selection = new IntList(copy.selection);
}
}
/**
* ColumnSelection
*/
public ColumnSelection()
{
}
/**
* Invert the column selection from first to end-1. leaves hiddenColumns
* untouched (and unselected)
*
* @param first
* @param end
*/
public void invertColumnSelection(int first, int width, AlignmentI al)
{
boolean hasHidden = al.getHiddenColumns().hasHiddenColumns();
for (int i = first; i < width; i++)
{
if (contains(i))
{
removeElement(i);
}
else
{
if (!hasHidden || al.getHiddenColumns().isVisible(i))
{
addElement(i);
}
}
}
}
/**
* set the selected columns to the given column selection, excluding any
* columns that are hidden.
*
* @param colsel
*/
public void setElementsFrom(ColumnSelection colsel,
HiddenColumns hiddenColumns)
{
selection = new IntList();
if (colsel.selection != null && colsel.selection.size() > 0)
{
if (hiddenColumns.hasHiddenColumns())
{
// only select visible columns in this columns selection
for (Integer col : colsel.getSelected())
{
if (hiddenColumns != null
&& hiddenColumns.isVisible(col.intValue()))
{
selection.add(col);
}
}
}
else
{
// add everything regardless
for (Integer col : colsel.getSelected())
{
addElement(col);
}
}
}
}
/**
*
* @return true if there are columns marked
*/
public boolean hasSelectedColumns()
{
return (selection != null && selection.size() > 0);
}
/**
* Selects columns where the given annotation matches the provided filter
* condition(s). Any existing column selections are first cleared. Answers the
* number of columns added.
*
* @param annotations
* @param filterParams
* @return
*/
public int filterAnnotations(Annotation[] annotations,
AnnotationFilterParameter filterParams)
{
// JBPNote - this method needs to be refactored to become independent of
// viewmodel package
this.clear();
int addedCount = 0;
int column = 0;
do
{
Annotation ann = annotations[column];
if (ann != null)
{
boolean matched = false;
/*
* filter may have multiple conditions -
* these are or'd until a match is found
*/
if (filterParams
.getThresholdType() == AnnotationFilterParameter.ThresholdType.ABOVE_THRESHOLD
&& ann.value > filterParams.getThresholdValue())
{
matched = true;
}
if (!matched && filterParams
.getThresholdType() == AnnotationFilterParameter.ThresholdType.BELOW_THRESHOLD
&& ann.value < filterParams.getThresholdValue())
{
matched = true;
}
if (!matched && filterParams.isFilterAlphaHelix()
&& ann.secondaryStructure == 'H')
{
matched = true;
}
if (!matched && filterParams.isFilterBetaSheet()
&& ann.secondaryStructure == 'E')
{
matched = true;
}
if (!matched && filterParams.isFilterTurn()
&& ann.secondaryStructure == 'S')
{
matched = true;
}
String regexSearchString = filterParams.getRegexString();
if (!matched && regexSearchString != null)
{
List fields = filterParams
.getRegexSearchFields();
for (SearchableAnnotationField field : fields)
{
String compareTo = field == SearchableAnnotationField.DISPLAY_STRING
? ann.displayCharacter // match 'Label'
: ann.description; // and/or 'Description'
if (compareTo != null)
{
try
{
if (compareTo.matches(regexSearchString))
{
matched = true;
}
} catch (PatternSyntaxException pse)
{
if (compareTo.equals(regexSearchString))
{
matched = true;
}
}
if (matched)
{
break;
}
}
}
}
if (matched)
{
this.addElement(column);
addedCount++;
}
}
column++;
} while (column < annotations.length);
return addedCount;
}
/**
* Returns a hashCode built from selected columns ranges
*/
@Override
public int hashCode()
{
return selection.hashCode();
}
/**
* Answers true if comparing to a ColumnSelection with the same selected
* columns and hidden columns, else false
*/
@Override
public boolean equals(Object obj)
{
if (!(obj instanceof ColumnSelection))
{
return false;
}
ColumnSelection that = (ColumnSelection) obj;
/*
* check columns selected are either both null, or match
*/
if (this.selection == null)
{
if (that.selection != null)
{
return false;
}
}
if (!this.selection.equals(that.selection))
{
return false;
}
return true;
}
/**
* Updates the column selection depending on the parameters, and returns true
* if any change was made to the selection
*
* @param markedColumns
* a set identifying marked columns (base 0)
* @param startCol
* the first column of the range to operate over (base 0)
* @param endCol
* the last column of the range to operate over (base 0)
* @param invert
* if true, deselect marked columns and select unmarked
* @param extendCurrent
* if true, extend rather than replacing the current column selection
* @param toggle
* if true, toggle the selection state of marked columns
*
* @return
*/
public boolean markColumns(BitSet markedColumns, int startCol, int endCol,
boolean invert, boolean extendCurrent, boolean toggle)
{
boolean changed = false;
if (!extendCurrent && !toggle)
{
changed = !this.isEmpty();
clear();
}
if (invert)
{
// invert only in the currently selected sequence region
int i = markedColumns.nextClearBit(startCol);
int ibs = markedColumns.nextSetBit(startCol);
while (i >= startCol && i <= endCol)
{
if (ibs < 0 || i < ibs)
{
changed = true;
if (toggle && contains(i))
{
removeElement(i++);
}
else
{
addElement(i++);
}
}
else
{
i = markedColumns.nextClearBit(ibs);
ibs = markedColumns.nextSetBit(i);
}
}
}
else
{
int i = markedColumns.nextSetBit(startCol);
while (i >= startCol && i <= endCol)
{
changed = true;
if (toggle && contains(i))
{
removeElement(i);
}
else
{
addElement(i);
}
i = markedColumns.nextSetBit(i + 1);
}
}
return changed;
}
/**
* Adjusts column selections, and the given selection group, to match the
* range of a stretch (e.g. mouse drag) operation
*
* Method refactored from ScalePanel.mouseDragged
*
* @param res
* current column position, adjusted for hidden columns
* @param sg
* current selection group
* @param min
* start position of the stretch group
* @param max
* end position of the stretch group
*/
public void stretchGroup(int res, SequenceGroup sg, int min, int max)
{
if (!contains(res))
{
addElement(res);
}
if (res > sg.getStartRes())
{
// expand selection group to the right
sg.setEndRes(res);
}
if (res < sg.getStartRes())
{
// expand selection group to the left
sg.setStartRes(res);
}
/*
* expand or shrink column selection to match the
* range of the drag operation
*/
for (int col = min; col <= max; col++)
{
if (col < sg.getStartRes() || col > sg.getEndRes())
{
// shrinking drag - remove from selection
removeElement(col);
}
else
{
// expanding drag - add to selection
addElement(col);
}
}
}
}