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