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