setting and merging selected columns from another selection object
[jalview.git] / src / jalview / datamodel / ColumnSelection.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)\r
3  * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  * \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
9  * \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
14  * \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
18  */\r
19 package jalview.datamodel;\r
20 \r
21 import java.util.*;\r
22 \r
23 import jalview.util.*;\r
24 \r
25 /**\r
26  * NOTE: Columns are zero based.\r
27  */\r
28 public class ColumnSelection\r
29 {\r
30   Vector selected = new Vector();\r
31 \r
32   // Vector of int [] {startCol, endCol}\r
33   Vector hiddenColumns;\r
34 \r
35   /**\r
36    * Add a column to the selection\r
37    * \r
38    * @param col\r
39    *          index of column\r
40    */\r
41   public void addElement(int col)\r
42   {\r
43     Integer column = new Integer(col);\r
44     if (!selected.contains(column))\r
45     {\r
46       selected.addElement(column);\r
47     }\r
48   }\r
49 \r
50   /**\r
51    * clears column selection\r
52    */\r
53   public void clear()\r
54   {\r
55     selected.removeAllElements();\r
56   }\r
57 \r
58   /**\r
59    * removes col from selection\r
60    * \r
61    * @param col\r
62    *          index of column to be removed\r
63    */\r
64   public void removeElement(int col)\r
65   {\r
66     Integer colInt = new Integer(col);\r
67 \r
68     if (selected.contains(colInt))\r
69     {\r
70       selected.removeElement(colInt);\r
71     }\r
72   }\r
73 \r
74   /**\r
75    * removes a range of columns from the selection\r
76    * \r
77    * @param start\r
78    *          int - first column in range to be removed\r
79    * @param end\r
80    *          int - last col\r
81    */\r
82   public void removeElements(int start, int end)\r
83   {\r
84     Integer colInt;\r
85     for (int i = start; i < end; i++)\r
86     {\r
87       colInt = new Integer(i);\r
88       if (selected.contains(colInt))\r
89       {\r
90         selected.removeElement(colInt);\r
91       }\r
92     }\r
93   }\r
94 \r
95   /**\r
96    * \r
97    * @return Vector containing selected columns as Integers\r
98    */\r
99   public Vector getSelected()\r
100   {\r
101     return selected;\r
102   }\r
103 \r
104   /**\r
105    * \r
106    * @param col\r
107    *          index to search for in column selection\r
108    * \r
109    * @return true if Integer(col) is in selection.\r
110    */\r
111   public boolean contains(int col)\r
112   {\r
113     return selected.contains(new Integer(col));\r
114   }\r
115 \r
116   /**\r
117    * Column number at position i in selection\r
118    * \r
119    * @param i\r
120    *          index into selected columns\r
121    * \r
122    * @return column number in alignment\r
123    */\r
124   public int columnAt(int i)\r
125   {\r
126     return ((Integer) selected.elementAt(i)).intValue();\r
127   }\r
128 \r
129   /**\r
130    * DOCUMENT ME!\r
131    * \r
132    * @return DOCUMENT ME!\r
133    */\r
134   public int size()\r
135   {\r
136     return selected.size();\r
137   }\r
138 \r
139   /**\r
140    * rightmost selected column\r
141    * \r
142    * @return rightmost column in alignment that is selected\r
143    */\r
144   public int getMax()\r
145   {\r
146     int max = -1;\r
147 \r
148     for (int i = 0; i < selected.size(); i++)\r
149     {\r
150       if (columnAt(i) > max)\r
151       {\r
152         max = columnAt(i);\r
153       }\r
154     }\r
155 \r
156     return max;\r
157   }\r
158 \r
159   /**\r
160    * Leftmost column in selection\r
161    * \r
162    * @return column index of leftmost column in selection\r
163    */\r
164   public int getMin()\r
165   {\r
166     int min = 1000000000;\r
167 \r
168     for (int i = 0; i < selected.size(); i++)\r
169     {\r
170       if (columnAt(i) < min)\r
171       {\r
172         min = columnAt(i);\r
173       }\r
174     }\r
175 \r
176     return min;\r
177   }\r
178 \r
179   /**\r
180    * propagate shift in alignment columns to column selection\r
181    * \r
182    * @param start\r
183    *          beginning of edit\r
184    * @param left\r
185    *          shift in edit (+ve for removal, or -ve for inserts)\r
186    */\r
187   public Vector compensateForEdit(int start, int change)\r
188   {\r
189     Vector deletedHiddenColumns = null;\r
190     for (int i = 0; i < size(); i++)\r
191     {\r
192       int temp = columnAt(i);\r
193 \r
194       if (temp >= start)\r
195       {\r
196         selected.setElementAt(new Integer(temp - change), i);\r
197       }\r
198     }\r
199 \r
200     if (hiddenColumns != null)\r
201     {\r
202       deletedHiddenColumns = new Vector();\r
203       int hSize = hiddenColumns.size();\r
204       for (int i = 0; i < hSize; i++)\r
205       {\r
206         int[] region = (int[]) hiddenColumns.elementAt(i);\r
207         if (region[0] > start && start + change > region[1])\r
208         {\r
209           deletedHiddenColumns.addElement(hiddenColumns.elementAt(i));\r
210 \r
211           hiddenColumns.removeElementAt(i);\r
212           i--;\r
213           hSize--;\r
214           continue;\r
215         }\r
216 \r
217         if (region[0] > start)\r
218         {\r
219           region[0] -= change;\r
220           region[1] -= change;\r
221         }\r
222 \r
223         if (region[0] < 0)\r
224         {\r
225           region[0] = 0;\r
226         }\r
227 \r
228       }\r
229 \r
230       this.revealHiddenColumns(0);\r
231     }\r
232 \r
233     return deletedHiddenColumns;\r
234   }\r
235 \r
236   /**\r
237    * propagate shift in alignment columns to column selection special version of\r
238    * compensateForEdit - allowing for edits within hidden regions\r
239    * \r
240    * @param start\r
241    *          beginning of edit\r
242    * @param left\r
243    *          shift in edit (+ve for removal, or -ve for inserts)\r
244    */\r
245   private void compensateForDelEdits(int start, int change)\r
246   {\r
247     for (int i = 0; i < size(); i++)\r
248     {\r
249       int temp = columnAt(i);\r
250 \r
251       if (temp >= start)\r
252       {\r
253         selected.setElementAt(new Integer(temp - change), i);\r
254       }\r
255     }\r
256 \r
257     if (hiddenColumns != null)\r
258     {\r
259       for (int i = 0; i < hiddenColumns.size(); i++)\r
260       {\r
261         int[] region = (int[]) hiddenColumns.elementAt(i);\r
262         if (region[0] >= start)\r
263         {\r
264           region[0] -= change;\r
265         }\r
266         if (region[1] >= start)\r
267         {\r
268           region[1] -= change;\r
269         }\r
270         if (region[1] < region[0])\r
271         {\r
272           hiddenColumns.removeElementAt(i--);\r
273         }\r
274 \r
275         if (region[0] < 0)\r
276         {\r
277           region[0] = 0;\r
278         }\r
279         if (region[1] < 0)\r
280         {\r
281           region[1] = 0;\r
282         }\r
283       }\r
284     }\r
285   }\r
286 \r
287   /**\r
288    * Adjust hidden column boundaries based on a series of column additions or\r
289    * deletions in visible regions.\r
290    * \r
291    * @param shiftrecord\r
292    * @return\r
293    */\r
294   public ShiftList compensateForEdits(ShiftList shiftrecord)\r
295   {\r
296     if (shiftrecord != null)\r
297     {\r
298       Vector shifts = shiftrecord.shifts;\r
299       if (shifts != null && shifts.size() > 0)\r
300       {\r
301         int shifted = 0;\r
302         for (int i = 0, j = shifts.size(); i < j; i++)\r
303         {\r
304           int[] sh = (int[]) shifts.elementAt(i);\r
305           // compensateForEdit(shifted+sh[0], sh[1]);\r
306           compensateForDelEdits(shifted + sh[0], sh[1]);\r
307           shifted -= sh[1];\r
308         }\r
309       }\r
310       return shiftrecord.getInverse();\r
311     }\r
312     return null;\r
313   }\r
314 \r
315   /**\r
316    * removes intersection of position,length ranges in deletions from the\r
317    * start,end regions marked in intervals.\r
318    * \r
319    * @param deletions\r
320    * @param intervals\r
321    * @return\r
322    */\r
323   private boolean pruneIntervalVector(Vector deletions, Vector intervals)\r
324   {\r
325     boolean pruned = false;\r
326     int i = 0, j = intervals.size() - 1, s = 0, t = deletions.size() - 1;\r
327     int hr[] = (int[]) intervals.elementAt(i);\r
328     int sr[] = (int[]) deletions.elementAt(s);\r
329     while (i <= j && s <= t)\r
330     {\r
331       boolean trailinghn = hr[1] >= sr[0];\r
332       if (!trailinghn)\r
333       {\r
334         if (i < j)\r
335         {\r
336           hr = (int[]) intervals.elementAt(++i);\r
337         }\r
338         else\r
339         {\r
340           i++;\r
341         }\r
342         continue;\r
343       }\r
344       int endshift = sr[0] + sr[1]; // deletion ranges - -ve means an insert\r
345       if (endshift < hr[0] || endshift < sr[0])\r
346       { // leadinghc disjoint or not a deletion\r
347         if (s < t)\r
348         {\r
349           sr = (int[]) deletions.elementAt(++s);\r
350         }\r
351         else\r
352         {\r
353           s++;\r
354         }\r
355         continue;\r
356       }\r
357       boolean leadinghn = hr[0] >= sr[0];\r
358       boolean leadinghc = hr[0] < endshift;\r
359       boolean trailinghc = hr[1] < endshift;\r
360       if (leadinghn)\r
361       {\r
362         if (trailinghc)\r
363         { // deleted hidden region.\r
364           intervals.removeElementAt(i);\r
365           pruned = true;\r
366           j--;\r
367           if (i <= j)\r
368           {\r
369             hr = (int[]) intervals.elementAt(i);\r
370           }\r
371           continue;\r
372         }\r
373         if (leadinghc)\r
374         {\r
375           hr[0] = endshift; // clip c terminal region\r
376           leadinghn = !leadinghn;\r
377           pruned = true;\r
378         }\r
379       }\r
380       if (!leadinghn)\r
381       {\r
382         if (trailinghc)\r
383         {\r
384           if (trailinghn)\r
385           {\r
386             hr[1] = sr[0] - 1;\r
387             pruned = true;\r
388           }\r
389         }\r
390         else\r
391         {\r
392           // sr contained in hr\r
393           if (s < t)\r
394           {\r
395             sr = (int[]) deletions.elementAt(++s);\r
396           }\r
397           else\r
398           {\r
399             s++;\r
400           }\r
401           continue;\r
402         }\r
403       }\r
404     }\r
405     return pruned; // true if any interval was removed or modified by\r
406     // operations.\r
407   }\r
408 \r
409   private boolean pruneColumnList(Vector deletion, Vector list)\r
410   {\r
411     int s = 0, t = deletion.size();\r
412     int[] sr = (int[]) list.elementAt(s++);\r
413     boolean pruned = false;\r
414     int i = 0, j = list.size();\r
415     while (i < j && s <= t)\r
416     {\r
417       int c = ((Integer) list.elementAt(i++)).intValue();\r
418       if (sr[0] <= c)\r
419       {\r
420         if (sr[1] + sr[0] >= c)\r
421         { // sr[1] -ve means inseriton.\r
422           list.removeElementAt(--i);\r
423           j--;\r
424         }\r
425         else\r
426         {\r
427           if (s < t)\r
428           {\r
429             sr = (int[]) deletion.elementAt(s);\r
430           }\r
431           s++;\r
432         }\r
433       }\r
434     }\r
435     return pruned;\r
436   }\r
437 \r
438   /**\r
439    * remove any hiddenColumns or selected columns and shift remaining based on a\r
440    * series of position, range deletions.\r
441    * \r
442    * @param deletions\r
443    */\r
444   public void pruneDeletions(ShiftList deletions)\r
445   {\r
446     if (deletions != null)\r
447     {\r
448       Vector shifts = deletions.shifts;\r
449       if (shifts != null && shifts.size() > 0)\r
450       {\r
451         // delete any intervals intersecting.\r
452         if (hiddenColumns != null)\r
453         {\r
454           pruneIntervalVector(shifts, hiddenColumns);\r
455           if (hiddenColumns != null && hiddenColumns.size() == 0)\r
456           {\r
457             hiddenColumns = null;\r
458           }\r
459         }\r
460         if (selected != null && selected.size() > 0)\r
461         {\r
462           pruneColumnList(shifts, selected);\r
463           if (selected != null && selected.size() == 0)\r
464           {\r
465             selected = null;\r
466           }\r
467         }\r
468         // and shift the rest.\r
469         this.compensateForEdits(deletions);\r
470       }\r
471     }\r
472   }\r
473 \r
474   /**\r
475    * This Method is used to return all the HiddenColumn regions less than the\r
476    * given index.\r
477    * \r
478    * @param end\r
479    *          int\r
480    * @return Vector\r
481    */\r
482   public Vector getHiddenColumns()\r
483   {\r
484     return hiddenColumns;\r
485   }\r
486 \r
487   /**\r
488    * Return absolute column index for a visible column index\r
489    * \r
490    * @param column\r
491    *          int column index in alignment view\r
492    * @return alignment column index for column\r
493    */\r
494   public int adjustForHiddenColumns(int column)\r
495   {\r
496     int result = column;\r
497     if (hiddenColumns != null)\r
498     {\r
499       for (int i = 0; i < hiddenColumns.size(); i++)\r
500       {\r
501         int[] region = (int[]) hiddenColumns.elementAt(i);\r
502         if (result >= region[0])\r
503         {\r
504           result += region[1] - region[0] + 1;\r
505         }\r
506       }\r
507     }\r
508     return result;\r
509   }\r
510 \r
511   /**\r
512    * Use this method to find out where a visible column is in the alignment when\r
513    * hidden columns exist\r
514    * \r
515    * @param hiddenColumn\r
516    *          int\r
517    * @return int\r
518    */\r
519   public int findColumnPosition(int hiddenColumn)\r
520   {\r
521     int result = hiddenColumn;\r
522     if (hiddenColumns != null)\r
523     {\r
524       int index = 0;\r
525       int gaps = 0;\r
526       do\r
527       {\r
528         int[] region = (int[]) hiddenColumns.elementAt(index);\r
529         if (hiddenColumn > region[1])\r
530         {\r
531           result -= region[1] + 1 - region[0];\r
532         }\r
533         index++;\r
534       } while (index < hiddenColumns.size());\r
535 \r
536       result -= gaps;\r
537     }\r
538 \r
539     return result;\r
540   }\r
541 \r
542   /**\r
543    * Use this method to determine where the next hiddenRegion starts\r
544    */\r
545   public int findHiddenRegionPosition(int hiddenRegion)\r
546   {\r
547     int result = 0;\r
548     if (hiddenColumns != null)\r
549     {\r
550       int index = 0;\r
551       int gaps = 0;\r
552       do\r
553       {\r
554         int[] region = (int[]) hiddenColumns.elementAt(index);\r
555         if (hiddenRegion == 0)\r
556         {\r
557           return region[0];\r
558         }\r
559 \r
560         gaps += region[1] + 1 - region[0];\r
561         result = region[1] + 1;\r
562         index++;\r
563       } while (index < hiddenRegion + 1);\r
564 \r
565       result -= gaps;\r
566     }\r
567 \r
568     return result;\r
569   }\r
570 \r
571   /**\r
572    * THis method returns the rightmost limit of a region of an alignment with\r
573    * hidden columns. In otherwords, the next hidden column.\r
574    * \r
575    * @param index\r
576    *          int\r
577    */\r
578   public int getHiddenBoundaryRight(int alPos)\r
579   {\r
580     if (hiddenColumns != null)\r
581     {\r
582       int index = 0;\r
583       do\r
584       {\r
585         int[] region = (int[]) hiddenColumns.elementAt(index);\r
586         if (alPos < region[0])\r
587         {\r
588           return region[0];\r
589         }\r
590 \r
591         index++;\r
592       } while (index < hiddenColumns.size());\r
593     }\r
594 \r
595     return alPos;\r
596 \r
597   }\r
598 \r
599   /**\r
600    * This method returns the leftmost limit of a region of an alignment with\r
601    * hidden columns. In otherwords, the previous hidden column.\r
602    * \r
603    * @param index\r
604    *          int\r
605    */\r
606   public int getHiddenBoundaryLeft(int alPos)\r
607   {\r
608     if (hiddenColumns != null)\r
609     {\r
610       int index = hiddenColumns.size() - 1;\r
611       do\r
612       {\r
613         int[] region = (int[]) hiddenColumns.elementAt(index);\r
614         if (alPos > region[1])\r
615         {\r
616           return region[1];\r
617         }\r
618 \r
619         index--;\r
620       } while (index > -1);\r
621     }\r
622 \r
623     return alPos;\r
624 \r
625   }\r
626 \r
627   public void hideSelectedColumns()\r
628   {\r
629     while (size() > 0)\r
630     {\r
631       int column = ((Integer) getSelected().firstElement()).intValue();\r
632       hideColumns(column);\r
633     }\r
634 \r
635   }\r
636 \r
637   public void hideColumns(int start, int end)\r
638   {\r
639     if (hiddenColumns == null)\r
640     {\r
641       hiddenColumns = new Vector();\r
642     }\r
643 \r
644     boolean added = false;\r
645     boolean overlap = false;\r
646 \r
647     for (int i = 0; i < hiddenColumns.size(); i++)\r
648     {\r
649       int[] region = (int[]) hiddenColumns.elementAt(i);\r
650       if (start <= region[1] && end >= region[0])\r
651       {\r
652         hiddenColumns.removeElementAt(i);\r
653         overlap = true;\r
654         break;\r
655       }\r
656       else if (end < region[0] && start < region[0])\r
657       {\r
658         hiddenColumns.insertElementAt(new int[]\r
659         { start, end }, i);\r
660         added = true;\r
661         break;\r
662       }\r
663     }\r
664 \r
665     if (overlap)\r
666     {\r
667       hideColumns(start, end);\r
668     }\r
669     else if (!added)\r
670     {\r
671       hiddenColumns.addElement(new int[]\r
672       { start, end });\r
673     }\r
674 \r
675   }\r
676 \r
677   /**\r
678    * This method will find a range of selected columns around the column\r
679    * specified\r
680    * \r
681    * @param res\r
682    *          int\r
683    */\r
684   public void hideColumns(int col)\r
685   {\r
686     // First find out range of columns to hide\r
687     int min = col, max = col + 1;\r
688     while (contains(min))\r
689     {\r
690       removeElement(min);\r
691       min--;\r
692     }\r
693 \r
694     while (contains(max))\r
695     {\r
696       removeElement(max);\r
697       max++;\r
698     }\r
699 \r
700     min++;\r
701     max--;\r
702     if (min > max)\r
703     {\r
704       min = max;\r
705     }\r
706 \r
707     hideColumns(min, max);\r
708   }\r
709 \r
710   public void revealAllHiddenColumns()\r
711   {\r
712     if (hiddenColumns != null)\r
713     {\r
714       for (int i = 0; i < hiddenColumns.size(); i++)\r
715       {\r
716         int[] region = (int[]) hiddenColumns.elementAt(i);\r
717         for (int j = region[0]; j < region[1] + 1; j++)\r
718         {\r
719           addElement(j);\r
720         }\r
721       }\r
722     }\r
723 \r
724     hiddenColumns = null;\r
725   }\r
726 \r
727   public void revealHiddenColumns(int res)\r
728   {\r
729     for (int i = 0; i < hiddenColumns.size(); i++)\r
730     {\r
731       int[] region = (int[]) hiddenColumns.elementAt(i);\r
732       if (res == region[0])\r
733       {\r
734         for (int j = region[0]; j < region[1] + 1; j++)\r
735         {\r
736           addElement(j);\r
737         }\r
738 \r
739         hiddenColumns.removeElement(region);\r
740         break;\r
741       }\r
742     }\r
743     if (hiddenColumns.size() == 0)\r
744     {\r
745       hiddenColumns = null;\r
746     }\r
747   }\r
748 \r
749   public boolean isVisible(int column)\r
750   {\r
751     if (hiddenColumns != null)\r
752       for (int i = 0; i < hiddenColumns.size(); i++)\r
753       {\r
754         int[] region = (int[]) hiddenColumns.elementAt(i);\r
755         if (column >= region[0] && column <= region[1])\r
756         {\r
757           return false;\r
758         }\r
759       }\r
760 \r
761     return true;\r
762   }\r
763 \r
764   /**\r
765    * Copy constructor\r
766    * \r
767    * @param copy\r
768    */\r
769   public ColumnSelection(ColumnSelection copy)\r
770   {\r
771     if (copy != null)\r
772     {\r
773       if (copy.selected != null)\r
774       {\r
775         selected = new Vector();\r
776         for (int i = 0, j = copy.selected.size(); i < j; i++)\r
777         {\r
778           selected.addElement(copy.selected.elementAt(i));\r
779         }\r
780       }\r
781       if (copy.hiddenColumns != null)\r
782       {\r
783         hiddenColumns = new Vector(copy.hiddenColumns.size());\r
784         for (int i = 0, j = copy.hiddenColumns.size(); i < j; i++)\r
785         {\r
786           int[] rh, cp;\r
787           rh = (int[]) copy.hiddenColumns.elementAt(i);\r
788           if (rh != null)\r
789           {\r
790             cp = new int[rh.length];\r
791             System.arraycopy(rh, 0, cp, 0, rh.length);\r
792             hiddenColumns.addElement(cp);\r
793           }\r
794         }\r
795       }\r
796     }\r
797   }\r
798 \r
799   /**\r
800    * ColumnSelection\r
801    */\r
802   public ColumnSelection()\r
803   {\r
804   }\r
805 \r
806   public String[] getVisibleSequenceStrings(int start, int end,\r
807           SequenceI[] seqs)\r
808   {\r
809     int i, iSize = seqs.length;\r
810     String selection[] = new String[iSize];\r
811     if (hiddenColumns != null && hiddenColumns.size() > 0)\r
812     {\r
813       for (i = 0; i < iSize; i++)\r
814       {\r
815         StringBuffer visibleSeq = new StringBuffer();\r
816         Vector regions = getHiddenColumns();\r
817 \r
818         int blockStart = start, blockEnd = end;\r
819         int[] region;\r
820         int hideStart, hideEnd;\r
821 \r
822         for (int j = 0; j < regions.size(); j++)\r
823         {\r
824           region = (int[]) regions.elementAt(j);\r
825           hideStart = region[0];\r
826           hideEnd = region[1];\r
827 \r
828           if (hideStart < start)\r
829           {\r
830             continue;\r
831           }\r
832 \r
833           blockStart = Math.min(blockStart, hideEnd + 1);\r
834           blockEnd = Math.min(blockEnd, hideStart);\r
835 \r
836           if (blockStart > blockEnd)\r
837           {\r
838             break;\r
839           }\r
840 \r
841           visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));\r
842 \r
843           blockStart = hideEnd + 1;\r
844           blockEnd = end;\r
845         }\r
846 \r
847         if (end > blockStart)\r
848         {\r
849           visibleSeq.append(seqs[i].getSequence(blockStart, end));\r
850         }\r
851 \r
852         selection[i] = visibleSeq.toString();\r
853       }\r
854     }\r
855     else\r
856     {\r
857       for (i = 0; i < iSize; i++)\r
858       {\r
859         selection[i] = seqs[i].getSequenceAsString(start, end);\r
860       }\r
861     }\r
862 \r
863     return selection;\r
864   }\r
865 \r
866   /**\r
867    * return all visible segments between the given start and end boundaries\r
868    * \r
869    * @param start\r
870    *          (first column inclusive from 0)\r
871    * @param end\r
872    *          (last column - not inclusive)\r
873    * @return int[] {i_start, i_end, ..} where intervals lie in\r
874    *         start<=i_start<=i_end<end\r
875    */\r
876   public int[] getVisibleContigs(int start, int end)\r
877   {\r
878     if (hiddenColumns != null && hiddenColumns.size() > 0)\r
879     {\r
880       Vector visiblecontigs = new Vector();\r
881       Vector regions = getHiddenColumns();\r
882 \r
883       int vstart = start;\r
884       int[] region;\r
885       int hideStart, hideEnd;\r
886 \r
887       for (int j = 0; vstart < end && j < regions.size(); j++)\r
888       {\r
889         region = (int[]) regions.elementAt(j);\r
890         hideStart = region[0];\r
891         hideEnd = region[1];\r
892 \r
893         if (hideEnd < vstart)\r
894         {\r
895           continue;\r
896         }\r
897         if (hideStart > vstart)\r
898         {\r
899           visiblecontigs.addElement(new int[]\r
900           { vstart, hideStart - 1 });\r
901         }\r
902         vstart = hideEnd + 1;\r
903       }\r
904 \r
905       if (vstart < end)\r
906       {\r
907         visiblecontigs.addElement(new int[]\r
908         { vstart, end - 1 });\r
909       }\r
910       int[] vcontigs = new int[visiblecontigs.size() * 2];\r
911       for (int i = 0, j = visiblecontigs.size(); i < j; i++)\r
912       {\r
913         int[] vc = (int[]) visiblecontigs.elementAt(i);\r
914         visiblecontigs.setElementAt(null, i);\r
915         vcontigs[i * 2] = vc[0];\r
916         vcontigs[i * 2 + 1] = vc[1];\r
917       }\r
918       visiblecontigs.removeAllElements();\r
919       return vcontigs;\r
920     }\r
921     else\r
922     {\r
923       return new int[]\r
924       { start, end - 1 };\r
925     }\r
926   }\r
927 \r
928   /**\r
929    * delete any columns in alignmentAnnotation that are hidden (including\r
930    * sequence associated annotation).\r
931    * \r
932    * @param alignmentAnnotation\r
933    */\r
934   public void makeVisibleAnnotation(AlignmentAnnotation alignmentAnnotation)\r
935   {\r
936     makeVisibleAnnotation(-1, -1, alignmentAnnotation);\r
937   }\r
938 \r
939   /**\r
940    * delete any columns in alignmentAnnotation that are hidden (including\r
941    * sequence associated annotation).\r
942    * \r
943    * @param start\r
944    *          remove any annotation to the right of this column\r
945    * @param end\r
946    *          remove any annotation to the left of this column\r
947    * @param alignmentAnnotation\r
948    *          the annotation to operate on\r
949    */\r
950   public void makeVisibleAnnotation(int start, int end,\r
951           AlignmentAnnotation alignmentAnnotation)\r
952   {\r
953     if (alignmentAnnotation.annotations == null)\r
954     {\r
955       return;\r
956     }\r
957     if (start == end && end == -1)\r
958     {\r
959       start = 0;\r
960       end = alignmentAnnotation.annotations.length;\r
961     }\r
962     if (hiddenColumns != null && hiddenColumns.size() > 0)\r
963     {\r
964       // then mangle the alignmentAnnotation annotation array\r
965       Vector annels = new Vector();\r
966       Annotation[] els = null;\r
967       Vector regions = getHiddenColumns();\r
968       int blockStart = start, blockEnd = end;\r
969       int[] region;\r
970       int hideStart, hideEnd, w = 0;\r
971 \r
972       for (int j = 0; j < regions.size(); j++)\r
973       {\r
974         region = (int[]) regions.elementAt(j);\r
975         hideStart = region[0];\r
976         hideEnd = region[1];\r
977 \r
978         if (hideStart < start)\r
979         {\r
980           continue;\r
981         }\r
982 \r
983         blockStart = Math.min(blockStart, hideEnd + 1);\r
984         blockEnd = Math.min(blockEnd, hideStart);\r
985 \r
986         if (blockStart > blockEnd)\r
987         {\r
988           break;\r
989         }\r
990 \r
991         annels.addElement(els = new Annotation[blockEnd - blockStart]);\r
992         System.arraycopy(alignmentAnnotation.annotations, blockStart, els,\r
993                 0, els.length);\r
994         w += els.length;\r
995         blockStart = hideEnd + 1;\r
996         blockEnd = end;\r
997       }\r
998 \r
999       if (end > blockStart)\r
1000       {\r
1001         annels.addElement(els = new Annotation[end - blockStart + 1]);\r
1002         if ((els.length + blockStart) <= alignmentAnnotation.annotations.length)\r
1003         {\r
1004           // copy just the visible segment of the annotation row\r
1005           System.arraycopy(alignmentAnnotation.annotations, blockStart,\r
1006                   els, 0, els.length);\r
1007         }\r
1008         else\r
1009         {\r
1010           // copy to the end of the annotation row\r
1011           System.arraycopy(alignmentAnnotation.annotations, blockStart,\r
1012                   els, 0,\r
1013                   (alignmentAnnotation.annotations.length - blockStart));\r
1014         }\r
1015         w += els.length;\r
1016       }\r
1017       if (w == 0)\r
1018         return;\r
1019       Enumeration e = annels.elements();\r
1020       alignmentAnnotation.annotations = new Annotation[w];\r
1021       w = 0;\r
1022       while (e.hasMoreElements())\r
1023       {\r
1024         Annotation[] chnk = (Annotation[]) e.nextElement();\r
1025         System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w,\r
1026                 chnk.length);\r
1027         w += chnk.length;\r
1028       }\r
1029     }\r
1030     else\r
1031     {\r
1032       alignmentAnnotation.restrict(start, end);\r
1033     }\r
1034   }\r
1035 \r
1036   /**\r
1037    * Invert the column selection from first to end-1. leaves hiddenColumns\r
1038    * untouched (and unselected)\r
1039    * \r
1040    * @param first\r
1041    * @param end\r
1042    */\r
1043   public void invertColumnSelection(int first, int width)\r
1044   {\r
1045     boolean hasHidden = hiddenColumns != null && hiddenColumns.size() > 0;\r
1046     for (int i = first; i < width; i++)\r
1047     {\r
1048       if (contains(i))\r
1049       {\r
1050         removeElement(i);\r
1051       }\r
1052       else\r
1053       {\r
1054         if (!hasHidden || isVisible(i))\r
1055         {\r
1056           addElement(i);\r
1057         }\r
1058       }\r
1059     }\r
1060   }\r
1061 \r
1062   /**\r
1063    * add in any unselected columns from the given column selection, excluding any that are hidden.\r
1064    * @param colsel\r
1065    */\r
1066   public void addElementsFrom(ColumnSelection colsel)\r
1067   {\r
1068     if (colsel != null && colsel.size() > 0)\r
1069     {\r
1070       Enumeration e = colsel.getSelected().elements();\r
1071       while (e.hasMoreElements())\r
1072       {\r
1073         Object eo = e.nextElement();\r
1074         if (hiddenColumns!=null && isVisible(((Integer) eo).intValue())) {\r
1075           if (!selected.contains(eo))\r
1076           {\r
1077             selected.addElement(eo);\r
1078           }\r
1079         }\r
1080       }\r
1081     }\r
1082   }\r
1083 /**\r
1084  * set the selected columns the given column selection, excluding any columns that are hidden. \r
1085  * @param colsel\r
1086  */\r
1087   public void setElementsFrom(ColumnSelection colsel)\r
1088   {\r
1089     if (colsel.selected != null && colsel.selected.size() > 0)\r
1090     {\r
1091       if (hiddenColumns!=null && hiddenColumns.size()>0)\r
1092       {\r
1093         // only select visible columns in this columns selection\r
1094         selected = new Vector();\r
1095         addElementsFrom(colsel);\r
1096       } else {\r
1097         // be quick\r
1098         selected = new Vector(colsel.selected);\r
1099       }\r
1100     }\r
1101     else\r
1102     {\r
1103       selected = new Vector();\r
1104     }\r
1105   }\r
1106 }\r