resolve 1:many mappings for sequence associated annotation to all alignment sequence...
[jalview.git] / src / jalview / io / AnnotationFile.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2007 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 \r
20 package jalview.io;\r
21 \r
22 import java.io.*;\r
23 import java.net.*;\r
24 import java.util.*;\r
25 \r
26 import jalview.analysis.*;\r
27 import jalview.datamodel.*;\r
28 import jalview.schemes.*;\r
29 \r
30 public class AnnotationFile\r
31 {\r
32   StringBuffer text = new StringBuffer(\r
33       "JALVIEW_ANNOTATION\n"\r
34       + "# Created: "\r
35       + new java.util.Date() + "\n\n");\r
36   /**\r
37    * convenience method for pre-2.4 feature files which have no view, hidden columns or hidden row keywords.\r
38    * @param annotations\r
39    * @param groups\r
40    * @param properties\r
41    * @return feature file as a string.\r
42    */\r
43   public String printAnnotations(AlignmentAnnotation[] annotations,\r
44                                  Vector groups,\r
45                                  Hashtable properties)\r
46   {\r
47     return printAnnotations(annotations, groups,\r
48             properties, null);\r
49 \r
50   }\r
51   /**\r
52    * hold all the information about a particular view definition\r
53    * read from or written out in an annotations file.\r
54    */\r
55   public class ViewDef {\r
56     public String viewname;\r
57     public HiddenSequences hidseqs;\r
58     public ColumnSelection hiddencols;\r
59     public Vector visibleGroups;\r
60     public ViewDef(String viewname, HiddenSequences hidseqs,\r
61             ColumnSelection hiddencols)\r
62     {\r
63       this.viewname = viewname;\r
64       this.hidseqs = hidseqs;\r
65       this.hiddencols = hiddencols;\r
66     }\r
67   }\r
68   public String printAnnotations(AlignmentAnnotation[] annotations,\r
69           Vector groups,\r
70           Hashtable properties, ViewDef[] views)\r
71   {\r
72     if (annotations != null)\r
73     {\r
74       boolean oneColour = true;\r
75       AlignmentAnnotation row;\r
76       String comma;\r
77       SequenceI refSeq = null;\r
78 \r
79       StringBuffer colours = new StringBuffer();\r
80       StringBuffer graphLine = new StringBuffer();\r
81 \r
82       Hashtable graphGroup = new Hashtable();\r
83 \r
84       java.awt.Color color;\r
85 \r
86       for (int i = 0; i < annotations.length; i++)\r
87       {\r
88         row = annotations[i];\r
89 \r
90         if (!row.visible && !row.hasScore())\r
91         {\r
92           continue;\r
93         }\r
94 \r
95         color = null;\r
96         oneColour = true;\r
97 \r
98         if (row.sequenceRef == null)\r
99         {\r
100           if (refSeq != null)\r
101           {\r
102             text.append("\nSEQUENCE_REF\tALIGNMENT\n");\r
103           }\r
104 \r
105           refSeq = null;\r
106         }\r
107 \r
108         else if (refSeq == null || refSeq != row.sequenceRef)\r
109         {\r
110           refSeq = row.sequenceRef;\r
111           text.append("\nSEQUENCE_REF\t" + refSeq.getName() + "\n");\r
112         }\r
113 \r
114         if (row.graph == AlignmentAnnotation.NO_GRAPH)\r
115         {\r
116           text.append("NO_GRAPH\t");\r
117         }\r
118         else\r
119         {\r
120           if (row.graph == AlignmentAnnotation.BAR_GRAPH)\r
121           {\r
122             text.append("BAR_GRAPH\t");\r
123           }\r
124           else if (row.graph == AlignmentAnnotation.LINE_GRAPH)\r
125           {\r
126             text.append("LINE_GRAPH\t");\r
127           }\r
128 \r
129           if (row.getThreshold() != null)\r
130           {\r
131             graphLine.append("GRAPHLINE\t"\r
132                              + row.label + "\t"\r
133                              + row.getThreshold().value + "\t"\r
134                              + row.getThreshold().label + "\t"\r
135                              + jalview.util.Format.getHexString(\r
136                                  row.getThreshold().colour) + "\n"\r
137                 );\r
138           }\r
139 \r
140           if (row.graphGroup > -1)\r
141           {\r
142             String key = String.valueOf(row.graphGroup);\r
143             if (graphGroup.containsKey(key))\r
144             {\r
145               graphGroup.put(key, graphGroup.get(key)\r
146                              + "\t" + row.label);\r
147             }\r
148             else\r
149             {\r
150               graphGroup.put(key, row.label);\r
151             }\r
152           }\r
153         }\r
154 \r
155         text.append(row.label + "\t");\r
156         if (row.description != null)\r
157         {\r
158           text.append(row.description + "\t");\r
159         }\r
160 \r
161         for (int j = 0; row.annotations!=null && j < row.annotations.length; j++)\r
162         {\r
163           if (refSeq != null &&\r
164               jalview.util.Comparison.isGap(refSeq.getCharAt(j)))\r
165           {\r
166             continue;\r
167           }\r
168 \r
169           if (row.annotations[j] != null)\r
170           {\r
171             comma = "";\r
172             if (row.annotations[j].secondaryStructure != ' ')\r
173             {\r
174               text.append(comma + row.annotations[j].secondaryStructure);\r
175               comma = ",";\r
176             }\r
177             if (row.annotations[j].displayCharacter!=null\r
178                 && row.annotations[j].displayCharacter.length() > 0\r
179                 && !row.annotations[j].displayCharacter.equals(" "))\r
180             {\r
181               text.append(comma + row.annotations[j].displayCharacter);\r
182               comma = ",";\r
183             }\r
184 \r
185             if (row.annotations[j] != null)\r
186             {\r
187               if(color!=null && !color.equals(row.annotations[j].colour))\r
188               {\r
189                 oneColour = false;\r
190               }\r
191 \r
192               color = row.annotations[j].colour;\r
193               if (row.annotations[j].value != 0f)\r
194               {\r
195                 text.append(comma + row.annotations[j].value);\r
196               }\r
197             }\r
198 \r
199             if(row.annotations[j].colour!=null\r
200                && row.annotations[j].colour!=java.awt.Color.black)\r
201             {\r
202               text.append(comma+"["+\r
203                           jalview.util.Format.getHexString(\r
204                           row.annotations[j].colour)+"]");\r
205             }\r
206           }\r
207           text.append("|");\r
208         }\r
209 \r
210         if(row.hasScore())\r
211           text.append("\t"+row.score);\r
212 \r
213         text.append("\n");\r
214 \r
215         if (color != null && color != java.awt.Color.black && oneColour)\r
216         {\r
217           colours.append("COLOUR\t"\r
218                          + row.label + "\t"\r
219                          + jalview.util.Format.getHexString(color) + "\n");\r
220         }\r
221 \r
222       }\r
223 \r
224       text.append("\n");\r
225 \r
226       text.append(colours.toString());\r
227       text.append(graphLine.toString());\r
228       if (graphGroup.size() > 0)\r
229       {\r
230         text.append("COMBINE\t");\r
231         Enumeration en = graphGroup.elements();\r
232         while (en.hasMoreElements())\r
233         {\r
234           text.append(en.nextElement() + "\n");\r
235         }\r
236       }\r
237     }\r
238 \r
239     if (groups != null)\r
240     {\r
241       printGroups(groups);\r
242     }\r
243 \r
244     if(properties!=null)\r
245     {\r
246       text.append("\n\nALIGNMENT");\r
247       Enumeration en = properties.keys();\r
248       while(en.hasMoreElements())\r
249       {\r
250         String key = en.nextElement().toString();\r
251         text.append("\t"+key+"="+properties.get(key));\r
252       }\r
253 \r
254     }\r
255     \r
256     return text.toString();\r
257   }\r
258 \r
259   public void printGroups(Vector sequenceGroups)\r
260   {\r
261     SequenceGroup sg;\r
262     for (int i = 0; i < sequenceGroups.size(); i++)\r
263     {\r
264       sg = (SequenceGroup) sequenceGroups.elementAt(i);\r
265       text.append("SEQUENCE_GROUP\t"\r
266                   + sg.getName() + "\t"\r
267                   + (sg.getStartRes() + 1) + "\t"\r
268                   + (sg.getEndRes() + 1) + "\t" + "-1\t");\r
269       for (int s = 0; s < sg.getSize(); s++)\r
270       {\r
271         text.append(sg.getSequenceAt(s).getName() + "\t");\r
272       }\r
273 \r
274       text.append("\nPROPERTIES\t" + sg.getName() + "\t");\r
275 \r
276       if (sg.getDescription() != null)\r
277       {\r
278         text.append("description=" + sg.getDescription() + "\t");\r
279       }\r
280       if (sg.cs != null)\r
281       {\r
282         text.append("colour=" + ColourSchemeProperty.getColourName(sg.cs) +\r
283                     "\t");\r
284         if (sg.cs.getThreshold() != 0)\r
285         {\r
286           text.append("pidThreshold=" + sg.cs.getThreshold());\r
287         }\r
288         if (sg.cs.conservationApplied())\r
289         {\r
290           text.append("consThreshold=" + sg.cs.getConservationInc() + "\t");\r
291         }\r
292       }\r
293       text.append("outlineColour=" +\r
294                   jalview.util.Format.getHexString(sg.getOutlineColour()) +\r
295                   "\t");\r
296 \r
297       text.append("displayBoxes=" + sg.getDisplayBoxes() + "\t");\r
298       text.append("displayText=" + sg.getDisplayText() + "\t");\r
299       text.append("colourText=" + sg.getColourText() + "\t");\r
300 \r
301       if (sg.textColour != java.awt.Color.black)\r
302       {\r
303         text.append("textCol1=" +\r
304                     jalview.util.Format.getHexString(sg.textColour) + "\t");\r
305       }\r
306       if (sg.textColour2 != java.awt.Color.white)\r
307       {\r
308         text.append("textCol2=" +\r
309                     jalview.util.Format.getHexString(sg.textColour2) + "\t");\r
310       }\r
311       if (sg.thresholdTextColour != 0)\r
312       {\r
313         text.append("textColThreshold=" + sg.thresholdTextColour);\r
314       }\r
315       if (sg.idColour!=null)\r
316       {\r
317         text.append("idColour="+jalview.util.Format.getHexString(sg.idColour)+"\t");\r
318       }\r
319 \r
320       text.append("\n\n");\r
321 \r
322     }\r
323   }\r
324 \r
325   SequenceI refSeq = null;\r
326   String refSeqId = null;\r
327   public boolean readAnnotationFile(AlignmentI al,\r
328                                     String file,\r
329                                     String protocol)\r
330   {\r
331     try\r
332     {\r
333       BufferedReader in = null;\r
334       if (protocol.equals(AppletFormatAdapter.FILE))\r
335       {\r
336         in = new BufferedReader(new FileReader(file));\r
337       }\r
338       else if (protocol.equals(AppletFormatAdapter.URL))\r
339       {\r
340         URL url = new URL(file);\r
341         in = new BufferedReader(new InputStreamReader(url.openStream()));\r
342       }\r
343       else if (protocol.equals(AppletFormatAdapter.PASTE))\r
344       {\r
345         in = new BufferedReader(new StringReader(file));\r
346       }\r
347       else if (protocol.equals(AppletFormatAdapter.CLASSLOADER))\r
348       {\r
349         java.io.InputStream is = getClass().getResourceAsStream("/" + file);\r
350         if (is != null)\r
351         {\r
352           in = new BufferedReader(new java.io.InputStreamReader(is));\r
353         }\r
354       }\r
355 \r
356       String line, label, description, token;\r
357       int graphStyle, index;\r
358       int refSeqIndex = 1;\r
359       int existingAnnotations = 0;\r
360       if (al.getAlignmentAnnotation() != null)\r
361       {\r
362         existingAnnotations = al.getAlignmentAnnotation().length;\r
363       }\r
364 \r
365       int alWidth = al.getWidth();\r
366 \r
367       StringTokenizer st;\r
368       Annotation[] annotations;\r
369       AlignmentAnnotation annotation = null;\r
370 \r
371       // First confirm this is an Annotation file\r
372       boolean jvAnnotationFile = false;\r
373       while ( (line = in.readLine()) != null)\r
374       {\r
375         if (line.indexOf("#") == 0)\r
376         {\r
377           continue;\r
378         }\r
379 \r
380         if (line.indexOf("JALVIEW_ANNOTATION") > -1)\r
381         {\r
382           jvAnnotationFile = true;\r
383           break;\r
384         }\r
385       }\r
386 \r
387       if (!jvAnnotationFile)\r
388       {\r
389         in.close();\r
390         return false;\r
391       }\r
392 \r
393       while ( (line = in.readLine()) != null)\r
394       {\r
395         if (line.indexOf("#") == 0\r
396             || line.indexOf("JALVIEW_ANNOTATION") > -1\r
397             || line.length() == 0)\r
398         {\r
399           continue;\r
400         }\r
401 \r
402         st = new StringTokenizer(line, "\t");\r
403         token = st.nextToken();\r
404         if (token.equalsIgnoreCase("COLOUR"))\r
405         {\r
406           colourAnnotations(al, st.nextToken(), st.nextToken());\r
407           continue;\r
408         }\r
409 \r
410         else if (token.equalsIgnoreCase("COMBINE"))\r
411         {\r
412           combineAnnotations(al, st);\r
413           continue;\r
414         }\r
415 \r
416         else if (token.equalsIgnoreCase("GRAPHLINE"))\r
417         {\r
418           addLine(al, st);\r
419           continue;\r
420         }\r
421 \r
422         else if (token.equalsIgnoreCase("SEQUENCE_REF"))\r
423         {\r
424           if (st.hasMoreTokens())\r
425           {\r
426             refSeq = al.findName(refSeqId=st.nextToken());\r
427           if (refSeq==null)\r
428           {\r
429             refSeqId=null;\r
430           }\r
431           try\r
432           {\r
433             refSeqIndex = Integer.parseInt(st.nextToken());\r
434             if (refSeqIndex < 1)\r
435             {\r
436               refSeqIndex = 1;\r
437               System.out.println(\r
438                   "WARNING: SEQUENCE_REF index must be > 0 in AnnotationFile");\r
439             }\r
440           }\r
441           catch (Exception ex)\r
442           {\r
443             refSeqIndex = 1;\r
444           }\r
445           } else {\r
446             refSeq = null;\r
447             refSeqId = null;\r
448           }\r
449           continue ;\r
450         }\r
451 \r
452         else if (token.equalsIgnoreCase("SEQUENCE_GROUP"))\r
453         {\r
454           addGroup(al, st);\r
455           continue;\r
456         }\r
457 \r
458         else if (token.equalsIgnoreCase("PROPERTIES"))\r
459         {\r
460           addProperties(al, st);\r
461           continue;\r
462         }\r
463 \r
464         else if( token.equalsIgnoreCase("BELOW_ALIGNMENT"))\r
465         {\r
466           setBelowAlignment(al, st);\r
467           continue;\r
468         }\r
469         else if( token.equalsIgnoreCase("ALIGNMENT"))\r
470         {\r
471           addAlignmentDetails(al, st);\r
472           continue;\r
473         }\r
474 \r
475         graphStyle = AlignmentAnnotation.getGraphValueFromString(token);\r
476         label = st.nextToken();\r
477 \r
478 \r
479         index = 0;\r
480         annotations = new Annotation[alWidth];\r
481         description = null;\r
482         float score = Float.NaN;\r
483 \r
484         if(st.hasMoreTokens())\r
485         {\r
486           line = st.nextToken();\r
487 \r
488           if (line.indexOf("|") ==-1)\r
489           {\r
490             description = line;\r
491             if (st.hasMoreTokens())\r
492               line = st.nextToken();\r
493           }\r
494 \r
495           if(st.hasMoreTokens())\r
496           {\r
497             //This must be the score\r
498             score = Float.valueOf(st.nextToken()).floatValue();\r
499           }\r
500 \r
501           st = new StringTokenizer(line, "|", true);\r
502 \r
503 \r
504           boolean emptyColumn = true;\r
505           boolean onlyOneElement = (st.countTokens()==1);\r
506 \r
507           while (st.hasMoreElements() && index < alWidth)\r
508           {\r
509             token = st.nextToken().trim();\r
510 \r
511             if(onlyOneElement)\r
512             {\r
513               try\r
514               {\r
515                 score = Float.valueOf(token).floatValue();\r
516                 break;\r
517               }\r
518               catch(NumberFormatException ex){}\r
519             }\r
520 \r
521             if (token.equals("|"))\r
522             {\r
523               if (emptyColumn)\r
524               {\r
525                 index++;\r
526               }\r
527 \r
528               emptyColumn = true;\r
529             }\r
530             else\r
531             {\r
532               annotations[index++] = parseAnnotation(token);\r
533               emptyColumn = false;\r
534             }\r
535           }\r
536 \r
537         }\r
538 \r
539         annotation = new AlignmentAnnotation(label,\r
540                                              description,\r
541                                              (index==0) ? null : annotations,\r
542                                              0,\r
543                                              0,\r
544                                              graphStyle);\r
545 \r
546         annotation.score = score;\r
547 \r
548         if (refSeq != null)\r
549         {\r
550           annotation.belowAlignment=false;\r
551           do {\r
552             // copy before we do any mapping business.\r
553             // TODO: verify that undo/redo with 1:many sequence associated annotations can be undone correctly\r
554             AlignmentAnnotation ann = new AlignmentAnnotation(annotation);\r
555             annotation.createSequenceMapping(refSeq, refSeqIndex, false);\r
556             annotation.adjustForAlignment();\r
557             refSeq.addAlignmentAnnotation(annotation);\r
558             al.addAnnotation(annotation);\r
559             al.setAnnotationIndex(annotation,\r
560                                 al.getAlignmentAnnotation().length - existingAnnotations -\r
561                                 1);\r
562             // and recover our virgin copy to use again if necessary.\r
563             annotation = ann;\r
564             \r
565           } while (refSeqId!=null && (refSeq=al.findName(refSeq, refSeqId, true))!=null);\r
566         } else {\r
567           al.addAnnotation(annotation);\r
568           al.setAnnotationIndex(annotation,\r
569                               al.getAlignmentAnnotation().length - existingAnnotations -\r
570                               1);\r
571         }\r
572       }\r
573 \r
574     }\r
575     catch (Exception ex)\r
576     {\r
577       ex.printStackTrace();\r
578       System.out.println("Problem reading annotation file: " + ex);\r
579       return false;\r
580     }\r
581     return true;\r
582   }\r
583 \r
584   Annotation parseAnnotation(String string)\r
585   {\r
586     String desc = null, displayChar = null;\r
587     char ss = ' '; // secondaryStructure\r
588     float value = 0;\r
589     boolean parsedValue = false;\r
590 \r
591     //find colour here\r
592     java.awt.Color colour = null;\r
593     int i=string.indexOf("[");\r
594     int j=string.indexOf("]");\r
595     if(i>-1 && j>-1)\r
596     {\r
597       UserColourScheme ucs = new UserColourScheme();\r
598 \r
599       colour = ucs.getColourFromString(string.substring(i+1,j));\r
600 \r
601       string = string.substring(0,i)+string.substring(j+1);\r
602     }\r
603 \r
604     StringTokenizer st = new StringTokenizer(string, ",");\r
605     String token;\r
606     while (st.hasMoreTokens())\r
607     {\r
608       token = st.nextToken().trim();\r
609       if (token.length() == 0)\r
610       {\r
611         continue;\r
612       }\r
613 \r
614       if (!parsedValue)\r
615       {\r
616         try\r
617         {\r
618           displayChar = token;\r
619           value = new Float(token).floatValue();\r
620           parsedValue = true;\r
621           continue;\r
622         }\r
623         catch (NumberFormatException ex)\r
624         {}\r
625       }\r
626 \r
627       if (token.equals("H") || token.equals("E"))\r
628       {\r
629         // Either this character represents a helix or sheet\r
630         // or an integer which can be displayed\r
631         ss = token.charAt(0);\r
632         if (displayChar.equals(token.substring(0, 1)))\r
633         {\r
634           displayChar = "";\r
635         }\r
636       }\r
637       else if (desc == null)\r
638       {\r
639         desc = token;\r
640       }\r
641 \r
642     }\r
643 \r
644     if (displayChar!=null\r
645         && displayChar.length() > 1\r
646         &&  desc!=null\r
647         && desc.length() == 1)\r
648     {\r
649       String tmp = displayChar;\r
650       displayChar = desc;\r
651       desc = tmp;\r
652     }\r
653     /*\r
654      * In principle, this code will ensure that the Annotation element generated is renderable by any of the applet or application rendering code\r
655      * but instead we check for null strings when the display character is rendered. \r
656     if (displayChar==null)\r
657     {\r
658       displayChar="";\r
659     }\r
660     */\r
661     Annotation anot = new Annotation(displayChar, desc, ss, value);\r
662 \r
663     anot.colour = colour;\r
664 \r
665     return anot;\r
666   }\r
667 \r
668   void colourAnnotations(AlignmentI al, String label, String colour)\r
669   {\r
670     UserColourScheme ucs = new UserColourScheme(colour);\r
671     Annotation[] annotations;\r
672     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
673     {\r
674       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(label))\r
675       {\r
676         annotations = al.getAlignmentAnnotation()[i].annotations;\r
677         for (int j = 0; j < annotations.length; j++)\r
678         {\r
679           if (annotations[j] != null)\r
680           {\r
681             annotations[j].colour = ucs.findColour('A');\r
682           }\r
683         }\r
684       }\r
685     }\r
686   }\r
687 \r
688   void combineAnnotations(AlignmentI al, StringTokenizer st)\r
689   {\r
690     int graphGroup = -1;\r
691     String group = st.nextToken();\r
692     //First make sure we are not overwriting the graphIndex\r
693     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
694     {\r
695       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
696       {\r
697         graphGroup = al.getAlignmentAnnotation()[i].graphGroup + 1;\r
698         al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
699         break;\r
700       }\r
701     }\r
702 \r
703     //Now update groups\r
704     while (st.hasMoreTokens())\r
705     {\r
706       group = st.nextToken();\r
707       for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
708       {\r
709         if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
710         {\r
711           al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
712           break;\r
713         }\r
714       }\r
715     }\r
716   }\r
717 \r
718   void addLine(AlignmentI al, StringTokenizer st)\r
719   {\r
720     String group = st.nextToken();\r
721     AlignmentAnnotation annotation = null;\r
722 \r
723     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
724     {\r
725       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
726       {\r
727         annotation = al.getAlignmentAnnotation()[i];\r
728         break;\r
729       }\r
730     }\r
731 \r
732     if (annotation == null)\r
733     {\r
734       return;\r
735     }\r
736     float value = new Float(st.nextToken()).floatValue();\r
737     String label = st.hasMoreTokens() ? st.nextToken() : null;\r
738     java.awt.Color colour = null;\r
739     if (st.hasMoreTokens())\r
740     {\r
741       UserColourScheme ucs = new UserColourScheme(st.nextToken());\r
742       colour = ucs.findColour('A');\r
743     }\r
744 \r
745     annotation.setThreshold(new GraphLine(value, label, colour));\r
746   }\r
747 \r
748   void addGroup(AlignmentI al, StringTokenizer st)\r
749   {\r
750     SequenceGroup sg = new SequenceGroup();\r
751     sg.setName(st.nextToken());\r
752     sg.setStartRes(Integer.parseInt(st.nextToken()) - 1);\r
753     sg.setEndRes(Integer.parseInt(st.nextToken()) - 1);\r
754 \r
755     String index = st.nextToken();\r
756     if (index.equals("-1"))\r
757     {\r
758       while (st.hasMoreElements())\r
759       {\r
760         sg.addSequence(al.findName(st.nextToken()), false);\r
761       }\r
762     }\r
763     else\r
764     {\r
765       StringTokenizer st2 = new StringTokenizer(index, ",");\r
766 \r
767       while (st2.hasMoreTokens())\r
768       {\r
769         String tmp = st2.nextToken();\r
770         if (tmp.equals("*"))\r
771         {\r
772           for (int i = 0; i < al.getHeight(); i++)\r
773           {\r
774             sg.addSequence(al.getSequenceAt(i), false);\r
775           }\r
776         }\r
777         else if (tmp.indexOf("-") >= 0)\r
778         {\r
779           StringTokenizer st3 = new StringTokenizer(tmp, "-");\r
780 \r
781           int start = (Integer.parseInt(st3.nextToken()));\r
782           int end = (Integer.parseInt(st3.nextToken()));\r
783 \r
784           if (end > start)\r
785           {\r
786             for (int i = start; i <= end; i++)\r
787             {\r
788               sg.addSequence(al.getSequenceAt(i - 1), false);\r
789             }\r
790           }\r
791         }\r
792         else\r
793         {\r
794           sg.addSequence(al.getSequenceAt(Integer.parseInt(tmp) - 1), false);\r
795         }\r
796       }\r
797     }\r
798 \r
799 \r
800 \r
801     if (refSeq != null)\r
802     {\r
803       sg.setStartRes(refSeq.findIndex(sg.getStartRes() + 1) - 1);\r
804       sg.setEndRes(refSeq.findIndex(sg.getEndRes() + 1) - 1);\r
805     }\r
806 \r
807     if (sg.getSize() > 0)\r
808     {\r
809       al.addGroup(sg);\r
810     }\r
811   }\r
812 \r
813   void addProperties(AlignmentI al, StringTokenizer st)\r
814   {\r
815 \r
816     //So far we have only added groups to the annotationHash,\r
817     //the idea is in the future properties can be added to\r
818     //alignments, other annotations etc\r
819     if (al.getGroups() == null)\r
820     {\r
821       return;\r
822     }\r
823     SequenceGroup sg = null;\r
824 \r
825     String name = st.nextToken();\r
826 \r
827     Vector groups = al.getGroups();\r
828     for (int i = 0; i < groups.size(); i++)\r
829     {\r
830       sg = (SequenceGroup) groups.elementAt(i);\r
831       if (sg.getName().equals(name))\r
832       {\r
833         break;\r
834       }\r
835       else\r
836       {\r
837         sg = null;\r
838       }\r
839     }\r
840 \r
841     if (sg != null)\r
842     {\r
843       String keyValue, key, value;\r
844       ColourSchemeI def = sg.cs;\r
845       sg.cs = null;\r
846       while (st.hasMoreTokens())\r
847       {\r
848         keyValue = st.nextToken();\r
849         key = keyValue.substring(0, keyValue.indexOf("="));\r
850         value = keyValue.substring(keyValue.indexOf("=") + 1);\r
851 \r
852         if (key.equalsIgnoreCase("description"))\r
853         {\r
854           sg.setDescription(value);\r
855         }\r
856         else if (key.equalsIgnoreCase("colour"))\r
857         {\r
858           sg.cs = ColourSchemeProperty.getColour(al, value);\r
859         }\r
860         else if (key.equalsIgnoreCase("pidThreshold"))\r
861         {\r
862           sg.cs.setThreshold(Integer.parseInt(value), true);\r
863 \r
864         }\r
865         else if (key.equalsIgnoreCase("consThreshold"))\r
866         {\r
867           sg.cs.setConservationInc(Integer.parseInt(value));\r
868           Conservation c = new Conservation("Group",\r
869                                             ResidueProperties.propHash, 3,\r
870                                             sg.getSequences(null),\r
871                                             sg.getStartRes(),\r
872                                             sg.getEndRes() + 1);\r
873 \r
874           c.calculate();\r
875           c.verdict(false, 25);\r
876 \r
877           sg.cs.setConservation(c);\r
878 \r
879         }\r
880         else if (key.equalsIgnoreCase("outlineColour"))\r
881         {\r
882           sg.setOutlineColour(new UserColourScheme(value).findColour('A'));\r
883         }\r
884         else if (key.equalsIgnoreCase("displayBoxes"))\r
885         {\r
886           sg.setDisplayBoxes(Boolean.valueOf(value).booleanValue());\r
887         }\r
888         else if (key.equalsIgnoreCase("displayText"))\r
889         {\r
890           sg.setDisplayText(Boolean.valueOf(value).booleanValue());\r
891         }\r
892         else if (key.equalsIgnoreCase("colourText"))\r
893         {\r
894           sg.setColourText(Boolean.valueOf(value).booleanValue());\r
895         }\r
896         else if (key.equalsIgnoreCase("textCol1"))\r
897         {\r
898           sg.textColour = new UserColourScheme(value).findColour('A');\r
899         }\r
900         else if (key.equalsIgnoreCase("textCol2"))\r
901         {\r
902           sg.textColour2 = new UserColourScheme(value).findColour('A');\r
903         }\r
904         else if (key.equalsIgnoreCase("textColThreshold"))\r
905         {\r
906           sg.thresholdTextColour = Integer.parseInt(value);\r
907         }\r
908         else if (key.equalsIgnoreCase("idColour"))\r
909         {\r
910           // consider warning if colour doesn't resolve to a real colour\r
911           sg.setIdColour((def = new UserColourScheme(value)).findColour('A'));\r
912         }\r
913         sg.recalcConservation();\r
914       }\r
915       if (sg.cs==null)\r
916       {\r
917         sg.cs = def;\r
918       }\r
919     }\r
920   }\r
921 \r
922   void setBelowAlignment(AlignmentI al, StringTokenizer st)\r
923   {\r
924     String token;\r
925     AlignmentAnnotation aa;\r
926     while(st.hasMoreTokens())\r
927     {\r
928       token = st.nextToken();\r
929       for(int i=0; i<al.getAlignmentAnnotation().length; i++)\r
930       {\r
931         aa = al.getAlignmentAnnotation()[i];\r
932         if(aa.sequenceRef==refSeq && aa.label.equals(token))\r
933         {\r
934           aa.belowAlignment = true;\r
935         }\r
936       }\r
937     }\r
938   }\r
939 \r
940   void addAlignmentDetails(AlignmentI al, StringTokenizer st)\r
941   {\r
942     String keyValue, key, value;\r
943     while (st.hasMoreTokens())\r
944     {\r
945       keyValue = st.nextToken();\r
946       key = keyValue.substring(0, keyValue.indexOf("="));\r
947       value = keyValue.substring(keyValue.indexOf("=") + 1);\r
948       al.setProperty(key,value);\r
949     }\r
950   }\r
951 \r
952   /**\r
953    * Write annotations as a CSV file of the form 'label, value, value, ...' for each row.\r
954    * @param annotations\r
955    * @return CSV file as a string.\r
956    */\r
957   public String printCSVAnnotations(AlignmentAnnotation[] annotations)\r
958   {\r
959     StringBuffer sp = new StringBuffer();\r
960     for (int i=0; i<annotations.length; i++)\r
961     {\r
962       String atos = annotations[i].toString();\r
963       int p = 0;\r
964       do {\r
965         int cp = atos.indexOf("\n", p);\r
966         sp.append(annotations[i].label);\r
967         sp.append(",");\r
968         if (cp>p)\r
969         {\r
970           sp.append(atos.substring(p, cp+1));\r
971         } else {\r
972           sp.append(atos.substring(p));\r
973           sp.append("\n");\r
974         }\r
975         p = cp+1;\r
976       } while (p>0);\r
977     }\r
978     return sp.toString();\r
979   }\r
980 }\r