1872f60a46ceb2cbc2ca53d642345e5aa54ef8b2
[jalview.git] / src / jalview / io / AnnotationFile.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)\r
3  * Copyright (C) 2008 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 \r
265     }\r
266 \r
267     return text.toString();\r
268   }\r
269 \r
270   public void printGroups(Vector sequenceGroups)\r
271   {\r
272     SequenceGroup sg;\r
273     SequenceI seqrep=null;\r
274     for (int i = 0; i < sequenceGroups.size(); i++)\r
275     {\r
276       sg = (SequenceGroup) sequenceGroups.elementAt(i);\r
277       if (!sg.hasSeqrep())\r
278       {\r
279         text.append("SEQUENCE_GROUP\t" + sg.getName() + "\t"\r
280                 + (sg.getStartRes() + 1) + "\t" + (sg.getEndRes() + 1) + "\t"\r
281                 + "-1\t");\r
282         seqrep = null;\r
283       } else {\r
284         seqrep = sg.getSeqrep();\r
285         text.append("SEQUENCE_REF\t"+seqrep.getName()+"\n");\r
286         text.append("SEQUENCE_GROUP\t" + sg.getName() + "\t"\r
287                 + (seqrep.findPosition(sg.getStartRes())) + "\t" + (seqrep.findPosition(sg.getEndRes())) + "\t"\r
288                 + "-1\t");\r
289       }\r
290       for (int s = 0; s < sg.getSize(); s++)\r
291       {\r
292         text.append(sg.getSequenceAt(s).getName() + "\t");\r
293       }\r
294 \r
295       text.append("\nPROPERTIES\t" + sg.getName() + "\t");\r
296 \r
297       if (sg.getDescription() != null)\r
298       {\r
299         text.append("description=" + sg.getDescription() + "\t");\r
300       }\r
301       if (sg.cs != null)\r
302       {\r
303         text.append("colour=" + ColourSchemeProperty.getColourName(sg.cs)\r
304                 + "\t");\r
305         if (sg.cs.getThreshold() != 0)\r
306         {\r
307           text.append("pidThreshold=" + sg.cs.getThreshold());\r
308         }\r
309         if (sg.cs.conservationApplied())\r
310         {\r
311           text.append("consThreshold=" + sg.cs.getConservationInc() + "\t");\r
312         }\r
313       }\r
314       text.append("outlineColour="\r
315               + jalview.util.Format.getHexString(sg.getOutlineColour())\r
316               + "\t");\r
317 \r
318       text.append("displayBoxes=" + sg.getDisplayBoxes() + "\t");\r
319       text.append("displayText=" + sg.getDisplayText() + "\t");\r
320       text.append("colourText=" + sg.getColourText() + "\t");\r
321 \r
322       if (sg.textColour != java.awt.Color.black)\r
323       {\r
324         text.append("textCol1="\r
325                 + jalview.util.Format.getHexString(sg.textColour) + "\t");\r
326       }\r
327       if (sg.textColour2 != java.awt.Color.white)\r
328       {\r
329         text.append("textCol2="\r
330                 + jalview.util.Format.getHexString(sg.textColour2) + "\t");\r
331       }\r
332       if (sg.thresholdTextColour != 0)\r
333       {\r
334         text.append("textColThreshold=" + sg.thresholdTextColour+"\t");\r
335       }\r
336       if (sg.idColour != null)\r
337       {\r
338         text.append("idColour="\r
339                 + jalview.util.Format.getHexString(sg.idColour) + "\t");\r
340       }\r
341       if (sg.isHidereps())\r
342       {\r
343         text.append("hide=true\t");\r
344       }\r
345       if (sg.isHideCols())\r
346       {\r
347         text.append("hidecols=true\t");\r
348       }\r
349       if (seqrep!=null)\r
350       {\r
351         // terminate the last line and clear the sequence ref for the group\r
352         text.append("\nSEQUENCE_REF");\r
353       }\r
354       text.append("\n\n");\r
355 \r
356     }\r
357   }\r
358 \r
359   SequenceI refSeq = null;\r
360 \r
361   String refSeqId = null;\r
362 \r
363   public boolean readAnnotationFile(AlignmentI al, String file,\r
364           String protocol)\r
365   {\r
366     try\r
367     {\r
368       BufferedReader in = null;\r
369       if (protocol.equals(AppletFormatAdapter.FILE))\r
370       {\r
371         in = new BufferedReader(new FileReader(file));\r
372       }\r
373       else if (protocol.equals(AppletFormatAdapter.URL))\r
374       {\r
375         URL url = new URL(file);\r
376         in = new BufferedReader(new InputStreamReader(url.openStream()));\r
377       }\r
378       else if (protocol.equals(AppletFormatAdapter.PASTE))\r
379       {\r
380         in = new BufferedReader(new StringReader(file));\r
381       }\r
382       else if (protocol.equals(AppletFormatAdapter.CLASSLOADER))\r
383       {\r
384         java.io.InputStream is = getClass().getResourceAsStream("/" + file);\r
385         if (is != null)\r
386         {\r
387           in = new BufferedReader(new java.io.InputStreamReader(is));\r
388         }\r
389       }\r
390 \r
391       String line, label, description, token;\r
392       int graphStyle, index;\r
393       int refSeqIndex = 1;\r
394       int existingAnnotations = 0;\r
395       if (al.getAlignmentAnnotation() != null)\r
396       {\r
397         existingAnnotations = al.getAlignmentAnnotation().length;\r
398       }\r
399 \r
400       int alWidth = al.getWidth();\r
401 \r
402       StringTokenizer st;\r
403       Annotation[] annotations;\r
404       AlignmentAnnotation annotation = null;\r
405 \r
406       // First confirm this is an Annotation file\r
407       boolean jvAnnotationFile = false;\r
408       while ((line = in.readLine()) != null)\r
409       {\r
410         if (line.indexOf("#") == 0)\r
411         {\r
412           continue;\r
413         }\r
414 \r
415         if (line.indexOf("JALVIEW_ANNOTATION") > -1)\r
416         {\r
417           jvAnnotationFile = true;\r
418           break;\r
419         }\r
420       }\r
421 \r
422       if (!jvAnnotationFile)\r
423       {\r
424         in.close();\r
425         return false;\r
426       }\r
427 \r
428       while ((line = in.readLine()) != null)\r
429       {\r
430         if (line.indexOf("#") == 0\r
431                 || line.indexOf("JALVIEW_ANNOTATION") > -1\r
432                 || line.length() == 0)\r
433         {\r
434           continue;\r
435         }\r
436 \r
437         st = new StringTokenizer(line, "\t");\r
438         token = st.nextToken();\r
439         if (token.equalsIgnoreCase("COLOUR"))\r
440         {\r
441           colourAnnotations(al, st.nextToken(), st.nextToken());\r
442           continue;\r
443         }\r
444 \r
445         else if (token.equalsIgnoreCase("COMBINE"))\r
446         {\r
447           combineAnnotations(al, st);\r
448           continue;\r
449         }\r
450 \r
451         else if (token.equalsIgnoreCase("GRAPHLINE"))\r
452         {\r
453           addLine(al, st);\r
454           continue;\r
455         }\r
456 \r
457         else if (token.equalsIgnoreCase("SEQUENCE_REF"))\r
458         {\r
459           if (st.hasMoreTokens())\r
460           {\r
461             refSeq = al.findName(refSeqId = st.nextToken());\r
462             if (refSeq == null)\r
463             {\r
464               refSeqId = null;\r
465             }\r
466             try\r
467             {\r
468               refSeqIndex = Integer.parseInt(st.nextToken());\r
469               if (refSeqIndex < 1)\r
470               {\r
471                 refSeqIndex = 1;\r
472                 System.out\r
473                         .println("WARNING: SEQUENCE_REF index must be > 0 in AnnotationFile");\r
474               }\r
475             } catch (Exception ex)\r
476             {\r
477               refSeqIndex = 1;\r
478             }\r
479           }\r
480           else\r
481           {\r
482             refSeq = null;\r
483             refSeqId = null;\r
484           }\r
485           continue;\r
486         }\r
487 \r
488         else if (token.equalsIgnoreCase("SEQUENCE_GROUP"))\r
489         {\r
490           addGroup(al, st);\r
491           continue;\r
492         }\r
493 \r
494         else if (token.equalsIgnoreCase("PROPERTIES"))\r
495         {\r
496           addProperties(al, st);\r
497           continue;\r
498         }\r
499 \r
500         else if (token.equalsIgnoreCase("BELOW_ALIGNMENT"))\r
501         {\r
502           setBelowAlignment(al, st);\r
503           continue;\r
504         }\r
505         else if (token.equalsIgnoreCase("ALIGNMENT"))\r
506         {\r
507           addAlignmentDetails(al, st);\r
508           continue;\r
509         }\r
510 \r
511         graphStyle = AlignmentAnnotation.getGraphValueFromString(token);\r
512         label = st.nextToken();\r
513 \r
514         index = 0;\r
515         annotations = new Annotation[alWidth];\r
516         description = null;\r
517         float score = Float.NaN;\r
518 \r
519         if (st.hasMoreTokens())\r
520         {\r
521           line = st.nextToken();\r
522 \r
523           if (line.indexOf("|") == -1)\r
524           {\r
525             description = line;\r
526             if (st.hasMoreTokens())\r
527               line = st.nextToken();\r
528           }\r
529 \r
530           if (st.hasMoreTokens())\r
531           {\r
532             // This must be the score\r
533             score = Float.valueOf(st.nextToken()).floatValue();\r
534           }\r
535 \r
536           st = new StringTokenizer(line, "|", true);\r
537 \r
538           boolean emptyColumn = true;\r
539           boolean onlyOneElement = (st.countTokens() == 1);\r
540 \r
541           while (st.hasMoreElements() && index < alWidth)\r
542           {\r
543             token = st.nextToken().trim();\r
544 \r
545             if (onlyOneElement)\r
546             {\r
547               try\r
548               {\r
549                 score = Float.valueOf(token).floatValue();\r
550                 break;\r
551               } catch (NumberFormatException ex)\r
552               {\r
553               }\r
554             }\r
555 \r
556             if (token.equals("|"))\r
557             {\r
558               if (emptyColumn)\r
559               {\r
560                 index++;\r
561               }\r
562 \r
563               emptyColumn = true;\r
564             }\r
565             else\r
566             {\r
567               annotations[index++] = parseAnnotation(token);\r
568               emptyColumn = false;\r
569             }\r
570           }\r
571 \r
572         }\r
573 \r
574         annotation = new AlignmentAnnotation(label, description,\r
575                 (index == 0) ? null : annotations, 0, 0, graphStyle);\r
576 \r
577         annotation.score = score;\r
578 \r
579         if (refSeq != null)\r
580         {\r
581           annotation.belowAlignment = false;\r
582           // make a copy of refSeq so we can find other matches in the alignment\r
583           SequenceI referedSeq = refSeq;\r
584           do\r
585           {\r
586             // copy before we do any mapping business.\r
587             // TODO: verify that undo/redo with 1:many sequence associated\r
588             // annotations can be undone correctly\r
589             AlignmentAnnotation ann = new AlignmentAnnotation(annotation);\r
590             annotation.createSequenceMapping(referedSeq, refSeqIndex, false);\r
591             annotation.adjustForAlignment();\r
592             referedSeq.addAlignmentAnnotation(annotation);\r
593             al.addAnnotation(annotation);\r
594             al.setAnnotationIndex(annotation,\r
595                     al.getAlignmentAnnotation().length\r
596                             - existingAnnotations - 1);\r
597             // and recover our virgin copy to use again if necessary.\r
598             annotation = ann;\r
599 \r
600           } while (refSeqId != null\r
601                   && (referedSeq = al.findName(referedSeq, refSeqId, true)) != null);\r
602         }\r
603         else\r
604         {\r
605           al.addAnnotation(annotation);\r
606           al.setAnnotationIndex(annotation,\r
607                   al.getAlignmentAnnotation().length - existingAnnotations\r
608                           - 1);\r
609         }\r
610       }\r
611 \r
612     } catch (Exception ex)\r
613     {\r
614       ex.printStackTrace();\r
615       System.out.println("Problem reading annotation file: " + ex);\r
616       return false;\r
617     }\r
618     return true;\r
619   }\r
620 \r
621   Annotation parseAnnotation(String string)\r
622   {\r
623     String desc = null, displayChar = null;\r
624     char ss = ' '; // secondaryStructure\r
625     float value = 0;\r
626     boolean parsedValue = false;\r
627 \r
628     // find colour here\r
629     java.awt.Color colour = null;\r
630     int i = string.indexOf("[");\r
631     int j = string.indexOf("]");\r
632     if (i > -1 && j > -1)\r
633     {\r
634       UserColourScheme ucs = new UserColourScheme();\r
635 \r
636       colour = ucs.getColourFromString(string.substring(i + 1, j));\r
637 \r
638       string = string.substring(0, i) + string.substring(j + 1);\r
639     }\r
640 \r
641     StringTokenizer st = new StringTokenizer(string, ",");\r
642     String token;\r
643     while (st.hasMoreTokens())\r
644     {\r
645       token = st.nextToken().trim();\r
646       if (token.length() == 0)\r
647       {\r
648         continue;\r
649       }\r
650 \r
651       if (!parsedValue)\r
652       {\r
653         try\r
654         {\r
655           displayChar = token;\r
656           value = new Float(token).floatValue();\r
657           parsedValue = true;\r
658           continue;\r
659         } catch (NumberFormatException ex)\r
660         {\r
661         }\r
662       }\r
663 \r
664       if (token.equals("H") || token.equals("E"))\r
665       {\r
666         // Either this character represents a helix or sheet\r
667         // or an integer which can be displayed\r
668         ss = token.charAt(0);\r
669         if (displayChar.equals(token.substring(0, 1)))\r
670         {\r
671           displayChar = "";\r
672         }\r
673       }\r
674       else if (desc == null)\r
675       {\r
676         desc = token;\r
677       }\r
678 \r
679     }\r
680 \r
681     if (displayChar != null && displayChar.length() > 1 && desc != null\r
682             && desc.length() == 1)\r
683     {\r
684       String tmp = displayChar;\r
685       displayChar = desc;\r
686       desc = tmp;\r
687     }\r
688     /*\r
689      * In principle, this code will ensure that the Annotation element generated\r
690      * is renderable by any of the applet or application rendering code but\r
691      * instead we check for null strings when the display character is rendered.\r
692      * if (displayChar==null) { displayChar=""; }\r
693      */\r
694     Annotation anot = new Annotation(displayChar, desc, ss, value);\r
695 \r
696     anot.colour = colour;\r
697 \r
698     return anot;\r
699   }\r
700 \r
701   void colourAnnotations(AlignmentI al, String label, String colour)\r
702   {\r
703     UserColourScheme ucs = new UserColourScheme(colour);\r
704     Annotation[] annotations;\r
705     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
706     {\r
707       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(label))\r
708       {\r
709         annotations = al.getAlignmentAnnotation()[i].annotations;\r
710         for (int j = 0; j < annotations.length; j++)\r
711         {\r
712           if (annotations[j] != null)\r
713           {\r
714             annotations[j].colour = ucs.findColour('A');\r
715           }\r
716         }\r
717       }\r
718     }\r
719   }\r
720 \r
721   void combineAnnotations(AlignmentI al, StringTokenizer st)\r
722   {\r
723     int graphGroup = -1;\r
724     String group = st.nextToken();\r
725     // First make sure we are not overwriting the graphIndex\r
726     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
727     {\r
728       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
729       {\r
730         graphGroup = al.getAlignmentAnnotation()[i].graphGroup + 1;\r
731         al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
732         break;\r
733       }\r
734     }\r
735 \r
736     // Now update groups\r
737     while (st.hasMoreTokens())\r
738     {\r
739       group = st.nextToken();\r
740       for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
741       {\r
742         if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
743         {\r
744           al.getAlignmentAnnotation()[i].graphGroup = graphGroup;\r
745           break;\r
746         }\r
747       }\r
748     }\r
749   }\r
750 \r
751   void addLine(AlignmentI al, StringTokenizer st)\r
752   {\r
753     String group = st.nextToken();\r
754     AlignmentAnnotation annotation = null;\r
755 \r
756     for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
757     {\r
758       if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(group))\r
759       {\r
760         annotation = al.getAlignmentAnnotation()[i];\r
761         break;\r
762       }\r
763     }\r
764 \r
765     if (annotation == null)\r
766     {\r
767       return;\r
768     }\r
769     float value = new Float(st.nextToken()).floatValue();\r
770     String label = st.hasMoreTokens() ? st.nextToken() : null;\r
771     java.awt.Color colour = null;\r
772     if (st.hasMoreTokens())\r
773     {\r
774       UserColourScheme ucs = new UserColourScheme(st.nextToken());\r
775       colour = ucs.findColour('A');\r
776     }\r
777 \r
778     annotation.setThreshold(new GraphLine(value, label, colour));\r
779   }\r
780   void addGroup(AlignmentI al, StringTokenizer st)\r
781   {\r
782     SequenceGroup sg = new SequenceGroup();\r
783     sg.setName(st.nextToken());\r
784     String rng ="";\r
785     try {\r
786       rng = st.nextToken();\r
787       if (rng.length()>0 && !rng.startsWith("*"))\r
788       {\r
789         sg.setStartRes(Integer.parseInt(rng) - 1);\r
790       } else {\r
791         sg.setStartRes(0);\r
792       }\r
793       rng = st.nextToken();\r
794       if (rng.length()>0 && !rng.startsWith("*"))\r
795       {\r
796         sg.setEndRes(Integer.parseInt(rng) - 1);\r
797       } else {\r
798         sg.setEndRes(al.getWidth()-1);\r
799       }\r
800     } catch (Exception e)\r
801     {\r
802       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
803       // assume group is full width\r
804       sg.setStartRes(0);\r
805       sg.setEndRes(al.getWidth()-1);\r
806     }\r
807 \r
808     String index = st.nextToken();\r
809     if (index.equals("-1"))\r
810     {\r
811       while (st.hasMoreElements())\r
812       {\r
813         sg.addSequence(al.findName(st.nextToken()), false);\r
814       }\r
815     }\r
816     else\r
817     {\r
818       StringTokenizer st2 = new StringTokenizer(index, ",");\r
819 \r
820       while (st2.hasMoreTokens())\r
821       {\r
822         String tmp = st2.nextToken();\r
823         if (tmp.equals("*"))\r
824         {\r
825           for (int i = 0; i < al.getHeight(); i++)\r
826           {\r
827             sg.addSequence(al.getSequenceAt(i), false);\r
828           }\r
829         }\r
830         else if (tmp.indexOf("-") >= 0)\r
831         {\r
832           StringTokenizer st3 = new StringTokenizer(tmp, "-");\r
833 \r
834           int start = (Integer.parseInt(st3.nextToken()));\r
835           int end = (Integer.parseInt(st3.nextToken()));\r
836 \r
837           if (end > start)\r
838           {\r
839             for (int i = start; i <= end; i++)\r
840             {\r
841               sg.addSequence(al.getSequenceAt(i - 1), false);\r
842             }\r
843           }\r
844         }\r
845         else\r
846         {\r
847           sg\r
848                   .addSequence(al.getSequenceAt(Integer.parseInt(tmp) - 1),\r
849                           false);\r
850         }\r
851       }\r
852     }\r
853 \r
854     if (refSeq != null)\r
855     {\r
856       sg.setStartRes(refSeq.findIndex(sg.getStartRes() + 1) - 1);\r
857       sg.setEndRes(refSeq.findIndex(sg.getEndRes() + 1) - 1);\r
858       sg.setSeqrep(refSeq);\r
859     }\r
860 \r
861     if (sg.getSize() > 0)\r
862     {\r
863       al.addGroup(sg);\r
864     }\r
865   }\r
866 \r
867   void addProperties(AlignmentI al, StringTokenizer st)\r
868   {\r
869 \r
870     // So far we have only added groups to the annotationHash,\r
871     // the idea is in the future properties can be added to\r
872     // alignments, other annotations etc\r
873     if (al.getGroups() == null)\r
874     {\r
875       return;\r
876     }\r
877     SequenceGroup sg = null;\r
878 \r
879     String name = st.nextToken();\r
880 \r
881     Vector groups = al.getGroups();\r
882     for (int i = 0; i < groups.size(); i++)\r
883     {\r
884       sg = (SequenceGroup) groups.elementAt(i);\r
885       if (sg.getName().equals(name))\r
886       {\r
887         break;\r
888       }\r
889       else\r
890       {\r
891         sg = null;\r
892       }\r
893     }\r
894 \r
895     if (sg != null)\r
896     {\r
897       String keyValue, key, value;\r
898       ColourSchemeI def = sg.cs;\r
899       sg.cs = null;\r
900       while (st.hasMoreTokens())\r
901       {\r
902         keyValue = st.nextToken();\r
903         key = keyValue.substring(0, keyValue.indexOf("="));\r
904         value = keyValue.substring(keyValue.indexOf("=") + 1);\r
905 \r
906         if (key.equalsIgnoreCase("description"))\r
907         {\r
908           sg.setDescription(value);\r
909         }\r
910         else if (key.equalsIgnoreCase("colour"))\r
911         {\r
912           sg.cs = ColourSchemeProperty.getColour(al, value);\r
913         }\r
914         else if (key.equalsIgnoreCase("pidThreshold"))\r
915         {\r
916           sg.cs.setThreshold(Integer.parseInt(value), true);\r
917 \r
918         }\r
919         else if (key.equalsIgnoreCase("consThreshold"))\r
920         {\r
921           sg.cs.setConservationInc(Integer.parseInt(value));\r
922           Conservation c = new Conservation("Group",\r
923                   ResidueProperties.propHash, 3, sg.getSequences(null), sg\r
924                           .getStartRes(), sg.getEndRes() + 1);\r
925 \r
926           c.calculate();\r
927           c.verdict(false, 25);\r
928 \r
929           sg.cs.setConservation(c);\r
930 \r
931         }\r
932         else if (key.equalsIgnoreCase("outlineColour"))\r
933         {\r
934           sg.setOutlineColour(new UserColourScheme(value).findColour('A'));\r
935         }\r
936         else if (key.equalsIgnoreCase("displayBoxes"))\r
937         {\r
938           sg.setDisplayBoxes(Boolean.valueOf(value).booleanValue());\r
939         }\r
940         else if (key.equalsIgnoreCase("displayText"))\r
941         {\r
942           sg.setDisplayText(Boolean.valueOf(value).booleanValue());\r
943         }\r
944         else if (key.equalsIgnoreCase("colourText"))\r
945         {\r
946           sg.setColourText(Boolean.valueOf(value).booleanValue());\r
947         }\r
948         else if (key.equalsIgnoreCase("textCol1"))\r
949         {\r
950           sg.textColour = new UserColourScheme(value).findColour('A');\r
951         }\r
952         else if (key.equalsIgnoreCase("textCol2"))\r
953         {\r
954           sg.textColour2 = new UserColourScheme(value).findColour('A');\r
955         }\r
956         else if (key.equalsIgnoreCase("textColThreshold"))\r
957         {\r
958           sg.thresholdTextColour = Integer.parseInt(value);\r
959         }\r
960         else if (key.equalsIgnoreCase("idColour"))\r
961         {\r
962           // consider warning if colour doesn't resolve to a real colour\r
963           sg.setIdColour((def = new UserColourScheme(value))\r
964                   .findColour('A'));\r
965         }\r
966         else if (key.equalsIgnoreCase("hide"))\r
967         {\r
968           // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847\r
969           sg.setHidereps(true);\r
970         }\r
971         else if (key.equalsIgnoreCase("hidecols"))\r
972         {\r
973           // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847\r
974           sg.setHideCols(true);\r
975         }\r
976         sg.recalcConservation();\r
977       }\r
978       if (sg.cs == null)\r
979       {\r
980         sg.cs = def;\r
981       }\r
982     }\r
983   }\r
984 \r
985   void setBelowAlignment(AlignmentI al, StringTokenizer st)\r
986   {\r
987     String token;\r
988     AlignmentAnnotation aa;\r
989     while (st.hasMoreTokens())\r
990     {\r
991       token = st.nextToken();\r
992       for (int i = 0; i < al.getAlignmentAnnotation().length; i++)\r
993       {\r
994         aa = al.getAlignmentAnnotation()[i];\r
995         if (aa.sequenceRef == refSeq && aa.label.equals(token))\r
996         {\r
997           aa.belowAlignment = true;\r
998         }\r
999       }\r
1000     }\r
1001   }\r
1002 \r
1003   void addAlignmentDetails(AlignmentI al, StringTokenizer st)\r
1004   {\r
1005     String keyValue, key, value;\r
1006     while (st.hasMoreTokens())\r
1007     {\r
1008       keyValue = st.nextToken();\r
1009       key = keyValue.substring(0, keyValue.indexOf("="));\r
1010       value = keyValue.substring(keyValue.indexOf("=") + 1);\r
1011       al.setProperty(key, value);\r
1012     }\r
1013   }\r
1014 \r
1015   /**\r
1016    * Write annotations as a CSV file of the form 'label, value, value, ...' for\r
1017    * each row.\r
1018    * \r
1019    * @param annotations\r
1020    * @return CSV file as a string.\r
1021    */\r
1022   public String printCSVAnnotations(AlignmentAnnotation[] annotations)\r
1023   {\r
1024     StringBuffer sp = new StringBuffer();\r
1025     for (int i = 0; i < annotations.length; i++)\r
1026     {\r
1027       String atos = annotations[i].toString();\r
1028       int p = 0;\r
1029       do\r
1030       {\r
1031         int cp = atos.indexOf("\n", p);\r
1032         sp.append(annotations[i].label);\r
1033         sp.append(",");\r
1034         if (cp > p)\r
1035         {\r
1036           sp.append(atos.substring(p, cp + 1));\r
1037         }\r
1038         else\r
1039         {\r
1040           sp.append(atos.substring(p));\r
1041           sp.append("\n");\r
1042         }\r
1043         p = cp + 1;\r
1044       } while (p > 0);\r
1045     }\r
1046     return sp.toString();\r
1047   }\r
1048 }\r