apply gpl development license
[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           colourAnnotations(al, st.nextToken(), st.nextToken());\r
443           continue;\r
444         }\r
445 \r
446         else if (token.equalsIgnoreCase("COMBINE"))\r
447         {\r
448           combineAnnotations(al, st);\r
449           continue;\r
450         }\r
451 \r
452         else if (token.equalsIgnoreCase("GRAPHLINE"))\r
453         {\r
454           addLine(al, st);\r
455           continue;\r
456         }\r
457 \r
458         else if (token.equalsIgnoreCase("SEQUENCE_REF"))\r
459         {\r
460           if (st.hasMoreTokens())\r
461           {\r
462             refSeq = al.findName(refSeqId = st.nextToken());\r
463             if (refSeq == null)\r
464             {\r
465               refSeqId = null;\r
466             }\r
467             try\r
468             {\r
469               refSeqIndex = Integer.parseInt(st.nextToken());\r
470               if (refSeqIndex < 1)\r
471               {\r
472                 refSeqIndex = 1;\r
473                 System.out\r
474                         .println("WARNING: SEQUENCE_REF index must be > 0 in AnnotationFile");\r
475               }\r
476             } catch (Exception ex)\r
477             {\r
478               refSeqIndex = 1;\r
479             }\r
480           }\r
481           else\r
482           {\r
483             refSeq = null;\r
484             refSeqId = null;\r
485           }\r
486           continue;\r
487         }\r
488 \r
489         else if (token.equalsIgnoreCase("SEQUENCE_GROUP"))\r
490         {\r
491           addGroup(al, st);\r
492           continue;\r
493         }\r
494 \r
495         else if (token.equalsIgnoreCase("PROPERTIES"))\r
496         {\r
497           addProperties(al, st);\r
498           continue;\r
499         }\r
500 \r
501         else if (token.equalsIgnoreCase("BELOW_ALIGNMENT"))\r
502         {\r
503           setBelowAlignment(al, st);\r
504           continue;\r
505         }\r
506         else if (token.equalsIgnoreCase("ALIGNMENT"))\r
507         {\r
508           addAlignmentDetails(al, st);\r
509           continue;\r
510         }\r
511 \r
512         graphStyle = AlignmentAnnotation.getGraphValueFromString(token);\r
513         label = st.nextToken();\r
514 \r
515         index = 0;\r
516         annotations = new Annotation[alWidth];\r
517         description = null;\r
518         float score = Float.NaN;\r
519 \r
520         if (st.hasMoreTokens())\r
521         {\r
522           line = st.nextToken();\r
523 \r
524           if (line.indexOf("|") == -1)\r
525           {\r
526             description = line;\r
527             if (st.hasMoreTokens())\r
528               line = st.nextToken();\r
529           }\r
530 \r
531           if (st.hasMoreTokens())\r
532           {\r
533             // This must be the score\r
534             score = Float.valueOf(st.nextToken()).floatValue();\r
535           }\r
536 \r
537           st = new StringTokenizer(line, "|", true);\r
538 \r
539           boolean emptyColumn = true;\r
540           boolean onlyOneElement = (st.countTokens() == 1);\r
541 \r
542           while (st.hasMoreElements() && index < alWidth)\r
543           {\r
544             token = st.nextToken().trim();\r
545 \r
546             if (onlyOneElement)\r
547             {\r
548               try\r
549               {\r
550                 score = Float.valueOf(token).floatValue();\r
551                 break;\r
552               } catch (NumberFormatException ex)\r
553               {\r
554               }\r
555             }\r
556 \r
557             if (token.equals("|"))\r
558             {\r
559               if (emptyColumn)\r
560               {\r
561                 index++;\r
562               }\r
563 \r
564               emptyColumn = true;\r
565             }\r
566             else\r
567             {\r
568               annotations[index++] = parseAnnotation(token);\r
569               emptyColumn = false;\r
570             }\r
571           }\r
572 \r
573         }\r
574 \r
575         annotation = new AlignmentAnnotation(label, description,\r
576                 (index == 0) ? null : annotations, 0, 0, graphStyle);\r
577 \r
578         annotation.score = score;\r
579 \r
580         if (refSeq != null)\r
581         {\r
582           annotation.belowAlignment = false;\r
583           // make a copy of refSeq so we can find other matches in the alignment\r
584           SequenceI referedSeq = refSeq;\r
585           do\r
586           {\r
587             // copy before we do any mapping business.\r
588             // TODO: verify that undo/redo with 1:many sequence associated\r
589             // annotations can be undone correctly\r
590             AlignmentAnnotation ann = new AlignmentAnnotation(annotation);\r
591             annotation.createSequenceMapping(referedSeq, refSeqIndex, false);\r
592             annotation.adjustForAlignment();\r
593             referedSeq.addAlignmentAnnotation(annotation);\r
594             al.addAnnotation(annotation);\r
595             al.setAnnotationIndex(annotation,\r
596                     al.getAlignmentAnnotation().length\r
597                             - existingAnnotations - 1);\r
598             // and recover our virgin copy to use again if necessary.\r
599             annotation = ann;\r
600 \r
601           } while (refSeqId != null\r
602                   && (referedSeq = al.findName(referedSeq, refSeqId, true)) != null);\r
603         }\r
604         else\r
605         {\r
606           al.addAnnotation(annotation);\r
607           al.setAnnotationIndex(annotation,\r
608                   al.getAlignmentAnnotation().length - existingAnnotations\r
609                           - 1);\r
610         }\r
611       }\r
612 \r
613     } catch (Exception ex)\r
614     {\r
615       ex.printStackTrace();\r
616       System.out.println("Problem reading annotation file: " + ex);\r
617       return false;\r
618     }\r
619     return true;\r
620   }\r
621 \r
622   Annotation parseAnnotation(String string)\r
623   {\r
624     String desc = null, displayChar = null;\r
625     char ss = ' '; // secondaryStructure\r
626     float value = 0;\r
627     boolean parsedValue = false;\r
628 \r
629     // find colour here\r
630     java.awt.Color colour = null;\r
631     int i = string.indexOf("[");\r
632     int j = string.indexOf("]");\r
633     if (i > -1 && j > -1)\r
634     {\r
635       UserColourScheme ucs = new UserColourScheme();\r
636 \r
637       colour = ucs.getColourFromString(string.substring(i + 1, j));\r
638 \r
639       string = string.substring(0, i) + string.substring(j + 1);\r
640     }\r
641 \r
642     StringTokenizer st = new StringTokenizer(string, ",");\r
643     String token;\r
644     while (st.hasMoreTokens())\r
645     {\r
646       token = st.nextToken().trim();\r
647       if (token.length() == 0)\r
648       {\r
649         continue;\r
650       }\r
651 \r
652       if (!parsedValue)\r
653       {\r
654         try\r
655         {\r
656           displayChar = token;\r
657           value = new Float(token).floatValue();\r
658           parsedValue = true;\r
659           continue;\r
660         } catch (NumberFormatException ex)\r
661         {\r
662         }\r
663       }\r
664 \r
665       if (token.equals("H") || token.equals("E"))\r
666       {\r
667         // Either this character represents a helix or sheet\r
668         // or an integer which can be displayed\r
669         ss = token.charAt(0);\r
670         if (displayChar.equals(token.substring(0, 1)))\r
671         {\r
672           displayChar = "";\r
673         }\r
674       }\r
675       else if (desc == null)\r
676       {\r
677         desc = token;\r
678       }\r
679 \r
680     }\r
681 \r
682     if (displayChar != null && displayChar.length() > 1 && desc != null\r
683             && desc.length() == 1)\r
684     {\r
685       String tmp = displayChar;\r
686       displayChar = desc;\r
687       desc = tmp;\r
688     }\r
689     /*\r
690      * In principle, this code will ensure that the Annotation element generated\r
691      * is renderable by any of the applet or application rendering code but\r
692      * instead we check for null strings when the display character is rendered.\r
693      * if (displayChar==null) { displayChar=""; }\r
694      */\r
695     Annotation anot = new Annotation(displayChar, desc, ss, value);\r
696 \r
697     anot.colour = colour;\r
698 \r
699     return anot;\r
700   }\r
701 \r
702   void colourAnnotations(AlignmentI al, String label, String colour)\r
703   {\r
704     UserColourScheme ucs = new UserColourScheme(colour);\r
705     Annotation[] annotations;\r
706     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
707     {\r
708       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(label))\r
709       {\r
710         annotations = al.getAlignmentAnnotation()[i].annotations;\r
711         for (int j = 0; j < annotations.length; j++)\r
712         {\r
713           if (annotations[j] != null)\r
714           {\r
715             annotations[j].colour = ucs.findColour('A');\r
716           }\r
717         }\r
718       }\r
719     }\r
720   }\r
721 \r
722   void combineAnnotations(AlignmentI al, StringTokenizer st)\r
723   {\r
724     int graphGroup = -1;\r
725     String group = st.nextToken();\r
726     // First make sure we are not overwriting the graphIndex\r
727     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
728     {\r
729       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
730       {\r
731         graphGroup = al.getAlignmentAnnotation()[i].graphGroup + 1;\r
732         al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
733         break;\r
734       }\r
735     }\r
736 \r
737     // Now update groups\r
738     while (st.hasMoreTokens())\r
739     {\r
740       group = st.nextToken();\r
741       for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
742       {\r
743         if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
744         {\r
745           al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
746           break;\r
747         }\r
748       }\r
749     }\r
750   }\r
751 \r
752   void addLine(AlignmentI al, StringTokenizer st)\r
753   {\r
754     String group = st.nextToken();\r
755     AlignmentAnnotation annotation = null;\r
756 \r
757     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
758     {\r
759       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
760       {\r
761         annotation = al.getAlignmentAnnotation()[i];\r
762         break;\r
763       }\r
764     }\r
765 \r
766     if (annotation == null)\r
767     {\r
768       return;\r
769     }\r
770     float value = new Float(st.nextToken()).floatValue();\r
771     String label = st.hasMoreTokens() ? st.nextToken() : null;\r
772     java.awt.Color colour = null;\r
773     if (st.hasMoreTokens())\r
774     {\r
775       UserColourScheme ucs = new UserColourScheme(st.nextToken());\r
776       colour = ucs.findColour('A');\r
777     }\r
778 \r
779     annotation.setThreshold(new GraphLine(value, label, colour));\r
780   }\r
781   void addGroup(AlignmentI al, StringTokenizer st)\r
782   {\r
783     SequenceGroup sg = new SequenceGroup();\r
784     sg.setName(st.nextToken());\r
785     String rng ="";\r
786     try {\r
787       rng = st.nextToken();\r
788       if (rng.length()>0 && !rng.startsWith("*"))\r
789       {\r
790         sg.setStartRes(Integer.parseInt(rng) - 1);\r
791       } else {\r
792         sg.setStartRes(0);\r
793       }\r
794       rng = st.nextToken();\r
795       if (rng.length()>0 && !rng.startsWith("*"))\r
796       {\r
797         sg.setEndRes(Integer.parseInt(rng) - 1);\r
798       } else {\r
799         sg.setEndRes(al.getWidth()-1);\r
800       }\r
801     } catch (Exception e)\r
802     {\r
803       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
804       // assume group is full width\r
805       sg.setStartRes(0);\r
806       sg.setEndRes(al.getWidth()-1);\r
807     }\r
808 \r
809     String index = st.nextToken();\r
810     if (index.equals("-1"))\r
811     {\r
812       while (st.hasMoreElements())\r
813       {\r
814         sg.addSequence(al.findName(st.nextToken()), false);\r
815       }\r
816     }\r
817     else\r
818     {\r
819       StringTokenizer st2 = new StringTokenizer(index, ",");\r
820 \r
821       while (st2.hasMoreTokens())\r
822       {\r
823         String tmp = st2.nextToken();\r
824         if (tmp.equals("*"))\r
825         {\r
826           for (int i = 0; i < al.getHeight(); i++)\r
827           {\r
828             sg.addSequence(al.getSequenceAt(i), false);\r
829           }\r
830         }\r
831         else if (tmp.indexOf("-") >= 0)\r
832         {\r
833           StringTokenizer st3 = new StringTokenizer(tmp, "-");\r
834 \r
835           int start = (Integer.parseInt(st3.nextToken()));\r
836           int end = (Integer.parseInt(st3.nextToken()));\r
837 \r
838           if (end > start)\r
839           {\r
840             for (int i = start; i <= end; i++)\r
841             {\r
842               sg.addSequence(al.getSequenceAt(i - 1), false);\r
843             }\r
844           }\r
845         }\r
846         else\r
847         {\r
848           sg\r
849                   .addSequence(al.getSequenceAt(Integer.parseInt(tmp) - 1),\r
850                           false);\r
851         }\r
852       }\r
853     }\r
854 \r
855     if (refSeq != null)\r
856     {\r
857       sg.setStartRes(refSeq.findIndex(sg.getStartRes() + 1) - 1);\r
858       sg.setEndRes(refSeq.findIndex(sg.getEndRes() + 1) - 1);\r
859       sg.setSeqrep(refSeq);\r
860     }\r
861 \r
862     if (sg.getSize() > 0)\r
863     {\r
864       al.addGroup(sg);\r
865     }\r
866   }\r
867 \r
868   void addProperties(AlignmentI al, StringTokenizer st)\r
869   {\r
870 \r
871     // So far we have only added groups to the annotationHash,\r
872     // the idea is in the future properties can be added to\r
873     // alignments, other annotations etc\r
874     if (al.getGroups() == null)\r
875     {\r
876       return;\r
877     }\r
878     SequenceGroup sg = null;\r
879 \r
880     String name = st.nextToken();\r
881 \r
882     Vector groups = al.getGroups();\r
883     for (int i = 0; i < groups.size(); i++)\r
884     {\r
885       sg = (SequenceGroup) groups.elementAt(i);\r
886       if (sg.getName().equals(name))\r
887       {\r
888         break;\r
889       }\r
890       else\r
891       {\r
892         sg = null;\r
893       }\r
894     }\r
895 \r
896     if (sg != null)\r
897     {\r
898       String keyValue, key, value;\r
899       ColourSchemeI def = sg.cs;\r
900       sg.cs = null;\r
901       while (st.hasMoreTokens())\r
902       {\r
903         keyValue = st.nextToken();\r
904         key = keyValue.substring(0, keyValue.indexOf("="));\r
905         value = keyValue.substring(keyValue.indexOf("=") + 1);\r
906 \r
907         if (key.equalsIgnoreCase("description"))\r
908         {\r
909           sg.setDescription(value);\r
910         }\r
911         else if (key.equalsIgnoreCase("colour"))\r
912         {\r
913           sg.cs = ColourSchemeProperty.getColour(al, value);\r
914         }\r
915         else if (key.equalsIgnoreCase("pidThreshold"))\r
916         {\r
917           sg.cs.setThreshold(Integer.parseInt(value), true);\r
918 \r
919         }\r
920         else if (key.equalsIgnoreCase("consThreshold"))\r
921         {\r
922           sg.cs.setConservationInc(Integer.parseInt(value));\r
923           Conservation c = new Conservation("Group",\r
924                   ResidueProperties.propHash, 3, sg.getSequences(null), sg\r
925                           .getStartRes(), sg.getEndRes() + 1);\r
926 \r
927           c.calculate();\r
928           c.verdict(false, 25);\r
929 \r
930           sg.cs.setConservation(c);\r
931 \r
932         }\r
933         else if (key.equalsIgnoreCase("outlineColour"))\r
934         {\r
935           sg.setOutlineColour(new UserColourScheme(value).findColour('A'));\r
936         }\r
937         else if (key.equalsIgnoreCase("displayBoxes"))\r
938         {\r
939           sg.setDisplayBoxes(Boolean.valueOf(value).booleanValue());\r
940         }\r
941         else if (key.equalsIgnoreCase("showUnconserved"))\r
942         {\r
943           sg.setShowunconserved(Boolean.valueOf(value).booleanValue());\r
944         }\r
945         else if (key.equalsIgnoreCase("displayText"))\r
946         {\r
947           sg.setDisplayText(Boolean.valueOf(value).booleanValue());\r
948         }\r
949         else if (key.equalsIgnoreCase("colourText"))\r
950         {\r
951           sg.setColourText(Boolean.valueOf(value).booleanValue());\r
952         }\r
953         else if (key.equalsIgnoreCase("textCol1"))\r
954         {\r
955           sg.textColour = new UserColourScheme(value).findColour('A');\r
956         }\r
957         else if (key.equalsIgnoreCase("textCol2"))\r
958         {\r
959           sg.textColour2 = new UserColourScheme(value).findColour('A');\r
960         }\r
961         else if (key.equalsIgnoreCase("textColThreshold"))\r
962         {\r
963           sg.thresholdTextColour = Integer.parseInt(value);\r
964         }\r
965         else if (key.equalsIgnoreCase("idColour"))\r
966         {\r
967           // consider warning if colour doesn't resolve to a real colour\r
968           sg.setIdColour((def = new UserColourScheme(value))\r
969                   .findColour('A'));\r
970         }\r
971         else if (key.equalsIgnoreCase("hide"))\r
972         {\r
973           // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847\r
974           sg.setHidereps(true);\r
975         }\r
976         else if (key.equalsIgnoreCase("hidecols"))\r
977         {\r
978           // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847\r
979           sg.setHideCols(true);\r
980         }\r
981         sg.recalcConservation();\r
982       }\r
983       if (sg.cs == null)\r
984       {\r
985         sg.cs = def;\r
986       }\r
987     }\r
988   }\r
989 \r
990   void setBelowAlignment(AlignmentI al, StringTokenizer st)\r
991   {\r
992     String token;\r
993     AlignmentAnnotation aa;\r
994     while (st.hasMoreTokens())\r
995     {\r
996       token = st.nextToken();\r
997       for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
998       {\r
999         aa = al.getAlignmentAnnotation()[i];\r
1000         if (aa.sequenceRef == refSeq && aa.label.equals(token))\r
1001         {\r
1002           aa.belowAlignment = true;\r
1003         }\r
1004       }\r
1005     }\r
1006   }\r
1007 \r
1008   void addAlignmentDetails(AlignmentI al, StringTokenizer st)\r
1009   {\r
1010     String keyValue, key, value;\r
1011     while (st.hasMoreTokens())\r
1012     {\r
1013       keyValue = st.nextToken();\r
1014       key = keyValue.substring(0, keyValue.indexOf("="));\r
1015       value = keyValue.substring(keyValue.indexOf("=") + 1);\r
1016       al.setProperty(key, value);\r
1017     }\r
1018   }\r
1019 \r
1020   /**\r
1021    * Write annotations as a CSV file of the form 'label, value, value, ...' for\r
1022    * each row.\r
1023    * \r
1024    * @param annotations\r
1025    * @return CSV file as a string.\r
1026    */\r
1027   public String printCSVAnnotations(AlignmentAnnotation[] annotations)\r
1028   {\r
1029     StringBuffer sp = new StringBuffer();\r
1030     for (int i = 0; i < annotations.length; i++)\r
1031     {\r
1032       String atos = annotations[i].toString();\r
1033       int p = 0;\r
1034       do\r
1035       {\r
1036         int cp = atos.indexOf("\n", p);\r
1037         sp.append(annotations[i].label);\r
1038         sp.append(",");\r
1039         if (cp > p)\r
1040         {\r
1041           sp.append(atos.substring(p, cp + 1));\r
1042         }\r
1043         else\r
1044         {\r
1045           sp.append(atos.substring(p));\r
1046           sp.append("\n");\r
1047         }\r
1048         p = cp + 1;\r
1049       } while (p > 0);\r
1050     }\r
1051     return sp.toString();\r
1052   }\r
1053 }\r