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