2 * Jalview - A Sequence Alignment Editor and Viewer
\r
3 * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
\r
5 * This program is free software; you can redistribute it and/or
\r
6 * modify it under the terms of the GNU General Public License
\r
7 * as published by the Free Software Foundation; either version 2
\r
8 * of the License, or (at your option) any later version.
\r
10 * This program is distributed in the hope that it will be useful,
\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 * GNU General Public License for more details.
\r
15 * You should have received a copy of the GNU General Public License
\r
16 * along with this program; if not, write to the Free Software
\r
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
\r
19 package jalview.datamodel;
\r
23 import jalview.util.*;
\r
26 * NOTE: Columns are zero based.
\r
28 public class ColumnSelection
\r
30 Vector selected = new Vector();
\r
32 //Vector of int [] {startCol, endCol}
\r
33 Vector hiddenColumns;
\r
36 * Add a column to the selection
\r
38 * @param col index of column
\r
40 public void addElement(int col)
\r
42 Integer column = new Integer(col);
\r
43 if (!selected.contains(column))
\r
45 selected.addElement(column);
\r
50 * clears column selection
\r
54 selected.removeAllElements();
\r
58 * removes col from selection
\r
60 * @param col index of column to be removed
\r
62 public void removeElement(int col)
\r
64 Integer colInt = new Integer(col);
\r
66 if (selected.contains(colInt))
\r
68 selected.removeElement(colInt);
\r
73 * removes a range of columns from the selection
\r
74 * @param start int - first column in range to be removed
\r
75 * @param end int - last col
\r
77 public void removeElements(int start, int end)
\r
80 for (int i = start; i < end; i++)
\r
82 colInt = new Integer(i);
\r
83 if (selected.contains(colInt))
\r
85 selected.removeElement(colInt);
\r
92 * @return Vector containing selected columns as Integers
\r
94 public Vector getSelected()
\r
101 * @param col index to search for in column selection
\r
103 * @return true if Integer(col) is in selection.
\r
105 public boolean contains(int col)
\r
107 return selected.contains(new Integer(col));
\r
113 * @param i DOCUMENT ME!
\r
115 * @return DOCUMENT ME!
\r
117 public int columnAt(int i)
\r
119 return ( (Integer) selected.elementAt(i)).intValue();
\r
125 * @return DOCUMENT ME!
\r
129 return selected.size();
\r
135 * @return DOCUMENT ME!
\r
137 public int getMax()
\r
141 for (int i = 0; i < selected.size(); i++)
\r
143 if (columnAt(i) > max)
\r
155 * @return DOCUMENT ME!
\r
157 public int getMin()
\r
159 int min = 1000000000;
\r
161 for (int i = 0; i < selected.size(); i++)
\r
163 if (columnAt(i) < min)
\r
173 * propagate shift in alignment columns to column selection
\r
175 * @param start beginning of edit
\r
176 * @param left shift in edit (+ve for removal, or -ve for inserts)
\r
178 public Vector compensateForEdit(int start, int change)
\r
180 Vector deletedHiddenColumns = null;
\r
181 for (int i = 0; i < size(); i++)
\r
183 int temp = columnAt(i);
\r
187 selected.setElementAt(new Integer(temp - change), i);
\r
191 if (hiddenColumns != null)
\r
193 deletedHiddenColumns = new Vector();
\r
194 int hSize = hiddenColumns.size();
\r
195 for (int i = 0; i < hSize; i++)
\r
197 int[] region = (int[]) hiddenColumns.elementAt(i);
\r
198 if (region[0] > start && start + change > region[1])
\r
200 deletedHiddenColumns.addElement(
\r
201 hiddenColumns.elementAt(i));
\r
203 hiddenColumns.removeElementAt(i);
\r
209 if (region[0] > start)
\r
211 region[0] -= change;
\r
212 region[1] -= change;
\r
222 this.revealHiddenColumns(0);
\r
225 return deletedHiddenColumns;
\r
229 * propagate shift in alignment columns to column selection
\r
230 * special version of compensateForEdit - allowing for edits within hidden regions
\r
231 * @param start beginning of edit
\r
232 * @param left shift in edit (+ve for removal, or -ve for inserts)
\r
234 private void compensateForDelEdits(int start, int change)
\r
236 for (int i = 0; i < size(); i++)
\r
238 int temp = columnAt(i);
\r
242 selected.setElementAt(new Integer(temp - change), i);
\r
246 if (hiddenColumns != null)
\r
248 for (int i = 0; i < hiddenColumns.size(); i++)
\r
250 int[] region = (int[]) hiddenColumns.elementAt(i);
\r
251 if (region[0] >= start)
\r
253 region[0] -= change;
\r
255 if (region[1] >= start)
\r
257 region[1] -= change;
\r
259 if (region[1] < region[0])
\r
261 hiddenColumns.removeElementAt(i--);
\r
277 * Adjust hidden column boundaries based on a series of column
\r
278 * additions or deletions in visible regions.
\r
279 * @param shiftrecord
\r
282 public ShiftList compensateForEdits(ShiftList shiftrecord)
\r
284 if (shiftrecord != null)
\r
286 Vector shifts = shiftrecord.shifts;
\r
287 if (shifts != null && shifts.size() > 0)
\r
290 for (int i = 0, j = shifts.size(); i < j; i++)
\r
292 int[] sh = (int[]) shifts.elementAt(i);
\r
293 //compensateForEdit(shifted+sh[0], sh[1]);
\r
294 compensateForDelEdits(shifted + sh[0], sh[1]);
\r
298 return shiftrecord.getInverse();
\r
304 * removes intersection of position,length ranges in deletions
\r
305 * from the start,end regions marked in intervals.
\r
310 private boolean pruneIntervalVector(Vector deletions, Vector intervals)
\r
312 boolean pruned = false;
\r
313 int i = 0, j = intervals.size() - 1, s = 0, t = deletions.size() - 1;
\r
314 int hr[] = (int[]) intervals.elementAt(i);
\r
315 int sr[] = (int[]) deletions.elementAt(s);
\r
316 while (i <= j && s <= t)
\r
318 boolean trailinghn = hr[1] >= sr[0];
\r
323 hr = (int[]) intervals.elementAt(++i);
\r
331 int endshift = sr[0] + sr[1]; // deletion ranges - -ve means an insert
\r
332 if (endshift < hr[0] || endshift < sr[0])
\r
333 { // leadinghc disjoint or not a deletion
\r
336 sr = (int[]) deletions.elementAt(++s);
\r
344 boolean leadinghn = hr[0] >= sr[0];
\r
345 boolean leadinghc = hr[0] < endshift;
\r
346 boolean trailinghc = hr[1] < endshift;
\r
350 { // deleted hidden region.
\r
351 intervals.removeElementAt(i);
\r
356 hr = (int[]) intervals.elementAt(i);
\r
362 hr[0] = endshift; // clip c terminal region
\r
363 leadinghn = !leadinghn;
\r
379 // sr contained in hr
\r
382 sr = (int[]) deletions.elementAt(++s);
\r
392 return pruned; // true if any interval was removed or modified by operations.
\r
395 private boolean pruneColumnList(Vector deletion, Vector list)
\r
397 int s = 0, t = deletion.size();
\r
398 int[] sr = (int[]) list.elementAt(s++);
\r
399 boolean pruned = false;
\r
400 int i = 0, j = list.size();
\r
401 while (i < j && s <= t)
\r
403 int c = ( (Integer) list.elementAt(i++)).intValue();
\r
406 if (sr[1] + sr[0] >= c)
\r
407 { // sr[1] -ve means inseriton.
\r
408 list.removeElementAt(--i);
\r
415 sr = (int[]) deletion.elementAt(s);
\r
425 * remove any hiddenColumns or selected columns and shift remaining
\r
426 * based on a series of position, range deletions.
\r
429 public void pruneDeletions(ShiftList deletions)
\r
431 if (deletions != null)
\r
433 Vector shifts = deletions.shifts;
\r
434 if (shifts != null && shifts.size() > 0)
\r
436 // delete any intervals intersecting.
\r
437 if (hiddenColumns != null)
\r
439 pruneIntervalVector(shifts, hiddenColumns);
\r
440 if (hiddenColumns != null && hiddenColumns.size() == 0)
\r
442 hiddenColumns = null;
\r
445 if (selected != null && selected.size() > 0)
\r
447 pruneColumnList(shifts, selected);
\r
448 if (selected != null && selected.size() == 0)
\r
453 // and shift the rest.
\r
454 this.compensateForEdits(deletions);
\r
460 * This Method is used to return all the HiddenColumn regions
\r
461 * less than the given index.
\r
465 public Vector getHiddenColumns()
\r
467 return hiddenColumns;
\r
471 * Return absolute column index for a visible column index
\r
472 * @param column int column index in alignment view
\r
473 * @return alignment column index for column
\r
475 public int adjustForHiddenColumns(int column)
\r
477 int result = column;
\r
478 if (hiddenColumns != null)
\r
480 for (int i = 0; i < hiddenColumns.size(); i++)
\r
482 int[] region = (int[]) hiddenColumns.elementAt(i);
\r
483 if (result >= region[0])
\r
485 result += region[1] - region[0] + 1;
\r
493 * Use this method to find out where a visible column is in the alignment
\r
494 * when hidden columns exist
\r
495 * @param hiddenColumn int
\r
498 public int findColumnPosition(int hiddenColumn)
\r
500 int result = hiddenColumn;
\r
501 if (hiddenColumns != null)
\r
507 int[] region = (int[]) hiddenColumns.elementAt(index);
\r
508 if (hiddenColumn > region[1])
\r
510 result -= region[1] + 1 - region[0];
\r
514 while (index < hiddenColumns.size());
\r
523 * Use this method to determine where the next hiddenRegion starts
\r
525 public int findHiddenRegionPosition(int hiddenRegion)
\r
528 if (hiddenColumns != null)
\r
534 int[] region = (int[]) hiddenColumns.elementAt(index);
\r
535 if (hiddenRegion == 0)
\r
540 gaps += region[1] + 1 - region[0];
\r
541 result = region[1] + 1;
\r
544 while (index < hiddenRegion + 1);
\r
553 * THis method returns the rightmost limit of a
\r
554 * region of an alignment with hidden columns.
\r
555 * In otherwords, the next hidden column.
\r
558 public int getHiddenBoundaryRight(int alPos)
\r
560 if (hiddenColumns != null)
\r
565 int[] region = (int[]) hiddenColumns.elementAt(index);
\r
566 if (alPos < region[0])
\r
573 while (index < hiddenColumns.size());
\r
581 * This method returns the leftmost limit of a
\r
582 * region of an alignment with hidden columns.
\r
583 * In otherwords, the previous hidden column.
\r
586 public int getHiddenBoundaryLeft(int alPos)
\r
588 if (hiddenColumns != null)
\r
590 int index = hiddenColumns.size() - 1;
\r
593 int[] region = (int[]) hiddenColumns.elementAt(index);
\r
594 if (alPos > region[1])
\r
601 while (index > -1);
\r
608 public void hideSelectedColumns()
\r
612 int column = ( (Integer) getSelected().firstElement()).intValue();
\r
613 hideColumns(column);
\r
618 public void hideColumns(int start, int end)
\r
620 if (hiddenColumns == null)
\r
622 hiddenColumns = new Vector();
\r
625 boolean added = false;
\r
626 boolean overlap = false;
\r
628 for (int i = 0; i < hiddenColumns.size(); i++)
\r
630 int[] region = (int[]) hiddenColumns.elementAt(i);
\r
631 if (start <= region[1] && end >= region[0])
\r
633 hiddenColumns.removeElementAt(i);
\r
637 else if (end < region[0] && start < region[0])
\r
639 hiddenColumns.insertElementAt(new int[]
\r
648 hideColumns(start, end);
\r
652 hiddenColumns.addElement(new int[]
\r
659 * This method will find a range of selected columns
\r
660 * around the column specified
\r
663 public void hideColumns(int col)
\r
665 // First find out range of columns to hide
\r
666 int min = col, max = col + 1;
\r
667 while (contains(min))
\r
669 removeElement(min);
\r
673 while (contains(max))
\r
675 removeElement(max);
\r
686 hideColumns(min, max);
\r
689 public void revealAllHiddenColumns()
\r
691 if (hiddenColumns != null)
\r
693 for (int i = 0; i < hiddenColumns.size(); i++)
\r
695 int[] region = (int[]) hiddenColumns.elementAt(i);
\r
696 for (int j = region[0]; j < region[1] + 1; j++)
\r
703 hiddenColumns = null;
\r
706 public void revealHiddenColumns(int res)
\r
708 for (int i = 0; i < hiddenColumns.size(); i++)
\r
710 int[] region = (int[]) hiddenColumns.elementAt(i);
\r
711 if (res == region[0])
\r
713 for (int j = region[0]; j < region[1] + 1; j++)
\r
718 hiddenColumns.removeElement(region);
\r
722 if (hiddenColumns.size() == 0)
\r
724 hiddenColumns = null;
\r
728 public boolean isVisible(int column)
\r
730 if (hiddenColumns != null)
\r
731 for (int i = 0; i < hiddenColumns.size(); i++)
\r
733 int[] region = (int[]) hiddenColumns.elementAt(i);
\r
734 if (column >= region[0] && column <= region[1])
\r
747 public ColumnSelection(ColumnSelection copy)
\r
751 if (copy.selected != null)
\r
753 selected = new Vector();
\r
754 for (int i = 0, j = copy.selected.size(); i < j; i++)
\r
756 selected.addElement(copy.selected.elementAt(i));
\r
759 if (copy.hiddenColumns != null)
\r
761 hiddenColumns = new Vector(copy.hiddenColumns.size());
\r
762 for (int i = 0, j = copy.hiddenColumns.size(); i < j; i++)
\r
765 rh = (int[]) copy.hiddenColumns.elementAt(i);
\r
768 cp = new int[rh.length];
\r
769 System.arraycopy(rh, 0, cp, 0, rh.length);
\r
770 hiddenColumns.addElement(cp);
\r
780 public ColumnSelection()
\r
784 public String[] getVisibleSequenceStrings(int start, int end,
\r
787 int i, iSize = seqs.length;
\r
788 String selection[] = new String[iSize];
\r
789 if (hiddenColumns != null && hiddenColumns.size() > 0)
\r
791 for (i = 0; i < iSize; i++)
\r
793 StringBuffer visibleSeq = new StringBuffer();
\r
794 Vector regions = getHiddenColumns();
\r
796 int blockStart = start, blockEnd = end;
\r
798 int hideStart, hideEnd;
\r
800 for (int j = 0; j < regions.size(); j++)
\r
802 region = (int[]) regions.elementAt(j);
\r
803 hideStart = region[0];
\r
804 hideEnd = region[1];
\r
806 if (hideStart < start)
\r
811 blockStart = Math.min(blockStart, hideEnd + 1);
\r
812 blockEnd = Math.min(blockEnd, hideStart);
\r
814 if (blockStart > blockEnd)
\r
819 visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
\r
821 blockStart = hideEnd + 1;
\r
825 if (end > blockStart)
\r
827 visibleSeq.append(seqs[i].getSequence(blockStart, end));
\r
830 selection[i] = visibleSeq.toString();
\r
835 for (i = 0; i < iSize; i++)
\r
837 selection[i] = seqs[i].getSequenceAsString(start, end);
\r
845 * return all visible segments between the given start and end boundaries
\r
847 * @param start (first column inclusive from 0)
\r
848 * @param end (last column - not inclusive)
\r
849 * @return int[] {i_start, i_end, ..} where intervals lie in start<=i_start<=i_end<end
\r
851 public int[] getVisibleContigs(int start, int end)
\r
853 if (hiddenColumns != null && hiddenColumns.size() > 0)
\r
855 Vector visiblecontigs = new Vector();
\r
856 Vector regions = getHiddenColumns();
\r
858 int vstart = start;
\r
860 int hideStart, hideEnd;
\r
862 for (int j = 0; vstart < end && j < regions.size(); j++)
\r
864 region = (int[]) regions.elementAt(j);
\r
865 hideStart = region[0];
\r
866 hideEnd = region[1];
\r
868 if (hideEnd < vstart)
\r
872 if (hideStart > vstart)
\r
874 visiblecontigs.addElement(new int[]
\r
875 {vstart, hideStart - 1});
\r
877 vstart = hideEnd + 1;
\r
882 visiblecontigs.addElement(new int[]
\r
883 {vstart, end - 1});
\r
885 int[] vcontigs = new int[visiblecontigs.size() * 2];
\r
886 for (int i = 0, j = visiblecontigs.size(); i < j; i++)
\r
888 int[] vc = (int[]) visiblecontigs.elementAt(i);
\r
889 visiblecontigs.setElementAt(null, i);
\r
890 vcontigs[i * 2] = vc[0];
\r
891 vcontigs[i * 2 + 1] = vc[1];
\r
893 visiblecontigs.removeAllElements();
\r