changeCase, removeGaps moved to commands package
[jalview.git] / src / jalview / datamodel / Sequence.java
1 /*
2 * Jalview - A Sequence Alignment Editor and Viewer
3 * Copyright (C) 2006 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.awt.*;
22
23 import java.util.*;
24
25
26 /**
27  * DOCUMENT ME!
28  *
29  * @author $author$
30  * @version $Revision$
31  */
32 public class Sequence implements SequenceI
33 {
34   SequenceI datasetSequence;
35   String name;
36   private String sequence;
37   String description;
38   int start;
39   int end;
40   Color color = Color.white;
41   Vector pdbIds;
42   String vamsasId;
43   DBRefEntry[] dbrefs;
44
45   /** This annotation is displayed below the alignment but the
46    * positions are tied to the residues of this sequence */
47   Vector annotation;
48
49   /** DOCUMENT ME!! */
50   public SequenceFeature[] sequenceFeatures;
51
52   /** This array holds hidden sequences
53    * of which this sequence is the representitive member of a group
54    */
55   SequenceGroup hiddenSequences;
56
57   /**
58    * Creates a new Sequence object.
59    *
60    * @param name DOCUMENT ME!
61    * @param sequence DOCUMENT ME!
62    * @param start DOCUMENT ME!
63    * @param end DOCUMENT ME!
64    */
65   public Sequence(String name, String sequence, int start, int end)
66   {
67     this.name = name;
68     this.sequence = sequence;
69     this.start = start;
70     this.end = end;
71
72     parseId();
73
74     checkValidRange();
75   }
76
77   com.stevesoft.pat.Regex limitrx = new com.stevesoft.pat.Regex(
78       "[/][0-9]{1,}[-][0-9]{1,}$");
79   com.stevesoft.pat.Regex endrx = new com.stevesoft.pat.Regex(
80       "[0-9]{1,}$");
81
82   void parseId()
83   {
84     // Does sequence have the /start-end signiature?
85     if (limitrx.search(name))
86     {
87       name = limitrx.left();
88       endrx.search(limitrx.stringMatched());
89       setStart(Integer.parseInt(limitrx.stringMatched().substring(1,
90           endrx.matchedFrom() - 1)));
91       setEnd(Integer.parseInt(endrx.stringMatched()));
92     }
93   }
94
95   void checkValidRange()
96   {
97     if (end < 1)
98     {
99       int endRes = 0;
100       char ch;
101       for (int j = 0; j < sequence.length(); j++)
102       {
103         ch = sequence.charAt(j);
104         if (!jalview.util.Comparison.isGap( (ch)))
105         {
106           endRes++;
107         }
108       }
109       if (endRes > 0)
110       {
111         endRes += start - 1;
112       }
113
114       this.end = endRes;
115     }
116
117   }
118
119   /**
120    * Creates a new Sequence object.
121    *
122    * @param name DOCUMENT ME!
123    * @param sequence DOCUMENT ME!
124    */
125   public Sequence(String name, String sequence)
126   {
127     this(name, sequence, 1, -1);
128   }
129
130   /**
131    * Creates a new Sequence object.
132    *
133    * @param seq DOCUMENT ME!
134    */
135   public Sequence(SequenceI seq)
136   {
137     this(seq.getName(), seq.getSequence(), seq.getStart(), seq.getEnd());
138   }
139
140   /**
141    * DOCUMENT ME!
142    *
143    * @param v DOCUMENT ME!
144    */
145   public void setSequenceFeatures(SequenceFeature[] features)
146   {
147     sequenceFeatures = features;
148   }
149
150   public synchronized void addSequenceFeature(SequenceFeature sf)
151   {
152     if (sequenceFeatures == null)
153     {
154       sequenceFeatures = new SequenceFeature[0];
155     }
156
157     for (int i = 0; i < sequenceFeatures.length; i++)
158     {
159       if (sequenceFeatures[i].equals(sf))
160       {
161         return;
162       }
163     }
164
165     SequenceFeature[] temp = new SequenceFeature[sequenceFeatures.length + 1];
166     System.arraycopy(sequenceFeatures, 0, temp, 0, sequenceFeatures.length);
167     temp[sequenceFeatures.length] = sf;
168
169     sequenceFeatures = temp;
170   }
171
172   /**
173    * DOCUMENT ME!
174    *
175    * @return DOCUMENT ME!
176    */
177   public SequenceFeature[] getSequenceFeatures()
178   {
179     return sequenceFeatures;
180   }
181
182   public void addPDBId(PDBEntry entry)
183   {
184     if (pdbIds == null)
185       pdbIds = new Vector();
186
187     pdbIds.addElement(entry);
188   }
189
190   /**
191    * DOCUMENT ME!
192    *
193    * @param id DOCUMENT ME!
194    */
195   public void setPDBId(Vector id)
196   {
197     pdbIds = id;
198   }
199
200   /**
201    * DOCUMENT ME!
202    *
203    * @return DOCUMENT ME!
204    */
205   public Vector getPDBId()
206   {
207     return pdbIds;
208   }
209
210   /**
211    * DOCUMENT ME!
212    *
213    * @return DOCUMENT ME!
214    */
215   public String getDisplayId(boolean jvsuffix)
216   {
217     StringBuffer result = new StringBuffer(name);
218     if (jvsuffix)
219     {
220       result.append("/" + start + "-" + end);
221     }
222
223     return result.toString();
224   }
225
226   /**
227    * DOCUMENT ME!
228    *
229    * @param name DOCUMENT ME!
230    */
231   public void setName(String name)
232   {
233     this.name = name;
234     this.parseId();
235   }
236
237   /**
238    * DOCUMENT ME!
239    *
240    * @return DOCUMENT ME!
241    */
242   public String getName()
243   {
244     return this.name;
245   }
246
247   /**
248    * DOCUMENT ME!
249    *
250    * @param start DOCUMENT ME!
251    */
252   public void setStart(int start)
253   {
254     this.start = start;
255   }
256
257   /**
258    * DOCUMENT ME!
259    *
260    * @return DOCUMENT ME!
261    */
262   public int getStart()
263   {
264     return this.start;
265   }
266
267   /**
268    * DOCUMENT ME!
269    *
270    * @param end DOCUMENT ME!
271    */
272   public void setEnd(int end)
273   {
274     this.end = end;
275   }
276
277   /**
278    * DOCUMENT ME!
279    *
280    * @return DOCUMENT ME!
281    */
282   public int getEnd()
283   {
284     return this.end;
285   }
286
287   /**
288    * DOCUMENT ME!
289    *
290    * @return DOCUMENT ME!
291    */
292   public int getLength()
293   {
294     return this.sequence.length();
295   }
296
297   /**
298    * DOCUMENT ME!
299    *
300    * @param seq DOCUMENT ME!
301    */
302   public void setSequence(String seq)
303   {
304     this.sequence = seq;
305     checkValidRange();
306   }
307
308   /**
309    * DOCUMENT ME!
310    *
311    * @return DOCUMENT ME!
312    */
313   public String getSequence()
314   {
315     return this.sequence;
316   }
317
318   /**
319    * DOCUMENT ME!
320    *
321    * @param start DOCUMENT ME!
322    * @param end DOCUMENT ME!
323    *
324    * @return DOCUMENT ME!
325    */
326   public String getSequence(int start, int end)
327   {
328     // JBPNote - left to user to pad the result here (TODO:Decide on this policy)
329     if (start >= sequence.length())
330     {
331       return "";
332     }
333
334     if (end >= sequence.length())
335     {
336       end = sequence.length();
337     }
338
339     return this.sequence.substring(start, end);
340   }
341
342   /**
343    * make a new Sequence object from start to end (including gaps) over this seqeunce
344    * @param start int
345    * @param end int
346    * @return SequenceI
347    */
348   public SequenceI getSubSequence(int start, int end)
349   {
350     if (start < 0)
351       start = 0;
352     String seq = getSequence(start, end);
353     if (seq == "")
354       return null;
355     int nstart = findPosition(start);
356     int nend = findPosition(end) - 1;
357     // JBPNote - this is an incomplete copy.
358     SequenceI nseq = new Sequence(this.getName(), seq, nstart, nend);
359     nseq.setDatasetSequence(getDatasetSequence());
360     return nseq;
361   }
362
363   /**
364    * DOCUMENT ME!
365    *
366    * @param i DOCUMENT ME!
367    *
368    * @return DOCUMENT ME!
369    */
370   public char getCharAt(int i)
371   {
372     if (i < sequence.length())
373     {
374       return sequence.charAt(i);
375     }
376     else
377     {
378       return ' ';
379     }
380   }
381
382   /**
383    * DOCUMENT ME!
384    *
385    * @param desc DOCUMENT ME!
386    */
387   public void setDescription(String desc)
388   {
389     this.description = desc;
390   }
391
392   /**
393    * DOCUMENT ME!
394    *
395    * @return DOCUMENT ME!
396    */
397   public String getDescription()
398   {
399     return this.description;
400   }
401
402   /**
403    * DOCUMENT ME!
404    *
405    * @param pos DOCUMENT ME!
406    *
407    * @return DOCUMENT ME!
408    */
409   public int findIndex(int pos)
410   {
411     // returns the alignment position for a residue
412     int j = start;
413     int i = 0;
414
415     while ( (i < sequence.length()) && (j <= end) && (j <= pos))
416     {
417       if (!jalview.util.Comparison.isGap(sequence.charAt(i)))
418       {
419         j++;
420       }
421
422       i++;
423     }
424
425     if ( (j == end) && (j < pos))
426     {
427       return end + 1;
428     }
429     else
430     {
431       return i;
432     }
433   }
434
435   /**
436    * Returns the sequence position for an alignment position
437    *
438    * @param i column index in alignment (from 1)
439    *
440    * @return residue number for residue (left of and) nearest ith column
441    */
442   public int findPosition(int i)
443   {
444     int j = 0;
445     int pos = start;
446     int seqlen = sequence.length();
447     while ( (j < i) && (j < seqlen))
448     {
449       if (!jalview.util.Comparison.isGap( (sequence.charAt(j))))
450       {
451         pos++;
452       }
453
454       j++;
455     }
456
457     return pos;
458   }
459
460   /**
461    * Returns an int array where indices correspond to each residue in the sequence and the element value gives its position in the alignment
462    *
463    * @return int[SequenceI.getEnd()-SequenceI.getStart()+1] or null if no residues in SequenceI object
464    */
465   public int[] gapMap()
466   {
467     String seq = jalview.analysis.AlignSeq.extractGaps(jalview.util.Comparison.
468         GapChars, sequence);
469     int[] map = new int[seq.length()];
470     int j = 0;
471     int p = 0;
472
473     while (j < sequence.length())
474     {
475       if (!jalview.util.Comparison.isGap(sequence.charAt(j)))
476       {
477         map[p++] = j;
478       }
479
480       j++;
481     }
482
483     return map;
484   }
485
486   /**
487    * DOCUMENT ME!
488    *
489    * @param i DOCUMENT ME!
490    */
491   public void deleteCharAt(int i)
492   {
493     if (i >= sequence.length())
494     {
495       return;
496     }
497
498     sequence = sequence.substring(0, i) + sequence.substring(i + 1);
499   }
500
501   /**
502    * DOCUMENT ME!
503    *
504    * @param i DOCUMENT ME!
505    * @param j DOCUMENT ME!
506    */
507   public void deleteChars(int i, int j)
508   {
509     if (i >= sequence.length())
510     {
511       return;
512     }
513
514     if (j >= sequence.length())
515     {
516       sequence = sequence.substring(0, i);
517     }
518     else
519     {
520       sequence = sequence.substring(0, i) + sequence.substring(j);
521     }
522   }
523
524   /**
525    * DOCUMENT ME!
526    *
527    * @param i DOCUMENT ME!
528    * @param c DOCUMENT ME!
529    * @param chop DOCUMENT ME!
530    */
531   public void insertCharAt(int i, int length, char c)
532   {
533     StringBuffer tmp;
534
535     if (i >= sequence.length())
536     {
537       length = i - sequence.length() + 1;
538       tmp = new StringBuffer(sequence);
539     }
540     else
541       tmp = new StringBuffer(sequence.substring(0, i));
542
543     while (length > 0)
544     {
545       tmp.append(c);
546       length--;
547     }
548
549     if (i < sequence.length())
550     {
551       tmp.append(sequence.substring(i));
552     }
553
554     sequence = tmp.toString();
555   }
556
557   public void insertCharAt(int i, char c)
558   {
559     insertCharAt(i, 1, c);
560   }
561
562   /**
563    * DOCUMENT ME!
564    *
565    * @param c DOCUMENT ME!
566    */
567   public void setColor(Color c)
568   {
569     this.color = c;
570   }
571
572   /**
573    * DOCUMENT ME!
574    *
575    * @return DOCUMENT ME!
576    */
577   public Color getColor()
578   {
579     return color;
580   }
581
582   public String getVamsasId()
583   {
584     return vamsasId;
585   }
586
587   public void setVamsasId(String id)
588   {
589     vamsasId = id;
590   }
591
592   public void setDBRef(DBRefEntry[] dbref)
593   {
594     dbrefs = dbref;
595   }
596
597   public DBRefEntry[] getDBRef()
598   {
599     return dbrefs;
600   }
601
602   public void addDBRef(DBRefEntry entry)
603   {
604     if (dbrefs == null)
605       dbrefs = new DBRefEntry[0];
606
607     DBRefEntry[] temp = new DBRefEntry[dbrefs.length + 1];
608     System.arraycopy(dbrefs, 0, temp, 0, dbrefs.length);
609
610     temp[temp.length - 1] = entry;
611
612     dbrefs = temp;
613   }
614
615   public void setDatasetSequence(SequenceI seq)
616   {
617     datasetSequence = seq;
618   }
619
620   public SequenceI getDatasetSequence()
621   {
622     return datasetSequence;
623   }
624
625   public AlignmentAnnotation[] getAnnotation()
626   {
627     if (annotation == null)
628       return null;
629
630     AlignmentAnnotation[] ret = new AlignmentAnnotation[annotation.size()];
631     for (int r = 0; r < ret.length; r++)
632       ret[r] = (AlignmentAnnotation) annotation.elementAt(r);
633
634     return ret;
635   }
636
637   public void addAlignmentAnnotation(AlignmentAnnotation annotation)
638   {
639     if (this.annotation == null)
640       this.annotation = new Vector();
641
642     this.annotation.addElement(annotation);
643   }
644
645   public SequenceGroup getHiddenSequences()
646   {
647     return hiddenSequences;
648   }
649
650   public void addHiddenSequence(SequenceI seq)
651   {
652     if (hiddenSequences == null)
653     {
654       hiddenSequences = new SequenceGroup();
655     }
656     hiddenSequences.addSequence(seq, false);
657   }
658
659   public void showHiddenSequence(SequenceI seq)
660   {
661     hiddenSequences.deleteSequence(seq, false);
662     if (hiddenSequences.getSize(false) < 1)
663     {
664       hiddenSequences = null;
665     }
666   }
667 }
668
669