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