Clover icon

Coverage Report

  1. Project Clover database Thu Nov 7 2024 17:01:39 GMT
  2. Package jalview.io

File AnnotationFile.java

 

Coverage histogram

../../img/srcFileCovDistChart0.png
0% of files have more coverage

Code metrics

422
752
27
2
1,773
1,496
297
0.39
27.85
13.5
11

Classes

Class Line # Actions
AnnotationFile 50 748 296
0.00%
AnnotationFile.ViewDef 105 4 1
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.io;
22   
23    import java.awt.Color;
24    import java.io.BufferedReader;
25    import java.util.ArrayList;
26    import java.util.BitSet;
27    import java.util.Enumeration;
28    import java.util.HashMap;
29    import java.util.Hashtable;
30    import java.util.List;
31    import java.util.Map;
32    import java.util.StringTokenizer;
33    import java.util.Vector;
34   
35    import jalview.analysis.Conservation;
36    import jalview.api.AlignViewportI;
37    import jalview.datamodel.AlignmentAnnotation;
38    import jalview.datamodel.AlignmentI;
39    import jalview.datamodel.Annotation;
40    import jalview.datamodel.ColumnSelection;
41    import jalview.datamodel.GraphLine;
42    import jalview.datamodel.HiddenColumns;
43    import jalview.datamodel.HiddenSequences;
44    import jalview.datamodel.SequenceGroup;
45    import jalview.datamodel.SequenceI;
46    import jalview.schemes.ColourSchemeI;
47    import jalview.schemes.ColourSchemeProperty;
48    import jalview.util.ColorUtils;
49   
 
50    public class AnnotationFile
51    {
52    private static final String GRAPHLINE = "GRAPHLINE";
53   
54    private static final String COMBINE = "COMBINE";
55   
56    protected String newline = System.getProperty("line.separator");
57   
58    private StringBuffer text;
59   
60    private SequenceI refSeq = null;
61   
62    private String refSeqId = null;
63   
64    private long nlinesread = 0;
65   
66    private String lastread = "";
67   
68    /**
69    * Constructor
70    */
 
71  0 toggle public AnnotationFile()
72    {
73  0 init();
74    }
75   
 
76  0 toggle private void init()
77    {
78  0 text = new StringBuffer("JALVIEW_ANNOTATION" + newline + "# Created: "
79    + new java.util.Date() + newline + newline);
80  0 refSeq = null;
81  0 refSeqId = null;
82    }
83   
84    /**
85    * convenience method for pre-2.9 annotation files which have no view, hidden
86    * columns or hidden row keywords.
87    *
88    * @param annotations
89    * @param list
90    * @param properties
91    * @return annotation file as a string.
92    */
 
93  0 toggle public String printAnnotations(AlignmentAnnotation[] annotations,
94    List<SequenceGroup> list, Hashtable properties)
95    {
96  0 return printAnnotations(annotations, list, properties, null, null,
97    null);
98   
99    }
100   
101    /**
102    * hold all the information about a particular view definition read from or
103    * written out in an annotations file.
104    */
 
105    public class ViewDef
106    {
107    // TODO this class is not used - remove?
108    public final String viewname;
109   
110    public final HiddenSequences hidseqs;
111   
112    public final HiddenColumns hiddencols;
113   
114    public final Hashtable hiddenRepSeqs;
115   
 
116  0 toggle public ViewDef(String vname, HiddenSequences hseqs, HiddenColumns hcols,
117    Hashtable hRepSeqs)
118    {
119  0 this.viewname = vname;
120  0 this.hidseqs = hseqs;
121  0 this.hiddencols = hcols;
122  0 this.hiddenRepSeqs = hRepSeqs;
123    }
124    }
125   
126    /**
127    * Prepare an annotation file given a set of annotations, groups, alignment
128    * properties and views.
129    *
130    * @param annotations
131    * @param list
132    * @param properties
133    * @param views
134    * @return annotation file
135    */
 
136  0 toggle public String printAnnotations(AlignmentAnnotation[] annotations,
137    List<SequenceGroup> list, Hashtable properties, HiddenColumns cs,
138    AlignmentI al, ViewDef view)
139    {
140  0 if (view != null)
141    {
142  0 if (view.viewname != null)
143    {
144  0 text.append("VIEW_DEF\t" + view.viewname + "\n");
145    }
146  0 if (list == null)
147    {
148    // list = view.visibleGroups;
149    }
150  0 if (cs == null)
151    {
152  0 cs = view.hiddencols;
153    }
154  0 if (al == null)
155    {
156    // add hidden rep sequences.
157    }
158    }
159    // first target - store and restore all settings for a view.
160  0 if (al != null && al.hasSeqrep())
161    {
162  0 text.append("VIEW_SETREF\t" + al.getSeqrep().getName() + "\n");
163    }
164  0 if (cs != null && cs.hasHiddenColumns())
165    {
166  0 text.append("VIEW_HIDECOLS\t");
167   
168  0 String regions = cs.regionsToString(",", "-");
169  0 text.append(regions);
170  0 text.append("\n");
171    }
172    // TODO: allow efficient recovery of annotation data shown in several
173    // different views
174  0 if (annotations != null)
175    {
176  0 boolean oneColour = true;
177  0 AlignmentAnnotation row;
178  0 String comma;
179  0 SequenceI refSeq = null;
180  0 SequenceGroup refGroup = null;
181   
182  0 StringBuffer colours = new StringBuffer();
183  0 StringBuffer graphLine = new StringBuffer();
184  0 StringBuffer rowprops = new StringBuffer();
185  0 Hashtable<Integer, String> graphGroup = new Hashtable<>();
186  0 Hashtable<Integer, Object[]> graphGroup_refs = new Hashtable<>();
187  0 BitSet graphGroupSeen = new BitSet();
188   
189  0 java.awt.Color color;
190   
191  0 for (int i = 0; i < annotations.length; i++)
192    {
193  0 row = annotations[i];
194   
195  0 if (!row.visible && !row.hasScore() && !(row.graphGroup > -1
196    && graphGroupSeen.get(row.graphGroup)))
197    {
198  0 continue;
199    }
200   
201  0 color = null;
202  0 oneColour = true;
203   
204    // mark any sequence references for the row
205  0 writeSequence_Ref(refSeq, row.sequenceRef);
206  0 refSeq = row.sequenceRef;
207    // mark any group references for the row
208  0 writeGroup_Ref(refGroup, row.groupRef);
209  0 refGroup = row.groupRef;
210   
211  0 boolean hasGlyphs = row.hasIcons, hasLabels = row.hasText,
212    hasValues = row.hasScore, hasText = false;
213    // lookahead to check what the annotation row object actually contains.
214  0 for (int j = 0; row.annotations != null
215    && j < row.annotations.length
216    && (!hasGlyphs || !hasLabels || !hasValues); j++)
217    {
218  0 if (row.annotations[j] != null)
219    {
220  0 hasLabels |= (row.annotations[j].displayCharacter != null
221    && row.annotations[j].displayCharacter.length() > 0
222    && !row.annotations[j].displayCharacter.equals(" "));
223  0 hasGlyphs |= (row.annotations[j].secondaryStructure != 0
224    && row.annotations[j].secondaryStructure != ' ');
225  0 hasValues |= (!Float.isNaN(row.annotations[j].value)); // NaNs can't
226    // be
227    // rendered..
228  0 hasText |= (row.annotations[j].description != null
229    && row.annotations[j].description.length() > 0);
230    }
231    }
232   
233  0 if (row.graph == AlignmentAnnotation.NO_GRAPH)
234    {
235  0 text.append("NO_GRAPH\t");
236  0 hasValues = false; // only secondary structure
237    // hasLabels = false; // and annotation description string.
238    }
239    else
240    {
241  0 if (row.graph == AlignmentAnnotation.BAR_GRAPH)
242    {
243  0 text.append("BAR_GRAPH\t");
244  0 hasGlyphs = false; // no secondary structure
245   
246    }
247  0 else if (row.graph == AlignmentAnnotation.LINE_GRAPH)
248    {
249  0 hasGlyphs = false; // no secondary structure
250  0 text.append("LINE_GRAPH\t");
251    }
252   
253  0 if (row.getThreshold() != null)
254    {
255  0 graphLine.append("GRAPHLINE\t");
256  0 graphLine.append(row.label);
257  0 graphLine.append("\t");
258  0 graphLine.append(row.getThreshold().value);
259  0 graphLine.append("\t");
260  0 graphLine.append(row.getThreshold().label);
261  0 graphLine.append("\t");
262  0 graphLine.append(jalview.util.Format
263    .getHexString(row.getThreshold().colour));
264  0 graphLine.append(newline);
265    }
266   
267  0 if (row.graphGroup > -1)
268    {
269  0 graphGroupSeen.set(row.graphGroup);
270  0 Integer key = Integer.valueOf(row.graphGroup);
271  0 if (graphGroup.containsKey(key))
272    {
273  0 graphGroup.put(key, graphGroup.get(key) + "\t" + row.label);
274   
275    }
276    else
277    {
278  0 graphGroup_refs.put(key, new Object[] { refSeq, refGroup });
279  0 graphGroup.put(key, row.label);
280    }
281    }
282    }
283   
284  0 text.append(row.label + "\t");
285  0 if (row.description != null)
286    {
287  0 text.append(row.description + "\t");
288    }
289  0 for (int j = 0; row.annotations != null
290    && j < row.annotations.length; j++)
291    {
292  0 if (refSeq != null
293    && jalview.util.Comparison.isGap(refSeq.getCharAt(j)))
294    {
295  0 continue;
296    }
297   
298  0 if (row.annotations[j] != null)
299    {
300  0 comma = "";
301  0 if (hasGlyphs) // could be also hasGlyphs || ...
302    {
303   
304  0 text.append(comma);
305  0 if (row.annotations[j].secondaryStructure != ' ')
306    {
307    // only write out the field if its not whitespace.
308  0 text.append(row.annotations[j].secondaryStructure);
309    }
310  0 comma = ",";
311    }
312  0 if (hasValues)
313    {
314  0 if (!Float.isNaN(row.annotations[j].value))
315    {
316  0 text.append(comma + row.annotations[j].value);
317    }
318    else
319    {
320    // jalview.bin.Console.errPrintln("Skipping NaN - not valid
321    // value.");
322  0 text.append(comma + 0f);// row.annotations[j].value);
323    }
324  0 comma = ",";
325    }
326  0 if (hasLabels)
327    {
328    // TODO: labels are emitted after values for bar graphs.
329  0 if // empty labels are allowed, so
330  0 (row.annotations[j].displayCharacter != null
331    && row.annotations[j].displayCharacter.length() > 0
332    && !row.annotations[j].displayCharacter.equals(" "))
333    {
334  0 text.append(comma + row.annotations[j].displayCharacter);
335  0 comma = ",";
336    }
337    }
338  0 if (hasText)
339    {
340  0 if (row.annotations[j].description != null
341    && row.annotations[j].description.length() > 0
342    && !row.annotations[j].description
343    .equals(row.annotations[j].displayCharacter))
344    {
345  0 text.append(comma + row.annotations[j].description);
346  0 comma = ",";
347    }
348    }
349  0 if (color != null && !color.equals(row.annotations[j].colour))
350    {
351  0 oneColour = false;
352    }
353   
354  0 color = row.annotations[j].colour;
355   
356  0 if (row.annotations[j].colour != null
357    && row.annotations[j].colour != java.awt.Color.black)
358    {
359  0 text.append(comma + "[" + jalview.util.Format
360    .getHexString(row.annotations[j].colour) + "]");
361  0 comma = ",";
362    }
363    }
364  0 text.append("|");
365    }
366   
367  0 if (row.hasScore())
368    {
369  0 text.append("\t" + row.score);
370    }
371   
372  0 text.append(newline);
373   
374  0 if (color != null && color != java.awt.Color.black && oneColour)
375    {
376  0 colours.append("COLOUR\t");
377  0 colours.append(row.label);
378  0 colours.append("\t");
379  0 colours.append(jalview.util.Format.getHexString(color));
380  0 colours.append(newline);
381    }
382  0 if (row.scaleColLabel || row.showAllColLabels
383    || row.centreColLabels)
384    {
385  0 rowprops.append("ROWPROPERTIES\t");
386  0 rowprops.append(row.label);
387  0 rowprops.append("\tscaletofit=");
388  0 rowprops.append(row.scaleColLabel);
389  0 rowprops.append("\tshowalllabs=");
390  0 rowprops.append(row.showAllColLabels);
391  0 rowprops.append("\tcentrelabs=");
392  0 rowprops.append(row.centreColLabels);
393  0 rowprops.append(newline);
394    }
395  0 if (graphLine.length() > 0)
396    {
397  0 text.append(graphLine.toString());
398  0 graphLine.setLength(0);
399    }
400    }
401   
402  0 text.append(newline);
403   
404  0 text.append(colours.toString());
405  0 if (graphGroup.size() > 0)
406    {
407  0 SequenceI oldRefSeq = refSeq;
408  0 SequenceGroup oldRefGroup = refGroup;
409  0 for (Map.Entry<Integer, String> combine_statement : graphGroup
410    .entrySet())
411    {
412  0 Object[] seqRefAndGroup = graphGroup_refs
413    .get(combine_statement.getKey());
414   
415  0 writeSequence_Ref(refSeq, (SequenceI) seqRefAndGroup[0]);
416  0 refSeq = (SequenceI) seqRefAndGroup[0];
417   
418  0 writeGroup_Ref(refGroup, (SequenceGroup) seqRefAndGroup[1]);
419  0 refGroup = (SequenceGroup) seqRefAndGroup[1];
420  0 text.append("COMBINE\t");
421  0 text.append(combine_statement.getValue());
422  0 text.append(newline);
423    }
424  0 writeSequence_Ref(refSeq, oldRefSeq);
425  0 refSeq = oldRefSeq;
426   
427  0 writeGroup_Ref(refGroup, oldRefGroup);
428  0 refGroup = oldRefGroup;
429    }
430  0 text.append(rowprops.toString());
431    }
432   
433  0 if (list != null)
434    {
435  0 printGroups(list);
436    }
437   
438  0 if (properties != null)
439    {
440  0 text.append(newline);
441  0 text.append(newline);
442  0 text.append("ALIGNMENT");
443  0 Enumeration en = properties.keys();
444  0 while (en.hasMoreElements())
445    {
446  0 String key = en.nextElement().toString();
447  0 text.append("\t");
448  0 text.append(key);
449  0 text.append("=");
450  0 text.append(properties.get(key));
451    }
452    // TODO: output alignment visualization settings here if required
453    // iterate through one or more views, defining, marking columns and rows
454    // as visible/hidden, and emmitting view properties.
455    // View specific annotation is
456    }
457   
458  0 return text.toString();
459    }
460   
 
461  0 toggle private Object writeGroup_Ref(SequenceGroup refGroup,
462    SequenceGroup next_refGroup)
463    {
464  0 if (next_refGroup == null)
465    {
466   
467  0 if (refGroup != null)
468    {
469  0 text.append(newline);
470  0 text.append("GROUP_REF\t");
471  0 text.append("ALIGNMENT");
472  0 text.append(newline);
473    }
474  0 return true;
475    }
476    else
477    {
478  0 if (refGroup == null || refGroup != next_refGroup)
479    {
480  0 text.append(newline);
481  0 text.append("GROUP_REF\t");
482  0 text.append(next_refGroup.getName());
483  0 text.append(newline);
484  0 return true;
485    }
486    }
487  0 return false;
488    }
489   
 
490  0 toggle private boolean writeSequence_Ref(SequenceI refSeq, SequenceI next_refSeq)
491    {
492   
493  0 if (next_refSeq == null)
494    {
495  0 if (refSeq != null)
496    {
497  0 text.append(newline);
498  0 text.append("SEQUENCE_REF\t");
499  0 text.append("ALIGNMENT");
500  0 text.append(newline);
501  0 return true;
502    }
503    }
504    else
505    {
506  0 if (refSeq == null || refSeq != next_refSeq)
507    {
508  0 text.append(newline);
509  0 text.append("SEQUENCE_REF\t");
510  0 text.append(next_refSeq.getName());
511  0 text.append(newline);
512  0 return true;
513    }
514    }
515  0 return false;
516    }
517   
 
518  0 toggle protected void printGroups(List<SequenceGroup> list)
519    {
520  0 SequenceI seqrep = null;
521  0 for (SequenceGroup sg : list)
522    {
523  0 if (!sg.hasSeqrep())
524    {
525  0 text.append("SEQUENCE_GROUP\t" + sg.getName() + "\t"
526    + (sg.getStartRes() + 1) + "\t" + (sg.getEndRes() + 1)
527    + "\t" + "-1\t");
528  0 seqrep = null;
529    }
530    else
531    {
532  0 seqrep = sg.getSeqrep();
533  0 text.append("SEQUENCE_REF\t");
534  0 text.append(seqrep.getName());
535  0 text.append(newline);
536  0 text.append("SEQUENCE_GROUP\t");
537  0 text.append(sg.getName());
538  0 text.append("\t");
539  0 text.append((seqrep.findPosition(sg.getStartRes())));
540  0 text.append("\t");
541  0 text.append((seqrep.findPosition(sg.getEndRes())));
542  0 text.append("\t");
543  0 text.append("-1\t");
544    }
545  0 for (int s = 0; s < sg.getSize(); s++)
546    {
547  0 text.append(sg.getSequenceAt(s).getName());
548  0 text.append("\t");
549    }
550  0 text.append(newline);
551  0 text.append("PROPERTIES\t");
552  0 text.append(sg.getName());
553  0 text.append("\t");
554   
555  0 if (sg.getDescription() != null)
556    {
557  0 text.append("description=");
558  0 text.append(sg.getDescription());
559  0 text.append("\t");
560    }
561  0 if (sg.cs != null)
562    {
563  0 text.append("colour=");
564  0 text.append(ColourSchemeProperty
565    .getColourName(sg.cs.getColourScheme()));
566  0 text.append("\t");
567  0 if (sg.cs.getThreshold() != 0)
568    {
569  0 text.append("pidThreshold=");
570  0 text.append(sg.cs.getThreshold());
571    }
572  0 if (sg.cs.conservationApplied())
573    {
574  0 text.append("consThreshold=");
575  0 text.append(sg.cs.getConservationInc());
576  0 text.append("\t");
577    }
578    }
579  0 text.append("outlineColour=");
580  0 text.append(jalview.util.Format.getHexString(sg.getOutlineColour()));
581  0 text.append("\t");
582   
583  0 text.append("displayBoxes=");
584  0 text.append(sg.getDisplayBoxes());
585  0 text.append("\t");
586  0 text.append("displayText=");
587  0 text.append(sg.getDisplayText());
588  0 text.append("\t");
589  0 text.append("colourText=");
590  0 text.append(sg.getColourText());
591  0 text.append("\t");
592  0 text.append("showUnconserved=");
593  0 text.append(sg.getShowNonconserved());
594  0 text.append("\t");
595  0 if (sg.textColour != java.awt.Color.black)
596    {
597  0 text.append("textCol1=");
598  0 text.append(jalview.util.Format.getHexString(sg.textColour));
599  0 text.append("\t");
600    }
601  0 if (sg.textColour2 != java.awt.Color.white)
602    {
603  0 text.append("textCol2=");
604  0 text.append(jalview.util.Format.getHexString(sg.textColour2));
605  0 text.append("\t");
606    }
607  0 if (sg.thresholdTextColour != 0)
608    {
609  0 text.append("textColThreshold=");
610  0 text.append(sg.thresholdTextColour);
611  0 text.append("\t");
612    }
613  0 if (sg.idColour != null)
614    {
615  0 text.append("idColour=");
616  0 text.append(jalview.util.Format.getHexString(sg.idColour));
617  0 text.append("\t");
618    }
619  0 if (sg.isHidereps())
620    {
621  0 text.append("hide=true\t");
622    }
623  0 if (sg.isHideCols())
624    {
625  0 text.append("hidecols=true\t");
626    }
627  0 if (seqrep != null)
628    {
629    // terminate the last line and clear the sequence ref for the group
630  0 text.append(newline);
631  0 text.append("SEQUENCE_REF");
632    }
633  0 text.append(newline);
634  0 text.append(newline);
635   
636    }
637    }
638   
 
639  0 toggle public boolean annotateAlignmentView(AlignViewportI viewport, Object file,
640    DataSourceType protocol)
641    {
642  0 ColumnSelection colSel = viewport.getColumnSelection();
643  0 HiddenColumns hidden = viewport.getAlignment().getHiddenColumns();
644  0 if (colSel == null)
645    {
646  0 colSel = new ColumnSelection();
647    }
648  0 if (hidden == null)
649    {
650  0 hidden = new HiddenColumns();
651    }
652  0 boolean rslt = readAnnotationFile(viewport.getAlignment(), hidden, file,
653    protocol);
654  0 if (rslt && (colSel.hasSelectedColumns() || hidden.hasHiddenColumns()))
655    {
656  0 viewport.setColumnSelection(colSel);
657  0 viewport.getAlignment().setHiddenColumns(hidden);
658    }
659   
660  0 return rslt;
661    }
662   
 
663  0 toggle public boolean readAnnotationFile(AlignmentI al, String file,
664    DataSourceType sourceType)
665    {
666  0 return readAnnotationFile(al, null, file, sourceType);
667    }
668   
 
669  0 toggle public boolean readAnnotationFile(AlignmentI al, HiddenColumns hidden,
670    Object file, DataSourceType sourceType)
671    {
672  0 BufferedReader in = null;
673  0 try
674    {
675  0 in = new FileParse().getBufferedReader(file, sourceType);
676  0 if (in != null)
677    {
678  0 return parseAnnotationFrom(al, hidden, in);
679    }
680    } catch (Exception ex)
681    {
682  0 ex.printStackTrace();
683  0 jalview.bin.Console
684    .outPrintln("Problem reading annotation file: " + ex);
685  0 if (nlinesread > 0)
686    {
687  0 jalview.bin.Console.outPrintln("Last read line " + nlinesread
688    + ": '" + lastread + "' (first 80 chars) ...");
689    }
690  0 return false;
691    }
692  0 return false;
693    }
694   
 
695  0 toggle public boolean parseAnnotationFrom(AlignmentI al, HiddenColumns hidden,
696    BufferedReader in) throws Exception
697    {
698  0 nlinesread = 0;
699  0 ArrayList<Object[]> combineAnnotation_calls = new ArrayList<>();
700  0 ArrayList<Object[]> deferredAnnotation_calls = new ArrayList<>();
701  0 boolean modified = false;
702  0 String groupRef = null;
703  0 Hashtable groupRefRows = new Hashtable();
704   
705  0 Hashtable autoAnnots = new Hashtable();
706    {
707  0 String line, label, description, token;
708  0 int graphStyle, index;
709  0 int refSeqIndex = 1;
710  0 int existingAnnotations = 0;
711    // when true - will add new rows regardless of whether they are duplicate
712    // auto-annotation like consensus or conservation graphs
713  0 boolean overrideAutoAnnot = false;
714  0 if (al.getAlignmentAnnotation() != null)
715    {
716  0 existingAnnotations = al.getAlignmentAnnotation().length;
717  0 if (existingAnnotations > 0)
718    {
719  0 AlignmentAnnotation[] aa = al.getAlignmentAnnotation();
720  0 for (int aai = 0; aai < aa.length; aai++)
721    {
722  0 if (aa[aai].autoCalculated)
723    {
724    // make a note of the name and description
725  0 autoAnnots.put(
726    autoAnnotsKey(aa[aai], aa[aai].sequenceRef,
727  0 (aa[aai].groupRef == null ? null
728    : aa[aai].groupRef.getName())),
729    Integer.valueOf(1));
730    }
731    }
732    }
733    }
734   
735  0 int alWidth = al.getWidth();
736   
737  0 StringTokenizer st;
738  0 Annotation[] annotations;
739  0 AlignmentAnnotation annotation = null;
740   
741    // First confirm this is an Annotation file
742  0 boolean jvAnnotationFile = false;
743  0 while ((line = in.readLine()) != null)
744    {
745  0 nlinesread++;
746  0 lastread = new String(line);
747  0 if (line.indexOf("#") == 0)
748    {
749  0 continue;
750    }
751   
752  0 if (line.indexOf("JALVIEW_ANNOTATION") > -1)
753    {
754  0 jvAnnotationFile = true;
755  0 break;
756    }
757    }
758   
759  0 if (!jvAnnotationFile)
760    {
761  0 in.close();
762  0 return false;
763    }
764   
765  0 while ((line = in.readLine()) != null)
766    {
767  0 nlinesread++;
768  0 lastread = new String(line);
769  0 if (line.indexOf("#") == 0
770    || line.indexOf("JALVIEW_ANNOTATION") > -1
771    || line.length() == 0)
772    {
773  0 continue;
774    }
775   
776  0 st = new StringTokenizer(line, "\t");
777  0 token = st.nextToken();
778  0 if (token.equalsIgnoreCase("COLOUR"))
779    {
780    // TODO: use graduated colour def'n here too
781  0 colourAnnotations(al, st.nextToken(), st.nextToken());
782  0 modified = true;
783  0 continue;
784    }
785   
786  0 else if (token.equalsIgnoreCase(COMBINE))
787    {
788    // keep a record of current state and resolve groupRef at end
789  0 combineAnnotation_calls
790    .add(new Object[]
791    { st, refSeq, groupRef });
792  0 modified = true;
793  0 continue;
794    }
795  0 else if (token.equalsIgnoreCase("ROWPROPERTIES"))
796    {
797  0 addRowProperties(al, st);
798  0 modified = true;
799  0 continue;
800    }
801  0 else if (token.equalsIgnoreCase(GRAPHLINE))
802    {
803    // resolve at end
804  0 deferredAnnotation_calls
805    .add(new Object[]
806    { GRAPHLINE, st, refSeq, groupRef });
807  0 modified = true;
808  0 continue;
809    }
810   
811  0 else if (token.equalsIgnoreCase("SEQUENCE_REF"))
812    {
813  0 if (st.hasMoreTokens())
814    {
815  0 refSeq = al.findName(refSeqId = st.nextToken());
816  0 if (refSeq == null)
817    {
818  0 refSeqId = null;
819    }
820  0 try
821    {
822  0 refSeqIndex = Integer.parseInt(st.nextToken());
823  0 if (refSeqIndex < 1)
824    {
825  0 refSeqIndex = 1;
826  0 jalview.bin.Console.outPrintln(
827    "WARNING: SEQUENCE_REF index must be > 0 in AnnotationFile");
828    }
829    } catch (Exception ex)
830    {
831  0 refSeqIndex = 1;
832    }
833    }
834    else
835    {
836  0 refSeq = null;
837  0 refSeqId = null;
838    }
839  0 continue;
840    }
841  0 else if (token.equalsIgnoreCase("GROUP_REF"))
842    {
843    // Group references could be forward or backwards, so they are
844    // resolved after the whole file is read in
845  0 groupRef = null;
846  0 if (st.hasMoreTokens())
847    {
848  0 groupRef = st.nextToken();
849  0 if (groupRef.length() < 1)
850    {
851  0 groupRef = null; // empty string
852    }
853    else
854    {
855  0 if (groupRefRows.get(groupRef) == null)
856    {
857  0 groupRefRows.put(groupRef, new Vector());
858    }
859    }
860    }
861  0 continue;
862    }
863  0 else if (token.equalsIgnoreCase("SEQUENCE_GROUP"))
864    {
865  0 addGroup(al, st);
866  0 modified = true;
867  0 continue;
868    }
869   
870  0 else if (token.equalsIgnoreCase("PROPERTIES"))
871    {
872  0 addProperties(al, st);
873  0 modified = true;
874  0 continue;
875    }
876   
877  0 else if (token.equalsIgnoreCase("BELOW_ALIGNMENT"))
878    {
879  0 setBelowAlignment(al, st);
880  0 modified = true;
881  0 continue;
882    }
883  0 else if (token.equalsIgnoreCase("ALIGNMENT"))
884    {
885  0 addAlignmentDetails(al, st);
886  0 modified = true;
887  0 continue;
888    }
889    // else if (token.equalsIgnoreCase("VIEW_DEF"))
890    // {
891    // addOrSetView(al,st);
892    // modified = true;
893    // continue;
894    // }
895  0 else if (token.equalsIgnoreCase("VIEW_SETREF"))
896    {
897  0 if (refSeq != null)
898    {
899  0 al.setSeqrep(refSeq);
900    }
901  0 modified = true;
902  0 continue;
903    }
904  0 else if (token.equalsIgnoreCase("VIEW_HIDECOLS"))
905    {
906  0 if (st.hasMoreTokens())
907    {
908  0 if (hidden == null)
909    {
910  0 hidden = new HiddenColumns();
911    }
912  0 parseHideCols(hidden, st.nextToken());
913    }
914  0 modified = true;
915  0 continue;
916    }
917  0 else if (token.equalsIgnoreCase("HIDE_INSERTIONS"))
918    {
919  0 SequenceI sr = refSeq == null ? al.getSeqrep() : refSeq;
920  0 if (sr == null)
921    {
922  0 sr = al.getSequenceAt(0);
923    }
924  0 if (sr != null)
925    {
926  0 if (hidden == null)
927    {
928  0 jalview.bin.Console.errPrintln(
929    "Cannot process HIDE_INSERTIONS without an alignment view: Ignoring line: "
930    + line);
931    }
932    else
933    {
934    // consider deferring this till after the file has been parsed ?
935  0 hidden.hideList(sr.getInsertions());
936    }
937    }
938  0 modified = true;
939  0 continue;
940    }
941   
942    // Parse out the annotation row
943  0 graphStyle = AlignmentAnnotation.getGraphValueFromString(token);
944  0 label = st.nextToken();
945   
946  0 index = 0;
947  0 annotations = new Annotation[alWidth];
948  0 description = null;
949  0 float score = Float.NaN;
950   
951  0 if (st.hasMoreTokens())
952    {
953  0 line = st.nextToken();
954   
955  0 if (line.indexOf("|") == -1)
956    {
957  0 description = line;
958  0 if (st.hasMoreTokens())
959    {
960  0 line = st.nextToken();
961    }
962    }
963   
964  0 if (st.hasMoreTokens())
965    {
966    // This must be the score
967  0 score = Float.valueOf(st.nextToken()).floatValue();
968    }
969   
970  0 st = new StringTokenizer(line, "|", true);
971   
972  0 boolean emptyColumn = true;
973  0 boolean onlyOneElement = (st.countTokens() == 1);
974   
975  0 while (st.hasMoreElements() && index < alWidth)
976    {
977  0 token = st.nextToken().trim();
978   
979  0 if (onlyOneElement)
980    {
981  0 try
982    {
983  0 score = Float.valueOf(token).floatValue();
984  0 break;
985    } catch (NumberFormatException ex)
986    {
987    }
988    }
989   
990  0 if (token.equals("|"))
991    {
992  0 if (emptyColumn)
993    {
994  0 index++;
995    }
996   
997  0 emptyColumn = true;
998    }
999    else
1000    {
1001  0 annotations[index++] = parseAnnotation(token, graphStyle);
1002  0 emptyColumn = false;
1003    }
1004    }
1005   
1006    }
1007   
1008  0 annotation = new AlignmentAnnotation(label, description,
1009  0 (index == 0) ? null : annotations, 0, 0, graphStyle);
1010   
1011  0 annotation.score = score;
1012  0 if (!overrideAutoAnnot && autoAnnots
1013    .containsKey(autoAnnotsKey(annotation, refSeq, groupRef)))
1014    {
1015    // skip - we've already got an automatic annotation of this type.
1016  0 continue;
1017    }
1018    // otherwise add it!
1019  0 if (refSeq != null)
1020    {
1021   
1022  0 annotation.belowAlignment = false;
1023    // make a copy of refSeq so we can find other matches in the alignment
1024  0 SequenceI referedSeq = refSeq;
1025  0 do
1026    {
1027    // copy before we do any mapping business.
1028    // TODO: verify that undo/redo with 1:many sequence associated
1029    // annotations can be undone correctly
1030  0 AlignmentAnnotation ann = new AlignmentAnnotation(annotation);
1031  0 annotation.createSequenceMapping(referedSeq, refSeqIndex,
1032    false);
1033  0 annotation.adjustForAlignment();
1034  0 referedSeq.addAlignmentAnnotation(annotation);
1035  0 al.addAnnotation(annotation);
1036  0 al.setAnnotationIndex(annotation,
1037    al.getAlignmentAnnotation().length - existingAnnotations
1038    - 1);
1039  0 if (groupRef != null)
1040    {
1041  0 ((Vector) groupRefRows.get(groupRef)).addElement(annotation);
1042    }
1043    // and recover our virgin copy to use again if necessary.
1044  0 annotation = ann;
1045   
1046  ? } while (refSeqId != null && (referedSeq = al.findName(referedSeq,
1047    refSeqId, true)) != null);
1048    }
1049    else
1050    {
1051  0 al.addAnnotation(annotation);
1052  0 al.setAnnotationIndex(annotation,
1053    al.getAlignmentAnnotation().length - existingAnnotations
1054    - 1);
1055  0 if (groupRef != null)
1056    {
1057  0 ((Vector) groupRefRows.get(groupRef)).addElement(annotation);
1058    }
1059    }
1060    // and set modification flag
1061  0 modified = true;
1062    }
1063    // Resolve the groupRefs
1064  0 Hashtable<String, SequenceGroup> groupRefLookup = new Hashtable<>();
1065  0 Enumeration en = groupRefRows.keys();
1066   
1067  0 while (en.hasMoreElements())
1068    {
1069  0 groupRef = (String) en.nextElement();
1070  0 boolean matched = false;
1071    // Resolve group: TODO: add a getGroupByName method to alignments
1072  0 for (SequenceGroup theGroup : al.getGroups())
1073    {
1074  0 if (theGroup.getName().equals(groupRef))
1075    {
1076  0 if (matched)
1077    {
1078    // TODO: specify and implement duplication of alignment annotation
1079    // for multiple group references.
1080  0 jalview.bin.Console.errPrintln(
1081    "Ignoring 1:many group reference mappings for group name '"
1082    + groupRef + "'");
1083    }
1084    else
1085    {
1086  0 matched = true;
1087  0 Vector rowset = (Vector) groupRefRows.get(groupRef);
1088  0 groupRefLookup.put(groupRef, theGroup);
1089  0 if (rowset != null && rowset.size() > 0)
1090    {
1091  0 AlignmentAnnotation alan = null;
1092  0 for (int elm = 0, elmSize = rowset
1093  0 .size(); elm < elmSize; elm++)
1094    {
1095  0 alan = (AlignmentAnnotation) rowset.elementAt(elm);
1096  0 alan.groupRef = theGroup;
1097    }
1098    }
1099    }
1100    }
1101    }
1102  0 ((Vector) groupRefRows.get(groupRef)).removeAllElements();
1103    }
1104    // process any deferred attribute settings for each context
1105  0 for (Object[] _deferred_args : deferredAnnotation_calls)
1106    {
1107  0 if (_deferred_args[0] == GRAPHLINE)
1108    {
1109  0 addLine(al, (StringTokenizer) _deferred_args[1], // st
1110    (SequenceI) _deferred_args[2], // refSeq
1111  0 (_deferred_args[3] == null) ? null
1112    : groupRefLookup.get(_deferred_args[3]) // the
1113    // reference
1114    // group, or
1115    // null
1116    );
1117    }
1118    }
1119   
1120    // finally, combine all the annotation rows within each context.
1121    /**
1122    * number of combine statements in this annotation file. Used to create
1123    * new groups for combined annotation graphs without disturbing existing
1124    * ones
1125    */
1126  0 int combinecount = 0;
1127  0 for (Object[] _combine_args : combineAnnotation_calls)
1128    {
1129  0 combineAnnotations(al, ++combinecount,
1130    (StringTokenizer) _combine_args[0], // st
1131    (SequenceI) _combine_args[1], // refSeq
1132  0 (_combine_args[2] == null) ? null
1133    : groupRefLookup.get(_combine_args[2]) // the reference
1134    // group,
1135    // or null
1136    );
1137    }
1138    }
1139  0 return modified;
1140    }
1141   
 
1142  0 toggle private void parseHideCols(HiddenColumns hidden, String nextToken)
1143    {
1144  0 StringTokenizer inval = new StringTokenizer(nextToken, ",");
1145  0 while (inval.hasMoreTokens())
1146    {
1147  0 String range = inval.nextToken().trim();
1148  0 int from, to = range.indexOf("-");
1149  0 if (to == -1)
1150    {
1151  0 from = to = Integer.parseInt(range);
1152  0 if (from >= 0)
1153    {
1154  0 hidden.hideColumns(from, to);
1155    }
1156    }
1157    else
1158    {
1159  0 from = Integer.parseInt(range.substring(0, to));
1160  0 if (to < range.length() - 1)
1161    {
1162  0 to = Integer.parseInt(range.substring(to + 1));
1163    }
1164    else
1165    {
1166  0 to = from;
1167    }
1168  0 if (from > 0 && to >= from)
1169    {
1170  0 hidden.hideColumns(from, to);
1171    }
1172    }
1173    }
1174    }
1175   
 
1176  0 toggle private Object autoAnnotsKey(AlignmentAnnotation annotation,
1177    SequenceI refSeq, String groupRef)
1178    {
1179  0 return annotation.graph + "\t" + annotation.label + "\t"
1180    + annotation.description + "\t"
1181  0 + (refSeq != null ? refSeq.getDisplayId(true) : "");
1182    }
1183   
 
1184  0 toggle Annotation parseAnnotation(String string, int graphStyle)
1185    {
1186    // don't do the glyph test if we don't want secondary structure
1187  0 boolean hasSymbols = (graphStyle == AlignmentAnnotation.NO_GRAPH);
1188  0 String desc = null, displayChar = null;
1189  0 char ss = ' '; // secondaryStructure
1190  0 float value = 0;
1191  0 boolean parsedValue = false, dcset = false;
1192   
1193    // find colour here
1194  0 Color colour = null;
1195  0 int i = string.indexOf("[");
1196  0 int j = string.indexOf("]");
1197  0 if (i > -1 && j > -1)
1198    {
1199  0 colour = ColorUtils.parseColourString(string.substring(i + 1, j));
1200  0 if (i > 0 && string.charAt(i - 1) == ',')
1201    {
1202    // clip the preceding comma as well
1203  0 i--;
1204    }
1205  0 string = string.substring(0, i) + string.substring(j + 1);
1206    }
1207   
1208  0 StringTokenizer st = new StringTokenizer(string, ",", true);
1209  0 String token;
1210  0 boolean seenContent = false;
1211  0 int pass = 0;
1212  0 while (st.hasMoreTokens())
1213    {
1214  0 pass++;
1215  0 token = st.nextToken().trim();
1216  0 if (token.equals(","))
1217    {
1218  0 if (!seenContent && parsedValue && !dcset)
1219    {
1220    // allow the value below the bar/line to be empty
1221  0 dcset = true;
1222  0 displayChar = " ";
1223    }
1224  0 seenContent = false;
1225  0 continue;
1226    }
1227    else
1228    {
1229  0 seenContent = true;
1230    }
1231   
1232  0 if (!parsedValue)
1233    {
1234  0 try
1235    {
1236  0 displayChar = token;
1237    // foo
1238  0 value = Float.valueOf(token).floatValue();
1239  0 parsedValue = true;
1240  0 continue;
1241    } catch (NumberFormatException ex)
1242    {
1243    }
1244    }
1245    else
1246    {
1247  0 if (token.length() == 1)
1248    {
1249  0 displayChar = token;
1250    }
1251    }
1252  0 if (hasSymbols && (token.length() == 1
1253    && "()<>[]{}AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
1254    .contains(token)))
1255    {
1256    // Either this character represents a helix or sheet
1257    // or an integer which can be displayed
1258  0 ss = token.charAt(0);
1259  0 if (displayChar.equals(token.substring(0, 1)))
1260    {
1261  0 displayChar = "";
1262    }
1263    }
1264  0 else if (desc == null || (parsedValue && pass > 2))
1265    {
1266  0 desc = token;
1267    }
1268   
1269    }
1270    // if (!dcset && string.charAt(string.length() - 1) == ',')
1271    // {
1272    // displayChar = " "; // empty display char symbol.
1273    // }
1274  0 if (displayChar != null && desc != null && desc.length() == 1)
1275    {
1276  0 if (displayChar.length() > 1)
1277    {
1278    // switch desc and displayChar - legacy support
1279  0 String tmp = displayChar;
1280  0 displayChar = desc;
1281  0 desc = tmp;
1282    }
1283    else
1284    {
1285  0 if (displayChar.equals(desc))
1286    {
1287    // duplicate label - hangover from the 'robust parser' above
1288  0 desc = null;
1289    }
1290    }
1291    }
1292  0 Annotation anot = new Annotation(displayChar, desc, ss, value);
1293   
1294  0 anot.colour = colour;
1295   
1296  0 return anot;
1297    }
1298   
 
1299  0 toggle void colourAnnotations(AlignmentI al, String label, String colour)
1300    {
1301  0 Color awtColour = ColorUtils.parseColourString(colour);
1302  0 Annotation[] annotations;
1303  0 for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
1304    {
1305  0 if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(label))
1306    {
1307  0 annotations = al.getAlignmentAnnotation()[i].annotations;
1308  0 for (int j = 0; j < annotations.length; j++)
1309    {
1310  0 if (annotations[j] != null)
1311    {
1312  0 annotations[j].colour = awtColour;
1313    }
1314    }
1315    }
1316    }
1317    }
1318   
 
1319  0 toggle void combineAnnotations(AlignmentI al, int combineCount,
1320    StringTokenizer st, SequenceI seqRef, SequenceGroup groupRef)
1321    {
1322  0 String group = st.nextToken();
1323    // First make sure we are not overwriting the graphIndex
1324  0 int graphGroup = 0;
1325  0 if (al.getAlignmentAnnotation() != null)
1326    {
1327  0 for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
1328    {
1329  0 AlignmentAnnotation aa = al.getAlignmentAnnotation()[i];
1330   
1331  0 if (aa.graphGroup > graphGroup)
1332    {
1333    // try to number graphGroups in order of occurence.
1334  0 graphGroup = aa.graphGroup + 1;
1335    }
1336  0 if (aa.sequenceRef == seqRef && aa.groupRef == groupRef
1337    && aa.label.equalsIgnoreCase(group))
1338    {
1339  0 if (aa.graphGroup > -1)
1340    {
1341  0 graphGroup = aa.graphGroup;
1342    }
1343    else
1344    {
1345  0 if (graphGroup <= combineCount)
1346    {
1347  0 graphGroup = combineCount + 1;
1348    }
1349  0 aa.graphGroup = graphGroup;
1350    }
1351  0 break;
1352    }
1353    }
1354   
1355    // Now update groups
1356  0 while (st.hasMoreTokens())
1357    {
1358  0 group = st.nextToken();
1359  0 for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
1360    {
1361  0 AlignmentAnnotation aa = al.getAlignmentAnnotation()[i];
1362  0 if (aa.sequenceRef == seqRef && aa.groupRef == groupRef
1363    && aa.label.equalsIgnoreCase(group))
1364    {
1365  0 aa.graphGroup = graphGroup;
1366  0 break;
1367    }
1368    }
1369    }
1370    }
1371    else
1372    {
1373  0 jalview.bin.Console.errPrintln(
1374    "Couldn't combine annotations. None are added to alignment yet!");
1375    }
1376    }
1377   
 
1378  0 toggle void addLine(AlignmentI al, StringTokenizer st, SequenceI seqRef,
1379    SequenceGroup groupRef)
1380    {
1381  0 String group = st.nextToken();
1382  0 AlignmentAnnotation[] alannot = al.getAlignmentAnnotation();
1383  0 String nextToken = st.nextToken();
1384  0 float value = 0f;
1385  0 try
1386    {
1387  0 value = Float.valueOf(nextToken);
1388    } catch (NumberFormatException e)
1389    {
1390  0 jalview.bin.Console.errPrintln("line " + nlinesread + ": Threshold '"
1391    + nextToken + "' invalid, setting to zero");
1392    }
1393  0 String label = st.hasMoreTokens() ? st.nextToken() : null;
1394  0 Color colour = null;
1395  0 if (st.hasMoreTokens())
1396    {
1397  0 colour = ColorUtils.parseColourString(st.nextToken());
1398    }
1399  0 if (alannot != null)
1400    {
1401  0 for (int i = 0; i < alannot.length; i++)
1402    {
1403  0 if (alannot[i].label.equalsIgnoreCase(group)
1404    && (seqRef == null || alannot[i].sequenceRef == seqRef)
1405    && (groupRef == null || alannot[i].groupRef == groupRef))
1406    {
1407  0 alannot[i].setThreshold(new GraphLine(value, label, colour));
1408    }
1409    }
1410    }
1411    }
1412   
 
1413  0 toggle void addGroup(AlignmentI al, StringTokenizer st)
1414    {
1415  0 SequenceGroup sg = new SequenceGroup();
1416  0 sg.setName(st.nextToken());
1417  0 String rng = "";
1418  0 try
1419    {
1420  0 rng = st.nextToken();
1421  0 if (rng.length() > 0 && !rng.startsWith("*"))
1422    {
1423  0 sg.setStartRes(Integer.parseInt(rng) - 1);
1424    }
1425    else
1426    {
1427  0 sg.setStartRes(0);
1428    }
1429  0 rng = st.nextToken();
1430  0 if (rng.length() > 0 && !rng.startsWith("*"))
1431    {
1432  0 sg.setEndRes(Integer.parseInt(rng) - 1);
1433    }
1434    else
1435    {
1436  0 sg.setEndRes(al.getWidth() - 1);
1437    }
1438    } catch (Exception e)
1439    {
1440  0 jalview.bin.Console.errPrintln(
1441    "Couldn't parse Group Start or End Field as '*' or a valid column or sequence index: '"
1442    + rng + "' - assuming alignment width for group.");
1443    // assume group is full width
1444  0 sg.setStartRes(0);
1445  0 sg.setEndRes(al.getWidth() - 1);
1446    }
1447   
1448  0 String index = st.nextToken();
1449  0 if (index.equals("-1"))
1450    {
1451  0 while (st.hasMoreElements())
1452    {
1453  0 sg.addSequence(al.findName(st.nextToken()), false);
1454    }
1455    }
1456    else
1457    {
1458  0 StringTokenizer st2 = new StringTokenizer(index, ",");
1459   
1460  0 while (st2.hasMoreTokens())
1461    {
1462  0 String tmp = st2.nextToken();
1463  0 if (tmp.equals("*"))
1464    {
1465  0 for (int i = 0; i < al.getHeight(); i++)
1466    {
1467  0 sg.addSequence(al.getSequenceAt(i), false);
1468    }
1469    }
1470  0 else if (tmp.indexOf("-") >= 0)
1471    {
1472  0 StringTokenizer st3 = new StringTokenizer(tmp, "-");
1473   
1474  0 int start = (Integer.parseInt(st3.nextToken()));
1475  0 int end = (Integer.parseInt(st3.nextToken()));
1476   
1477  0 if (end > start)
1478    {
1479  0 for (int i = start; i <= end; i++)
1480    {
1481  0 sg.addSequence(al.getSequenceAt(i - 1), false);
1482    }
1483    }
1484    }
1485    else
1486    {
1487  0 sg.addSequence(al.getSequenceAt(Integer.parseInt(tmp) - 1),
1488    false);
1489    }
1490    }
1491    }
1492   
1493  0 if (refSeq != null)
1494    {
1495  0 sg.setStartRes(refSeq.findIndex(sg.getStartRes() + 1) - 1);
1496  0 sg.setEndRes(refSeq.findIndex(sg.getEndRes() + 1) - 1);
1497  0 sg.setSeqrep(refSeq);
1498    }
1499   
1500  0 if (sg.getSize() > 0)
1501    {
1502  0 al.addGroup(sg);
1503    }
1504    }
1505   
 
1506  0 toggle void addRowProperties(AlignmentI al, StringTokenizer st)
1507    {
1508  0 String label = st.nextToken(), keyValue, key, value;
1509  0 boolean scaletofit = false, centerlab = false, showalllabs = false;
1510  0 while (st.hasMoreTokens())
1511    {
1512  0 keyValue = st.nextToken();
1513  0 key = keyValue.substring(0, keyValue.indexOf("="));
1514  0 value = keyValue.substring(keyValue.indexOf("=") + 1);
1515  0 if (key.equalsIgnoreCase("scaletofit"))
1516    {
1517  0 scaletofit = Boolean.valueOf(value).booleanValue();
1518    }
1519  0 if (key.equalsIgnoreCase("showalllabs"))
1520    {
1521  0 showalllabs = Boolean.valueOf(value).booleanValue();
1522    }
1523  0 if (key.equalsIgnoreCase("centrelabs"))
1524    {
1525  0 centerlab = Boolean.valueOf(value).booleanValue();
1526    }
1527  0 AlignmentAnnotation[] alr = al.getAlignmentAnnotation();
1528  0 if (alr != null)
1529    {
1530  0 for (int i = 0; i < alr.length; i++)
1531    {
1532  0 if (alr[i].label.equalsIgnoreCase(label))
1533    {
1534  0 alr[i].centreColLabels = centerlab;
1535  0 alr[i].scaleColLabel = scaletofit;
1536  0 alr[i].showAllColLabels = showalllabs;
1537    }
1538    }
1539    }
1540    }
1541    }
1542   
 
1543  0 toggle void addProperties(AlignmentI al, StringTokenizer st)
1544    {
1545   
1546    // So far we have only added groups to the annotationHash,
1547    // the idea is in the future properties can be added to
1548    // alignments, other annotations etc
1549  0 if (al.getGroups() == null)
1550    {
1551  0 return;
1552    }
1553   
1554  0 String name = st.nextToken();
1555   
1556  0 Map<String, String> properties = new HashMap<>();
1557  0 while (st.hasMoreTokens())
1558    {
1559  0 String keyValue = st.nextToken();
1560  0 String key = keyValue.substring(0, keyValue.indexOf("="));
1561  0 String value = keyValue.substring(keyValue.indexOf("=") + 1);
1562  0 properties.put(key, value);
1563    }
1564   
1565  0 for (SequenceGroup sg : al.getGroups())
1566    {
1567  0 if (sg.getName().equals(name))
1568    {
1569  0 addProperties(sg, properties, al);
1570    }
1571    }
1572    }
1573   
1574    /**
1575    * Helper method that applies any specified properties to a SequenceGroup
1576    *
1577    * @param sg
1578    * @param properties
1579    * @param al
1580    */
 
1581  0 toggle private void addProperties(SequenceGroup sg,
1582    Map<String, String> properties, AlignmentI al)
1583    {
1584  0 ColourSchemeI def = sg.getColourScheme();
1585  0 for (String key : properties.keySet())
1586    {
1587  0 String value = properties.get(key);
1588  0 if (key.equalsIgnoreCase("description"))
1589    {
1590  0 sg.setDescription(value);
1591    }
1592  0 else if (key.equalsIgnoreCase("colour"))
1593    {
1594    // TODO need to notify colourscheme of view reference once it is
1595    // available
1596  0 sg.cs.setColourScheme(
1597    ColourSchemeProperty.getColourScheme(null, al, value));
1598    }
1599  0 else if (key.equalsIgnoreCase("pidThreshold"))
1600    {
1601  0 sg.cs.setThreshold(Integer.parseInt(value), true);
1602   
1603    }
1604  0 else if (key.equalsIgnoreCase("consThreshold"))
1605    {
1606  0 sg.cs.setConservationInc(Integer.parseInt(value));
1607  0 Conservation c = new Conservation("Group", sg.getSequences(null),
1608    sg.getStartRes(), sg.getEndRes() + 1);
1609   
1610  0 c.calculate();
1611  0 c.verdict(false, 25); // TODO: refer to conservation percent threshold
1612   
1613  0 sg.cs.setConservation(c);
1614   
1615    }
1616  0 else if (key.equalsIgnoreCase("outlineColour"))
1617    {
1618  0 sg.setOutlineColour(ColorUtils.parseColourString(value));
1619    }
1620  0 else if (key.equalsIgnoreCase("displayBoxes"))
1621    {
1622  0 sg.setDisplayBoxes(Boolean.valueOf(value).booleanValue());
1623    }
1624  0 else if (key.equalsIgnoreCase("showUnconserved"))
1625    {
1626  0 sg.setShowNonconserved(Boolean.valueOf(value).booleanValue());
1627    }
1628  0 else if (key.equalsIgnoreCase("displayText"))
1629    {
1630  0 sg.setDisplayText(Boolean.valueOf(value).booleanValue());
1631    }
1632  0 else if (key.equalsIgnoreCase("colourText"))
1633    {
1634  0 sg.setColourText(Boolean.valueOf(value).booleanValue());
1635    }
1636  0 else if (key.equalsIgnoreCase("textCol1"))
1637    {
1638  0 sg.textColour = ColorUtils.parseColourString(value);
1639    }
1640  0 else if (key.equalsIgnoreCase("textCol2"))
1641    {
1642  0 sg.textColour2 = ColorUtils.parseColourString(value);
1643    }
1644  0 else if (key.equalsIgnoreCase("textColThreshold"))
1645    {
1646  0 sg.thresholdTextColour = Integer.parseInt(value);
1647    }
1648  0 else if (key.equalsIgnoreCase("idColour"))
1649    {
1650  0 Color idColour = ColorUtils.parseColourString(value);
1651  0 sg.setIdColour(idColour == null ? Color.black : idColour);
1652    }
1653  0 else if (key.equalsIgnoreCase("hide"))
1654    {
1655    // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847
1656  0 sg.setHidereps(true);
1657    }
1658  0 else if (key.equalsIgnoreCase("hidecols"))
1659    {
1660    // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847
1661  0 sg.setHideCols(true);
1662    }
1663  0 sg.recalcConservation();
1664    }
1665   
1666  0 if (sg.getColourScheme() == null)
1667    {
1668  0 sg.setColourScheme(def);
1669    }
1670    }
1671   
 
1672  0 toggle void setBelowAlignment(AlignmentI al, StringTokenizer st)
1673    {
1674  0 String token;
1675  0 AlignmentAnnotation aa, ala[] = al.getAlignmentAnnotation();
1676  0 if (ala == null)
1677    {
1678  0 System.err.print(
1679    "Warning - no annotation to set below for sequence associated annotation:");
1680    }
1681  0 while (st.hasMoreTokens())
1682    {
1683  0 token = st.nextToken();
1684  0 if (ala == null)
1685    {
1686  0 System.err.print(" " + token);
1687    }
1688    else
1689    {
1690  0 for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
1691    {
1692  0 aa = al.getAlignmentAnnotation()[i];
1693  0 if (aa.sequenceRef == refSeq && aa.label.equals(token))
1694    {
1695  0 aa.belowAlignment = true;
1696    }
1697    }
1698    }
1699    }
1700  0 if (ala == null)
1701    {
1702  0 System.err.print("\n");
1703    }
1704    }
1705   
 
1706  0 toggle void addAlignmentDetails(AlignmentI al, StringTokenizer st)
1707    {
1708  0 String keyValue, key, value;
1709  0 while (st.hasMoreTokens())
1710    {
1711  0 keyValue = st.nextToken();
1712  0 key = keyValue.substring(0, keyValue.indexOf("="));
1713  0 value = keyValue.substring(keyValue.indexOf("=") + 1);
1714  0 al.setProperty(key, value);
1715    }
1716    }
1717   
1718    /**
1719    * Write annotations as a CSV file of the form 'label, value, value, ...' for
1720    * each row.
1721    *
1722    * @param annotations
1723    * @return CSV file as a string.
1724    */
 
1725  0 toggle public String printCSVAnnotations(AlignmentAnnotation[] annotations)
1726    {
1727  0 if (annotations == null)
1728    {
1729  0 return "";
1730    }
1731  0 StringBuffer sp = new StringBuffer();
1732  0 for (int i = 0; i < annotations.length; i++)
1733    {
1734  0 String atos = annotations[i].toString();
1735  0 int p = 0;
1736  0 do
1737    {
1738  0 int cp = atos.indexOf("\n", p);
1739  0 sp.append(annotations[i].label);
1740  0 sp.append(",");
1741  0 if (cp > p)
1742    {
1743  0 sp.append(atos.substring(p, cp + 1));
1744    }
1745    else
1746    {
1747  0 sp.append(atos.substring(p));
1748  0 sp.append(newline);
1749    }
1750  0 p = cp + 1;
1751  0 } while (p > 0);
1752    }
1753  0 return sp.toString();
1754    }
1755   
 
1756  0 toggle public String printAnnotationsForView(AlignViewportI viewport)
1757    {
1758  0 return printAnnotations(
1759  0 viewport.isShowAnnotation()
1760    ? viewport.getAlignment().getAlignmentAnnotation()
1761    : null,
1762    viewport.getAlignment().getGroups(),
1763    viewport.getAlignment().getProperties(),
1764    viewport.getAlignment().getHiddenColumns(),
1765    viewport.getAlignment(), null);
1766    }
1767   
 
1768  0 toggle public String printAnnotationsForAlignment(AlignmentI al)
1769    {
1770  0 return printAnnotations(al.getAlignmentAnnotation(), al.getGroups(),
1771    al.getProperties(), null, al, null);
1772    }
1773    }