javadoc
[jalview.git] / src / jalview / datamodel / SequenceGroup.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2007 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 import java.awt.*;
24
25 import jalview.analysis.*;
26 import jalview.schemes.*;
27
28 /**
29  * Collects a set contiguous ranges on a set of sequences
30  * @author $author$
31  * @version $Revision$
32  */
33 public class SequenceGroup
34 {
35   String groupName;
36   String description;
37   Conservation conserve;
38   Vector aaFrequency;
39   boolean displayBoxes = true;
40   boolean displayText = true;
41   boolean colourText = false;
42   private Vector sequences = new Vector();
43   int width = -1;
44
45   /** DOCUMENT ME!! */
46   public ColourSchemeI cs;
47   int startRes = 0;
48   int endRes = 0;
49   Color outlineColour = Color.black;
50   public int thresholdTextColour = 0;
51   public Color textColour = Color.black;
52   public Color textColour2 = Color.white;
53
54   /**
55    * Creates a new SequenceGroup object.
56    */
57   public SequenceGroup()
58   {
59     groupName = "JGroup:" + this.hashCode();
60   }
61
62   /**
63    * Creates a new SequenceGroup object.
64    *
65    * @param sequences 
66    * @param groupName 
67    * @param scheme 
68    * @param displayBoxes 
69    * @param displayText 
70    * @param colourText 
71    * @param start first column of group
72    * @param end last column of group
73    */
74   public SequenceGroup(Vector sequences, String groupName,
75                        ColourSchemeI scheme, boolean displayBoxes,
76                        boolean displayText,
77                        boolean colourText, int start, int end)
78   {
79     this.sequences = sequences;
80     this.groupName = groupName;
81     this.displayBoxes = displayBoxes;
82     this.displayText = displayText;
83     this.colourText = colourText;
84     this.cs = scheme;
85     startRes = start;
86     endRes = end;
87     recalcConservation();
88   }
89
90   public SequenceI[] getSelectionAsNewSequences(AlignmentI align)
91   {
92     int iSize = sequences.size();
93     SequenceI[] seqs = new SequenceI[iSize];
94     SequenceI[] inorder = getSequencesInOrder(align);
95     
96     for (int i = 0,ipos=0; i < inorder.length; i++)
97     {
98       SequenceI seq = inorder[i];
99
100       seqs[ipos] = seq.getSubSequence(startRes, endRes+1);
101       if (seqs[ipos]!=null)
102       {
103         seqs[ipos].setDescription(seq.getDescription());
104         seqs[ipos].setDBRef(seq.getDBRef());
105         seqs[ipos].setSequenceFeatures(seq.getSequenceFeatures());
106         if (seq.getDatasetSequence() != null)
107         {
108           seqs[ipos].setDatasetSequence(seq.getDatasetSequence());
109         }
110
111         if (seq.getAnnotation() != null)
112         {
113           AlignmentAnnotation[] alann = align.getAlignmentAnnotation();
114           // Only copy annotation that is either a score or referenced by the alignment's annotation vector
115           for (int a = 0; a < seq.getAnnotation().length; a++)
116           {
117             AlignmentAnnotation tocopy = seq.getAnnotation()[a];
118             if (alann!=null)
119             {
120               boolean found=false;
121               for (int pos=0;pos<alann.length; pos++)
122               {
123                 if (alann[pos]==tocopy)
124                 { 
125                   found=true;
126                   break;
127                 }
128               }
129               if (!found)
130                 continue;
131             }
132             AlignmentAnnotation newannot = new AlignmentAnnotation(seq
133                     .getAnnotation()[a]);
134             newannot.restrict(startRes, endRes);
135             newannot.setSequenceRef(seqs[ipos]);
136             newannot.adjustForAlignment();
137             seqs[ipos].addAlignmentAnnotation(newannot);
138           }
139         }
140         ipos++;
141       } else {
142         iSize--;
143       }
144     }
145     if (iSize!=inorder.length)
146     {
147       SequenceI[] nseqs = new SequenceI[iSize];
148       System.arraycopy(seqs, 0, nseqs, 0, iSize);
149       seqs = nseqs;
150     }
151     return seqs;
152
153   }
154
155   /**
156    * If sequence ends in gaps, the end residue can
157    * be correctly calculated here
158    * @param seq SequenceI
159    * @return int
160    */
161   public int findEndRes(SequenceI seq)
162   {
163     int eres = 0;
164     char ch;
165
166     for (int j = 0; j < endRes + 1 && j < seq.getLength(); j++)
167     {
168       ch = seq.getCharAt(j);
169       if (!jalview.util.Comparison.isGap( (ch)))
170       {
171         eres++;
172       }
173     }
174
175     if (eres > 0)
176     {
177       eres += seq.getStart() - 1;
178     }
179
180     return eres;
181   }
182
183   public Vector getSequences(Hashtable hiddenReps)
184   {
185     if (hiddenReps == null)
186     {
187       return sequences;
188     }
189     else
190     {
191       Vector allSequences = new Vector();
192       SequenceI seq, seq2;
193       for (int i = 0; i < sequences.size(); i++)
194       {
195         seq = (SequenceI) sequences.elementAt(i);
196         allSequences.addElement(seq);
197         if (hiddenReps.containsKey(seq))
198         {
199           SequenceGroup hsg = (SequenceGroup) hiddenReps.get(seq);
200           for (int h = 0; h < hsg.getSize(); h++)
201           {
202             seq2 = hsg.getSequenceAt(h);
203             if (seq2 != seq
204                 && !allSequences.contains(seq2))
205             {
206               allSequences.addElement(seq2);
207             }
208           }
209         }
210       }
211
212       return allSequences;
213     }
214   }
215
216   public SequenceI[] getSequencesAsArray(Hashtable hiddenReps)
217   {
218     Vector tmp = getSequences(hiddenReps);
219     if (tmp == null)
220     {
221       return null;
222     }
223     SequenceI[] result = new SequenceI[tmp.size()];
224     for (int i = 0; i < result.length; i++)
225     {
226       result[i] = (SequenceI) tmp.elementAt(i);
227     }
228
229     return result;
230   }
231
232   /**
233    * DOCUMENT ME!
234    *
235    * @param col DOCUMENT ME!
236    *
237    * @return DOCUMENT ME!
238    */
239   public boolean adjustForRemoveLeft(int col)
240   {
241     // return value is true if the group still exists
242     if (startRes >= col)
243     {
244       startRes = startRes - col;
245     }
246
247     if (endRes >= col)
248     {
249       endRes = endRes - col;
250
251       if (startRes > endRes)
252       {
253         startRes = 0;
254       }
255     }
256     else
257     {
258       // must delete this group!!
259       return false;
260     }
261
262     return true;
263   }
264
265   /**
266    * DOCUMENT ME!
267    *
268    * @param col DOCUMENT ME!
269    *
270    * @return DOCUMENT ME!
271    */
272   public boolean adjustForRemoveRight(int col)
273   {
274     if (startRes > col)
275     {
276       // delete this group
277       return false;
278     }
279
280     if (endRes >= col)
281     {
282       endRes = col;
283     }
284
285     return true;
286   }
287
288   /**
289    * DOCUMENT ME!
290    *
291    * @return DOCUMENT ME!
292    */
293   public String getName()
294   {
295     return groupName;
296   }
297
298   public String getDescription()
299   {
300     return description;
301   }
302
303   /**
304    * DOCUMENT ME!
305    *
306    * @param name DOCUMENT ME!
307    */
308   public void setName(String name)
309   {
310     groupName = name;
311   }
312
313   public void setDescription(String desc)
314   {
315     description = desc;
316   }
317
318   /**
319    * DOCUMENT ME!
320    *
321    * @return DOCUMENT ME!
322    */
323   public Conservation getConservation()
324   {
325     return conserve;
326   }
327
328   /**
329    * DOCUMENT ME!
330    *
331    * @param c DOCUMENT ME!
332    */
333   public void setConservation(Conservation c)
334   {
335     conserve = c;
336   }
337
338   /**
339    * DOCUMENT ME!
340    *
341    * @param s DOCUMENT ME!
342    * @param recalc DOCUMENT ME!
343    */
344   public void addSequence(SequenceI s, boolean recalc)
345   {
346     if (s != null && !sequences.contains(s))
347     {
348       sequences.addElement(s);
349     }
350
351     if (recalc)
352     {
353       recalcConservation();
354     }
355   }
356
357   /**
358    * DOCUMENT ME!
359    */
360   public void recalcConservation()
361   {
362     if (cs == null)
363     {
364       return;
365     }
366
367     try
368     {
369       cs.setConsensus(AAFrequency.calculate(sequences, startRes, endRes + 1));
370
371       if (cs instanceof ClustalxColourScheme)
372       {
373         ( (ClustalxColourScheme) cs).resetClustalX(sequences, getWidth());
374       }
375
376       if (cs.conservationApplied())
377       {
378         Conservation c = new Conservation(groupName,
379                                           ResidueProperties.propHash, 3,
380                                           sequences,
381                                           startRes, endRes + 1);
382         c.calculate();
383         c.verdict(false, 25);
384
385         cs.setConservation(c);
386
387         if (cs instanceof ClustalxColourScheme)
388         {
389           ( (ClustalxColourScheme) cs).resetClustalX(sequences,
390               getWidth());
391         }
392       }
393     }
394     catch (java.lang.OutOfMemoryError err)
395     {
396       System.out.println("Out of memory loading groups: " + err);
397     }
398
399   }
400
401   /**
402    * DOCUMENT ME!
403    *
404    * @param s DOCUMENT ME!
405    * @param recalc DOCUMENT ME!
406    */
407   public void addOrRemove(SequenceI s, boolean recalc)
408   {
409     if (sequences.contains(s))
410     {
411       deleteSequence(s, recalc);
412     }
413     else
414     {
415       addSequence(s, recalc);
416     }
417   }
418
419   /**
420    * DOCUMENT ME!
421    *
422    * @param s DOCUMENT ME!
423    * @param recalc DOCUMENT ME!
424    */
425   public void deleteSequence(SequenceI s, boolean recalc)
426   {
427     sequences.removeElement(s);
428
429     if (recalc)
430     {
431       recalcConservation();
432     }
433   }
434
435   /**
436    * DOCUMENT ME!
437    *
438    * @return DOCUMENT ME!
439    */
440   public int getStartRes()
441   {
442     return startRes;
443   }
444
445   /**
446    * DOCUMENT ME!
447    *
448    * @return DOCUMENT ME!
449    */
450   public int getEndRes()
451   {
452     return endRes;
453   }
454
455   /**
456    * DOCUMENT ME!
457    *
458    * @param i DOCUMENT ME!
459    */
460   public void setStartRes(int i)
461   {
462     startRes = i;
463   }
464
465   /**
466    * DOCUMENT ME!
467    *
468    * @param i DOCUMENT ME!
469    */
470   public void setEndRes(int i)
471   {
472     endRes = i;
473   }
474
475   /**
476    * DOCUMENT ME!
477    *
478    * @return DOCUMENT ME!
479    */
480   public int getSize()
481   {
482     return sequences.size();
483   }
484
485   /**
486    * DOCUMENT ME!
487    *
488    * @param i DOCUMENT ME!
489    *
490    * @return DOCUMENT ME!
491    */
492   public SequenceI getSequenceAt(int i)
493   {
494     return (SequenceI) sequences.elementAt(i);
495   }
496
497   /**
498    * DOCUMENT ME!
499    *
500    * @param state DOCUMENT ME!
501    */
502   public void setColourText(boolean state)
503   {
504     colourText = state;
505   }
506
507   /**
508    * DOCUMENT ME!
509    *
510    * @return DOCUMENT ME!
511    */
512   public boolean getColourText()
513   {
514     return colourText;
515   }
516
517   /**
518    * DOCUMENT ME!
519    *
520    * @param state DOCUMENT ME!
521    */
522   public void setDisplayText(boolean state)
523   {
524     displayText = state;
525   }
526
527   /**
528    * DOCUMENT ME!
529    *
530    * @return DOCUMENT ME!
531    */
532   public boolean getDisplayText()
533   {
534     return displayText;
535   }
536
537   /**
538    * DOCUMENT ME!
539    *
540    * @param state DOCUMENT ME!
541    */
542   public void setDisplayBoxes(boolean state)
543   {
544     displayBoxes = state;
545   }
546
547   /**
548    * DOCUMENT ME!
549    *
550    * @return DOCUMENT ME!
551    */
552   public boolean getDisplayBoxes()
553   {
554     return displayBoxes;
555   }
556
557   /**
558    * DOCUMENT ME!
559    *
560    * @return DOCUMENT ME!
561    */
562   public int getWidth()
563   {
564     // MC This needs to get reset when characters are inserted and deleted
565     if (sequences.size() > 0)
566     {
567       width = ( (SequenceI) sequences.elementAt(0)).getLength();
568     }
569
570     for (int i = 1; i < sequences.size(); i++)
571     {
572       SequenceI seq = (SequenceI) sequences.elementAt(i);
573
574       if (seq.getLength() > width)
575       {
576         width = seq.getLength();
577       }
578     }
579
580     return width;
581   }
582
583   /**
584    * DOCUMENT ME!
585    *
586    * @param c DOCUMENT ME!
587    */
588   public void setOutlineColour(Color c)
589   {
590     outlineColour = c;
591   }
592
593   /**
594    * DOCUMENT ME!
595    *
596    * @return DOCUMENT ME!
597    */
598   public Color getOutlineColour()
599   {
600     return outlineColour;
601   }
602
603   /**
604    *
605    * returns the sequences in the group ordered by the ordering given by al
606    *
607    * @param al Alignment
608    * @return SequenceI[]
609    */
610   public SequenceI[] getSequencesInOrder(AlignmentI al)
611   {
612     int sSize = sequences.size();
613     int alHeight = al.getHeight();
614
615     SequenceI[] seqs = new SequenceI[sSize];
616
617     int index = 0;
618     for (int i = 0; i < alHeight && index < sSize; i++)
619     {
620       if (sequences.contains(al.getSequenceAt(i)))
621       {
622         seqs[index++] = al.getSequenceAt(i);
623       }
624     }
625
626     return seqs;
627   }
628 }