Send gapChar to print original Data
[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     /**\r
343      * DOCUMENT ME!\r
344      *\r
345      * @param i DOCUMENT ME!\r
346      *\r
347      * @return DOCUMENT ME!\r
348      */\r
349     public char getCharAt(int i)\r
350     {\r
351         if (i < sequence.length())\r
352         {\r
353             return sequence.charAt(i);\r
354         }\r
355         else\r
356         {\r
357             return ' ';\r
358         }\r
359     }\r
360 \r
361     /**\r
362      * DOCUMENT ME!\r
363      *\r
364      * @param desc DOCUMENT ME!\r
365      */\r
366     public void setDescription(String desc)\r
367     {\r
368         this.description = desc;\r
369     }\r
370 \r
371     /**\r
372      * DOCUMENT ME!\r
373      *\r
374      * @return DOCUMENT ME!\r
375      */\r
376     public String getDescription()\r
377     {\r
378         return this.description;\r
379     }\r
380 \r
381     /**\r
382      * DOCUMENT ME!\r
383      *\r
384      * @param pos DOCUMENT ME!\r
385      *\r
386      * @return DOCUMENT ME!\r
387      */\r
388     public int findIndex(int pos)\r
389     {\r
390         // returns the alignment position for a residue\r
391         int j = start;\r
392         int i = 0;\r
393 \r
394         while ((i < sequence.length()) && (j <= end) && (j <= pos))\r
395         {\r
396             if (!jalview.util.Comparison.isGap(sequence.charAt(i)))\r
397             {\r
398                 j++;\r
399             }\r
400 \r
401             i++;\r
402         }\r
403 \r
404         if ((j == end) && (j < pos))\r
405         {\r
406             return end + 1;\r
407         }\r
408         else\r
409         {\r
410             return i;\r
411         }\r
412     }\r
413 \r
414     /**\r
415      * DOCUMENT ME!\r
416      *\r
417      * @param i DOCUMENT ME!\r
418      *\r
419      * @return DOCUMENT ME!\r
420      */\r
421     public int findPosition(int i)\r
422     {\r
423         // Returns the sequence position for an alignment position\r
424         int j = 0;\r
425         int pos = start;\r
426 \r
427         while ((j < i) && (j < sequence.length()))\r
428         {\r
429             if (!jalview.util.Comparison.isGap((sequence.charAt(j))))\r
430             {\r
431                 pos++;\r
432             }\r
433 \r
434             j++;\r
435         }\r
436 \r
437         return pos;\r
438     }\r
439 \r
440     /**\r
441      * DOCUMENT ME!\r
442      *\r
443      * @return DOCUMENT ME!\r
444      */\r
445     public int[] gapMap()\r
446     {\r
447         // Returns an int array giving the position of each residue in the sequence in the alignment\r
448         String seq = jalview.analysis.AlignSeq.extractGaps(jalview.util.Comparison.GapChars, sequence);\r
449         int[] map = new int[seq.length()];\r
450         int j = 0;\r
451         int p = 0;\r
452 \r
453         while (j < sequence.length())\r
454         {\r
455             if (!jalview.util.Comparison.isGap(sequence.charAt(j)))\r
456             {\r
457                 map[p++] = j;\r
458             }\r
459 \r
460             j++;\r
461         }\r
462 \r
463         return map;\r
464     }\r
465 \r
466     /**\r
467      * DOCUMENT ME!\r
468      *\r
469      * @param i DOCUMENT ME!\r
470      */\r
471     public void deleteCharAt(int i)\r
472     {\r
473         if (i >= sequence.length())\r
474         {\r
475             return;\r
476         }\r
477 \r
478         sequence = sequence.substring(0, i) + sequence.substring(i + 1);\r
479     }\r
480 \r
481     /**\r
482      * DOCUMENT ME!\r
483      *\r
484      * @param i DOCUMENT ME!\r
485      * @param j DOCUMENT ME!\r
486      */\r
487     public void deleteChars(int i, int j)\r
488     {\r
489         if (i >= sequence.length())\r
490         {\r
491             return;\r
492         }\r
493 \r
494         if (j >= sequence.length())\r
495         {\r
496             sequence = sequence.substring(0, i);\r
497         }\r
498         else\r
499         {\r
500             sequence = sequence.substring(0, i) + sequence.substring(j);\r
501         }\r
502     }\r
503 \r
504 \r
505     /**\r
506      * DOCUMENT ME!\r
507      *\r
508      * @param i DOCUMENT ME!\r
509      * @param c DOCUMENT ME!\r
510      * @param chop DOCUMENT ME!\r
511      */\r
512     public void insertCharAt(int i, char c)\r
513     {\r
514         String tmp = new String(sequence);\r
515 \r
516         if (i < sequence.length())\r
517         {\r
518             sequence = tmp.substring(0, i) + String.valueOf(c) +\r
519                 tmp.substring(i);\r
520         }\r
521         else\r
522         {\r
523             // JBPNote : padding char at end of sequence. We'll not get away with this when we insert residues, I bet!\r
524             char[] ch = new char[(1 + i) - sequence.length()];\r
525 \r
526             for (int j = 0, k = ch.length; j < k; j++)\r
527                 ch[j] = c;\r
528 \r
529             sequence = tmp + String.valueOf(ch);\r
530         }\r
531     }\r
532 \r
533     /**\r
534      * DOCUMENT ME!\r
535      *\r
536      * @param c DOCUMENT ME!\r
537      */\r
538     public void setColor(Color c)\r
539     {\r
540         this.color = c;\r
541     }\r
542 \r
543     /**\r
544      * DOCUMENT ME!\r
545      *\r
546      * @return DOCUMENT ME!\r
547      */\r
548     public Color getColor()\r
549     {\r
550         return color;\r
551     }\r
552 \r
553     public String getVamsasId()\r
554     {\r
555       return vamsasId;\r
556     }\r
557 \r
558     public void setVamsasId(String id)\r
559     {\r
560       vamsasId = id;\r
561     }\r
562 \r
563     public void setDBRef(DBRefEntry [] dbref)\r
564     {\r
565       dbrefs = dbref;\r
566     }\r
567 \r
568     public DBRefEntry [] getDBRef()\r
569     {\r
570       return dbrefs;\r
571     }\r
572 \r
573     public void addDBRef(DBRefEntry entry)\r
574     {\r
575       if(dbrefs == null)\r
576         dbrefs = new DBRefEntry[0];\r
577 \r
578       DBRefEntry [] temp = new DBRefEntry[dbrefs.length+1];\r
579       System.arraycopy(dbrefs, 0, temp, 0, dbrefs.length);\r
580 \r
581       temp[temp.length-1] = entry;\r
582 \r
583       dbrefs = temp;\r
584     }\r
585 \r
586     public void setDatasetSequence(SequenceI seq)\r
587     {\r
588       datasetSequence = seq;\r
589     }\r
590 \r
591     public SequenceI getDatasetSequence()\r
592     {\r
593       return datasetSequence;\r
594     }\r
595 \r
596     public AlignmentAnnotation [] getAnnotation()\r
597     {\r
598       if(annotation==null)\r
599         return null;\r
600 \r
601       AlignmentAnnotation [] ret = new AlignmentAnnotation[annotation.size()];\r
602       for(int r = 0; r<ret.length; r++)\r
603         ret[r] = (AlignmentAnnotation)annotation.elementAt(r);\r
604 \r
605       return ret;\r
606     }\r
607 \r
608     public void addAlignmentAnnotation(AlignmentAnnotation annotation)\r
609     {\r
610       if(this.annotation==null)\r
611         this.annotation = new Vector();\r
612 \r
613       this.annotation.addElement( annotation );\r
614     }\r
615 \r
616     public SequenceGroup getHiddenSequences()\r
617     {\r
618       return hiddenSequences;\r
619     }\r
620 \r
621     public void addHiddenSequence(SequenceI seq)\r
622     {\r
623       if(hiddenSequences==null)\r
624       {\r
625         hiddenSequences = new SequenceGroup();\r
626       }\r
627       hiddenSequences.addSequence(seq, false);\r
628     }\r
629 \r
630     public void showHiddenSequence(SequenceI seq)\r
631     {\r
632       hiddenSequences.deleteSequence(seq, false);\r
633       if (hiddenSequences.getSize(false) < 1)\r
634       {\r
635         hiddenSequences = null;\r
636       }\r
637     }\r
638 \r
639     public void changeCase(boolean toUpper, int start, int end)\r
640     {\r
641       StringBuffer newSeq = new StringBuffer();\r
642 \r
643       if(end>sequence.length())\r
644         end = sequence.length();\r
645 \r
646       if (start > 0)\r
647       {\r
648         newSeq.append(sequence.substring(0, start));\r
649       }\r
650 \r
651       if (toUpper)\r
652         newSeq.append(sequence.substring(start, end).toUpperCase());\r
653       else\r
654         newSeq.append(sequence.substring(start, end).toLowerCase());\r
655 \r
656       if (end < sequence.length())\r
657         newSeq.append(sequence.substring(end));\r
658 \r
659       sequence = newSeq.toString();\r
660     }\r
661 \r
662     public void toggleCase(int start, int end)\r
663     {\r
664       StringBuffer newSeq = new StringBuffer();\r
665 \r
666      if(end>sequence.length())\r
667        end = sequence.length();\r
668 \r
669      if (start > 0)\r
670      {\r
671        newSeq.append(sequence.substring(0, start));\r
672      }\r
673 \r
674      char nextChar;\r
675      for(int c=start; c<end; c++)\r
676      {\r
677        nextChar = sequence.charAt(c);\r
678        if(Character.isLetter(nextChar))\r
679        {\r
680          if(Character.isUpperCase(nextChar))\r
681            nextChar = Character.toLowerCase(nextChar);\r
682          else\r
683            nextChar = Character.toUpperCase(nextChar);\r
684        }\r
685 \r
686 \r
687        newSeq.append(nextChar);\r
688      }\r
689 \r
690      if (end < sequence.length())\r
691        newSeq.append(sequence.substring(end));\r
692 \r
693      sequence = newSeq.toString();\r
694     }\r
695 \r
696 }\r