Implemented CIGAR representation of an Alignment view for passing to
[jalview.git] / src / jalview / datamodel / ColumnSelection.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.datamodel;
20
21 import java.util.*;
22
23 /**
24  * NOTE: Columns are zero based.
25  */
26 public class ColumnSelection
27 {
28     Vector selected = new Vector();
29
30     //Vector of int [] {startCol, endCol}
31     Vector hiddenColumns;
32
33     /**
34      * Add a column to the selection
35      *
36      * @param col index of column
37      */
38     public void addElement(int col)
39     {
40         Integer column = new Integer(col);
41         if (!selected.contains(column))
42         {
43             selected.addElement(column);
44         }
45     }
46
47     /**
48      * clears column selection
49      */
50     public void clear()
51     {
52         selected.removeAllElements();
53     }
54
55     /**
56      * removes col from selection
57      *
58      * @param col index of column to be removed
59      */
60     public void removeElement(int col)
61     {
62         Integer colInt = new Integer(col);
63
64         if (selected.contains(colInt))
65         {
66             selected.removeElement(colInt);
67         }
68     }
69
70     /**
71      * removes a range of columns from the selection
72      * @param start int - first column in range to be removed
73      * @param end int - last col
74      */
75     public void removeElements(int start, int end)
76     {
77       Integer colInt;
78       for(int i=start; i<end; i++)
79       {
80         colInt = new Integer(i);
81         if (selected.contains(colInt))
82         {
83             selected.removeElement(colInt);
84         }
85       }
86     }
87     /**
88      *
89      * @return Vector containing selected columns as Integers
90      */
91     public Vector getSelected()
92     {
93       return selected;
94     }
95
96     /**
97      *
98      * @param col index to search for in column selection
99      *
100      * @return true if Integer(col) is in selection.
101      */
102     public boolean contains(int col)
103     {
104         return selected.contains(new Integer(col));
105     }
106
107     /**
108      * DOCUMENT ME!
109      *
110      * @param i DOCUMENT ME!
111      *
112      * @return DOCUMENT ME!
113      */
114     public int columnAt(int i)
115     {
116         return ((Integer) selected.elementAt(i)).intValue();
117     }
118
119     /**
120      * DOCUMENT ME!
121      *
122      * @return DOCUMENT ME!
123      */
124     public int size()
125     {
126         return selected.size();
127     }
128
129     /**
130      * DOCUMENT ME!
131      *
132      * @return DOCUMENT ME!
133      */
134     public int getMax()
135     {
136         int max = -1;
137
138         for (int i = 0; i < selected.size(); i++)
139         {
140             if (columnAt(i) > max)
141             {
142                 max = columnAt(i);
143             }
144         }
145
146         return max;
147     }
148
149     /**
150      * DOCUMENT ME!
151      *
152      * @return DOCUMENT ME!
153      */
154     public int getMin()
155     {
156         int min = 1000000000;
157
158         for (int i = 0; i < selected.size(); i++)
159         {
160             if (columnAt(i) < min)
161             {
162                 min = columnAt(i);
163             }
164         }
165
166         return min;
167     }
168
169
170     /**
171      * DOCUMENT ME!
172      *
173      * @param start DOCUMENT ME!
174      * @param change DOCUMENT ME!
175      */
176     public void compensateForEdit(int start, int change)
177     {
178         for (int i = 0; i < size(); i++)
179         {
180             int temp = columnAt(i);
181
182             if (temp >= start)
183             {
184                 selected.setElementAt(new Integer(temp - change), i);
185             }
186         }
187
188         if(hiddenColumns!=null)
189         {
190           for(int i=0; i<hiddenColumns.size(); i++)
191           {
192             int[] region = (int[]) hiddenColumns.elementAt(i);
193             if(region[0] > start)
194             {
195               region[0] -= change;
196               region[1] -= change;
197             }
198             if(region[0]<0)
199               region[0] = 0;
200             if(region[1] <0)
201              region[1] = 0;
202           }
203         }
204     }
205
206     /**
207      * This Method is used to return all the HiddenColumn regions
208      * less than the given index.
209      * @param end int
210      * @return Vector
211      */
212     public Vector getHiddenColumns()
213     {
214       return hiddenColumns;
215     }
216     /**
217      * Return absolute column index for a visible column index
218      * @param column int column index in alignment view
219      * @return alignment column index for column
220      */
221     public int adjustForHiddenColumns(int column)
222     {
223       int result = column;
224       if (hiddenColumns != null)
225       {
226         for (int i = 0; i < hiddenColumns.size(); i++)
227         {
228           int[] region = (int[]) hiddenColumns.elementAt(i);
229           if (result >= region[0])
230           {
231             result += region[1] - region[0] + 1;
232           }
233         }
234       }
235       return result;
236     }
237
238     /**
239      * Use this method to find out where a visible column is in the alignment
240      * when hidden columns exist
241      * @param hiddenColumn int
242      * @return int
243      */
244     public int findColumnPosition(int hiddenColumn)
245     {
246       int result = hiddenColumn;
247       if (hiddenColumns != null)
248       {
249         int index = 0;
250         int gaps = 0;
251         do
252         {
253           int[] region = (int[]) hiddenColumns.elementAt(index);
254           if (hiddenColumn > region[1])
255           {
256             result -= region[1]+1-region[0];
257           }
258           index++;
259         }
260         while (index < hiddenColumns.size());
261
262         result -= gaps;
263       }
264
265       return result;
266     }
267
268     /**
269      * Use this method to determine where the next hiddenRegion starts
270     */
271     public int findHiddenRegionPosition(int hiddenRegion)
272     {
273       int result = 0;
274       if (hiddenColumns != null)
275       {
276         int index = 0;
277         int gaps = 0;
278         do
279         {
280           int[] region = (int[]) hiddenColumns.elementAt(index);
281           if(hiddenRegion==0)
282           {
283             return region[0];
284           }
285
286             gaps +=  region[1] +1 - region[0];
287             result = region[1] +1;
288             index++;
289         }
290         while(index < hiddenRegion+1);
291
292         result -= gaps;
293       }
294
295       return result;
296     }
297
298     /**
299      * THis method returns the rightmost limit of a
300      * region of an alignment with hidden columns.
301      * In otherwords, the next hidden column.
302      * @param index int
303      */
304     public int getHiddenBoundaryRight(int alPos)
305     {
306       if (hiddenColumns != null)
307       {
308         int index = 0;
309         do
310         {
311           int[] region = (int[]) hiddenColumns.elementAt(index);
312           if(alPos < region[0])
313             return region[0];
314
315           index++;
316         }
317         while(index < hiddenColumns.size());
318       }
319
320       return alPos;
321
322     }
323     /**
324      * THis method returns the rightmost limit of a
325      * region of an alignment with hidden columns.
326      * In otherwords, the next hidden column.
327      * @param index int
328      */
329     public int getHiddenBoundaryLeft(int alPos)
330     {
331       if (hiddenColumns != null)
332       {
333         int index = hiddenColumns.size()-1;
334         do
335         {
336           int[] region = (int[]) hiddenColumns.elementAt(index);
337           if(alPos > region[1])
338             return region[1];
339
340           index--;
341         }
342         while(index >-1);
343       }
344
345       return alPos;
346
347     }
348
349     public void hideSelectedColumns()
350     {
351       while (size() > 0)
352       {
353         int column = ( (Integer) getSelected().firstElement()).intValue();
354         hideColumns(column);
355       }
356
357     }
358
359     public void hideColumns(int start, int end)
360     {
361       if(hiddenColumns==null)
362         hiddenColumns = new Vector();
363
364       boolean added = false;
365       boolean overlap = false;
366
367       for (int i = 0; i < hiddenColumns.size(); i++)
368       {
369         int[] region = (int[]) hiddenColumns.elementAt(i);
370         if ( start<=region[1] && end>=region[0])
371         {
372           hiddenColumns.removeElementAt(i);
373           overlap = true;
374           break;
375         }
376         else if (end < region[0] && start < region[0])
377         {
378           hiddenColumns.insertElementAt(new int[]
379                                         {start, end}, i);
380           added = true;
381           break;
382         }
383       }
384
385       if(overlap)
386       {
387          hideColumns(start, end);
388       }
389       else if (!added)
390         hiddenColumns.addElement(new int[] {start, end});
391
392     }
393
394     /**
395      * This method will find a range of selected columns
396      * around the column specified
397      * @param res int
398      */
399     public void hideColumns(int col)
400     {
401       // First find out range of columns to hide
402       int min = col, max = col+1;
403       while( contains(min) )
404       {  removeElement(min); min --;  }
405
406       while( contains(max) )
407       { removeElement(max);  max ++;  }
408
409       min++; max--;
410
411       hideColumns(min, max);
412     }
413
414     public void revealAllHiddenColumns()
415     {
416       if(hiddenColumns!=null)
417       {
418         for (int i = 0; i < hiddenColumns.size(); i++)
419         {
420           int[] region = (int[]) hiddenColumns.elementAt(i);
421           for (int j = region[0]; j < region[1]; j++)
422           {
423             addElement(j);
424           }
425         }
426       }
427
428       hiddenColumns = null;
429     }
430
431     public void revealHiddenColumns(int res)
432     {
433       for(int i=0; i<hiddenColumns.size(); i++)
434       {
435         int [] region = (int[])hiddenColumns.elementAt(i);
436         if( res == region[0])
437         {
438           for (int j = region[0]; j < region[1]; j++)
439           {
440             addElement(j);
441           }
442
443           hiddenColumns.removeElement(region);
444           break;
445         }
446       }
447       if(hiddenColumns.size()==0)
448         hiddenColumns = null;
449     }
450
451     public boolean isVisible(int column)
452     {
453       for(int i=0; i<hiddenColumns.size(); i++)
454       {
455         int [] region = (int[])hiddenColumns.elementAt(i);
456         if( column >= region[0] && column <= region[1])
457         {
458           return false;
459         }
460       }
461       return true;
462     }
463
464 }