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