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