Clover icon

Coverage Report

  1. Project Clover database Wed Nov 6 2024 00:56:24 GMT
  2. Package jalview.io

File AnnotationFile.java

 

Coverage histogram

../../img/srcFileCovDistChart8.png
20% 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.775083677.5%
AnnotationFile.ViewDef 105 4 1
1.0100%
 

Contributing tests

This file is covered by 12 tests. .

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  38 toggle public AnnotationFile()
72    {
73  38 init();
74    }
75   
 
76  38 toggle private void init()
77    {
78  38 text = new StringBuffer("JALVIEW_ANNOTATION" + newline + "# Created: "
79    + new java.util.Date() + newline + newline);
80  38 refSeq = null;
81  38 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  5 toggle public ViewDef(String vname, HiddenSequences hseqs, HiddenColumns hcols,
117    Hashtable hRepSeqs)
118    {
119  5 this.viewname = vname;
120  5 this.hidseqs = hseqs;
121  5 this.hiddencols = hcols;
122  5 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  5 toggle public String printAnnotations(AlignmentAnnotation[] annotations,
137    List<SequenceGroup> list, Hashtable properties, HiddenColumns cs,
138    AlignmentI al, ViewDef view)
139    {
140  5 if (view != null)
141    {
142  5 if (view.viewname != null)
143    {
144  0 text.append("VIEW_DEF\t" + view.viewname + "\n");
145    }
146  5 if (list == null)
147    {
148    // list = view.visibleGroups;
149    }
150  5 if (cs == null)
151    {
152  5 cs = view.hiddencols;
153    }
154  5 if (al == null)
155    {
156    // add hidden rep sequences.
157    }
158    }
159    // first target - store and restore all settings for a view.
160  5 if (al != null && al.hasSeqrep())
161    {
162  1 text.append("VIEW_SETREF\t" + al.getSeqrep().getName() + "\n");
163    }
164  5 if (cs != null && cs.hasHiddenColumns())
165    {
166  1 text.append("VIEW_HIDECOLS\t");
167   
168  1 String regions = cs.regionsToString(",", "-");
169  1 text.append(regions);
170  1 text.append("\n");
171    }
172    // TODO: allow efficient recovery of annotation data shown in several
173    // different views
174  5 if (annotations != null)
175    {
176  4 boolean oneColour = true;
177  4 AlignmentAnnotation row;
178  4 String comma;
179  4 SequenceI refSeq = null;
180  4 SequenceGroup refGroup = null;
181   
182  4 StringBuffer colours = new StringBuffer();
183  4 StringBuffer graphLine = new StringBuffer();
184  4 StringBuffer rowprops = new StringBuffer();
185  4 Hashtable<Integer, String> graphGroup = new Hashtable<>();
186  4 Hashtable<Integer, Object[]> graphGroup_refs = new Hashtable<>();
187  4 BitSet graphGroupSeen = new BitSet();
188   
189  4 java.awt.Color color;
190   
191  84 for (int i = 0; i < annotations.length; i++)
192    {
193  80 row = annotations[i];
194   
195  80 if (!row.visible && !row.hasScore() && !(row.graphGroup > -1
196    && graphGroupSeen.get(row.graphGroup)))
197    {
198  0 continue;
199    }
200   
201  80 color = null;
202  80 oneColour = true;
203   
204    // mark any sequence references for the row
205  80 writeSequence_Ref(refSeq, row.sequenceRef);
206  80 refSeq = row.sequenceRef;
207    // mark any group references for the row
208  80 writeGroup_Ref(refGroup, row.groupRef);
209  80 refGroup = row.groupRef;
210   
211  80 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  12348 for (int j = 0; row.annotations != null
215    && j < row.annotations.length
216    && (!hasGlyphs || !hasLabels || !hasValues); j++)
217    {
218  12268 if (row.annotations[j] != null)
219    {
220  9156 hasLabels |= (row.annotations[j].displayCharacter != null
221    && row.annotations[j].displayCharacter.length() > 0
222    && !row.annotations[j].displayCharacter.equals(" "));
223  9156 hasGlyphs |= (row.annotations[j].secondaryStructure != 0
224    && row.annotations[j].secondaryStructure != ' ');
225  9156 hasValues |= (!Float.isNaN(row.annotations[j].value)); // NaNs can't
226    // be
227    // rendered..
228  9156 hasText |= (row.annotations[j].description != null
229    && row.annotations[j].description.length() > 0);
230    }
231    }
232   
233  80 if (row.graph == AlignmentAnnotation.NO_GRAPH)
234    {
235  4 text.append("NO_GRAPH\t");
236  4 hasValues = false; // only secondary structure
237    // hasLabels = false; // and annotation description string.
238    }
239    else
240    {
241  76 if (row.graph == AlignmentAnnotation.BAR_GRAPH)
242    {
243  10 text.append("BAR_GRAPH\t");
244  10 hasGlyphs = false; // no secondary structure
245   
246    }
247  66 else if (row.graph == AlignmentAnnotation.LINE_GRAPH)
248    {
249  66 hasGlyphs = false; // no secondary structure
250  66 text.append("LINE_GRAPH\t");
251    }
252   
253  76 if (row.getThreshold() != null)
254    {
255  62 graphLine.append("GRAPHLINE\t");
256  62 graphLine.append(row.label);
257  62 graphLine.append("\t");
258  62 graphLine.append(row.getThreshold().value);
259  62 graphLine.append("\t");
260  62 graphLine.append(row.getThreshold().label);
261  62 graphLine.append("\t");
262  62 graphLine.append(jalview.util.Format
263    .getHexString(row.getThreshold().colour));
264  62 graphLine.append(newline);
265    }
266   
267  76 if (row.graphGroup > -1)
268    {
269  66 graphGroupSeen.set(row.graphGroup);
270  66 Integer key = Integer.valueOf(row.graphGroup);
271  66 if (graphGroup.containsKey(key))
272    {
273  33 graphGroup.put(key, graphGroup.get(key) + "\t" + row.label);
274   
275    }
276    else
277    {
278  33 graphGroup_refs.put(key, new Object[] { refSeq, refGroup });
279  33 graphGroup.put(key, row.label);
280    }
281    }
282    }
283   
284  80 text.append(row.label + "\t");
285  80 if (row.description != null)
286    {
287  68 text.append(row.description + "\t");
288    }
289  12640 for (int j = 0; row.annotations != null
290    && j < row.annotations.length; j++)
291    {
292  12560 if (refSeq != null
293    && jalview.util.Comparison.isGap(refSeq.getCharAt(j)))
294    {
295  1462 continue;
296    }
297   
298  11098 if (row.annotations[j] != null)
299    {
300  9168 comma = "";
301  9168 if (hasGlyphs) // could be also hasGlyphs || ...
302    {
303   
304  32 text.append(comma);
305  32 if (row.annotations[j].secondaryStructure != ' ')
306    {
307    // only write out the field if its not whitespace.
308  32 text.append(row.annotations[j].secondaryStructure);
309    }
310  32 comma = ",";
311    }
312  9168 if (hasValues)
313    {
314  9136 if (!Float.isNaN(row.annotations[j].value))
315    {
316  9136 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  9136 comma = ",";
325    }
326  9168 if (hasLabels)
327    {
328    // TODO: labels are emitted after values for bar graphs.
329  9150 if // empty labels are allowed, so
330  9150 (row.annotations[j].displayCharacter != null
331    && row.annotations[j].displayCharacter.length() > 0
332    && !row.annotations[j].displayCharacter.equals(" "))
333    {
334  362 text.append(comma + row.annotations[j].displayCharacter);
335  362 comma = ",";
336    }
337    }
338  9168 if (hasText)
339    {
340  9070 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  9028 text.append(comma + row.annotations[j].description);
346  9028 comma = ",";
347    }
348    }
349  9168 if (color != null && !color.equals(row.annotations[j].colour))
350    {
351  450 oneColour = false;
352    }
353   
354  9168 color = row.annotations[j].colour;
355   
356  9168 if (row.annotations[j].colour != null
357    && row.annotations[j].colour != java.awt.Color.black)
358    {
359  8796 text.append(comma + "[" + jalview.util.Format
360    .getHexString(row.annotations[j].colour) + "]");
361  8796 comma = ",";
362    }
363    }
364  11098 text.append("|");
365    }
366   
367  80 if (row.hasScore())
368    {
369  0 text.append("\t" + row.score);
370    }
371   
372  80 text.append(newline);
373   
374  80 if (color != null && color != java.awt.Color.black && oneColour)
375    {
376  68 colours.append("COLOUR\t");
377  68 colours.append(row.label);
378  68 colours.append("\t");
379  68 colours.append(jalview.util.Format.getHexString(color));
380  68 colours.append(newline);
381    }
382  80 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  80 if (graphLine.length() > 0)
396    {
397  62 text.append(graphLine.toString());
398  62 graphLine.setLength(0);
399    }
400    }
401   
402  4 text.append(newline);
403   
404  4 text.append(colours.toString());
405  4 if (graphGroup.size() > 0)
406    {
407  4 SequenceI oldRefSeq = refSeq;
408  4 SequenceGroup oldRefGroup = refGroup;
409  4 for (Map.Entry<Integer, String> combine_statement : graphGroup
410    .entrySet())
411    {
412  33 Object[] seqRefAndGroup = graphGroup_refs
413    .get(combine_statement.getKey());
414   
415  33 writeSequence_Ref(refSeq, (SequenceI) seqRefAndGroup[0]);
416  33 refSeq = (SequenceI) seqRefAndGroup[0];
417   
418  33 writeGroup_Ref(refGroup, (SequenceGroup) seqRefAndGroup[1]);
419  33 refGroup = (SequenceGroup) seqRefAndGroup[1];
420  33 text.append("COMBINE\t");
421  33 text.append(combine_statement.getValue());
422  33 text.append(newline);
423    }
424  4 writeSequence_Ref(refSeq, oldRefSeq);
425  4 refSeq = oldRefSeq;
426   
427  4 writeGroup_Ref(refGroup, oldRefGroup);
428  4 refGroup = oldRefGroup;
429    }
430  4 text.append(rowprops.toString());
431    }
432   
433  5 if (list != null)
434    {
435  5 printGroups(list);
436    }
437   
438  5 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  5 return text.toString();
459    }
460   
 
461  117 toggle private Object writeGroup_Ref(SequenceGroup refGroup,
462    SequenceGroup next_refGroup)
463    {
464  117 if (next_refGroup == null)
465    {
466   
467  117 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  117 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  117 toggle private boolean writeSequence_Ref(SequenceI refSeq, SequenceI next_refSeq)
491    {
492   
493  117 if (next_refSeq == null)
494    {
495  6 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  111 if (refSeq == null || refSeq != next_refSeq)
507    {
508  62 text.append(newline);
509  62 text.append("SEQUENCE_REF\t");
510  62 text.append(next_refSeq.getName());
511  62 text.append(newline);
512  62 return true;
513    }
514    }
515  55 return false;
516    }
517   
 
518  5 toggle protected void printGroups(List<SequenceGroup> list)
519    {
520  5 SequenceI seqrep = null;
521  5 for (SequenceGroup sg : list)
522    {
523  6 if (!sg.hasSeqrep())
524    {
525  2 text.append("SEQUENCE_GROUP\t" + sg.getName() + "\t"
526    + (sg.getStartRes() + 1) + "\t" + (sg.getEndRes() + 1)
527    + "\t" + "-1\t");
528  2 seqrep = null;
529    }
530    else
531    {
532  4 seqrep = sg.getSeqrep();
533  4 text.append("SEQUENCE_REF\t");
534  4 text.append(seqrep.getName());
535  4 text.append(newline);
536  4 text.append("SEQUENCE_GROUP\t");
537  4 text.append(sg.getName());
538  4 text.append("\t");
539  4 text.append((seqrep.findPosition(sg.getStartRes())));
540  4 text.append("\t");
541  4 text.append((seqrep.findPosition(sg.getEndRes())));
542  4 text.append("\t");
543  4 text.append("-1\t");
544    }
545  47 for (int s = 0; s < sg.getSize(); s++)
546    {
547  41 text.append(sg.getSequenceAt(s).getName());
548  41 text.append("\t");
549    }
550  6 text.append(newline);
551  6 text.append("PROPERTIES\t");
552  6 text.append(sg.getName());
553  6 text.append("\t");
554   
555  6 if (sg.getDescription() != null)
556    {
557  2 text.append("description=");
558  2 text.append(sg.getDescription());
559  2 text.append("\t");
560    }
561  6 if (sg.cs != null)
562    {
563  6 text.append("colour=");
564  6 text.append(ColourSchemeProperty
565    .getColourName(sg.cs.getColourScheme()));
566  6 text.append("\t");
567  6 if (sg.cs.getThreshold() != 0)
568    {
569  0 text.append("pidThreshold=");
570  0 text.append(sg.cs.getThreshold());
571    }
572  6 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  6 text.append("outlineColour=");
580  6 text.append(jalview.util.Format.getHexString(sg.getOutlineColour()));
581  6 text.append("\t");
582   
583  6 text.append("displayBoxes=");
584  6 text.append(sg.getDisplayBoxes());
585  6 text.append("\t");
586  6 text.append("displayText=");
587  6 text.append(sg.getDisplayText());
588  6 text.append("\t");
589  6 text.append("colourText=");
590  6 text.append(sg.getColourText());
591  6 text.append("\t");
592  6 text.append("showUnconserved=");
593  6 text.append(sg.getShowNonconserved());
594  6 text.append("\t");
595  6 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  6 if (sg.textColour2 != java.awt.Color.white)
602    {
603  2 text.append("textCol2=");
604  2 text.append(jalview.util.Format.getHexString(sg.textColour2));
605  2 text.append("\t");
606    }
607  6 if (sg.thresholdTextColour != 0)
608    {
609  0 text.append("textColThreshold=");
610  0 text.append(sg.thresholdTextColour);
611  0 text.append("\t");
612    }
613  6 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  6 if (sg.isHidereps())
620    {
621  0 text.append("hide=true\t");
622    }
623  6 if (sg.isHideCols())
624    {
625  0 text.append("hidecols=true\t");
626    }
627  6 if (seqrep != null)
628    {
629    // terminate the last line and clear the sequence ref for the group
630  4 text.append(newline);
631  4 text.append("SEQUENCE_REF");
632    }
633  6 text.append(newline);
634  6 text.append(newline);
635   
636    }
637    }
638   
 
639  8 toggle public boolean annotateAlignmentView(AlignViewportI viewport, Object file,
640    DataSourceType protocol)
641    {
642  8 ColumnSelection colSel = viewport.getColumnSelection();
643  8 HiddenColumns hidden = viewport.getAlignment().getHiddenColumns();
644  8 if (colSel == null)
645    {
646  0 colSel = new ColumnSelection();
647    }
648  8 if (hidden == null)
649    {
650  0 hidden = new HiddenColumns();
651    }
652  8 boolean rslt = readAnnotationFile(viewport.getAlignment(), hidden, file,
653    protocol);
654  8 if (rslt && (colSel.hasSelectedColumns() || hidden.hasHiddenColumns()))
655    {
656  0 viewport.setColumnSelection(colSel);
657  0 viewport.getAlignment().setHiddenColumns(hidden);
658    }
659   
660  8 return rslt;
661    }
662   
 
663  13 toggle public boolean readAnnotationFile(AlignmentI al, String file,
664    DataSourceType sourceType)
665    {
666  13 return readAnnotationFile(al, null, file, sourceType);
667    }
668   
 
669  26 toggle public boolean readAnnotationFile(AlignmentI al, HiddenColumns hidden,
670    Object file, DataSourceType sourceType)
671    {
672  26 BufferedReader in = null;
673  26 try
674    {
675  26 in = new FileParse().getBufferedReader(file, sourceType);
676  26 if (in != null)
677    {
678  26 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  26 toggle public boolean parseAnnotationFrom(AlignmentI al, HiddenColumns hidden,
696    BufferedReader in) throws Exception
697    {
698  26 nlinesread = 0;
699  26 ArrayList<Object[]> combineAnnotation_calls = new ArrayList<>();
700  26 ArrayList<Object[]> deferredAnnotation_calls = new ArrayList<>();
701  26 boolean modified = false;
702  26 String groupRef = null;
703  26 Hashtable groupRefRows = new Hashtable();
704   
705  26 Hashtable autoAnnots = new Hashtable();
706    {
707  26 String line, label, description, token;
708  26 int graphStyle, index;
709  26 int refSeqIndex = 1;
710  26 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  26 boolean overrideAutoAnnot = false;
714  26 if (al.getAlignmentAnnotation() != null)
715    {
716  8 existingAnnotations = al.getAlignmentAnnotation().length;
717  8 if (existingAnnotations > 0)
718    {
719  8 AlignmentAnnotation[] aa = al.getAlignmentAnnotation();
720  40 for (int aai = 0; aai < aa.length; aai++)
721    {
722  32 if (aa[aai].autoCalculated)
723    {
724    // make a note of the name and description
725  32 autoAnnots.put(
726    autoAnnotsKey(aa[aai], aa[aai].sequenceRef,
727  32 (aa[aai].groupRef == null ? null
728    : aa[aai].groupRef.getName())),
729    Integer.valueOf(1));
730    }
731    }
732    }
733    }
734   
735  26 int alWidth = al.getWidth();
736   
737  26 StringTokenizer st;
738  26 Annotation[] annotations;
739  26 AlignmentAnnotation annotation = null;
740   
741    // First confirm this is an Annotation file
742  26 boolean jvAnnotationFile = false;
743  ? while ((line = in.readLine()) != null)
744    {
745  146 nlinesread++;
746  146 lastread = new String(line);
747  146 if (line.indexOf("#") == 0)
748    {
749  18 continue;
750    }
751   
752  128 if (line.indexOf("JALVIEW_ANNOTATION") > -1)
753    {
754  23 jvAnnotationFile = true;
755  23 break;
756    }
757    }
758   
759  26 if (!jvAnnotationFile)
760    {
761  3 in.close();
762  3 return false;
763    }
764   
765  ? while ((line = in.readLine()) != null)
766    {
767  1076 nlinesread++;
768  1076 lastread = new String(line);
769  1076 if (line.indexOf("#") == 0
770    || line.indexOf("JALVIEW_ANNOTATION") > -1
771    || line.length() == 0)
772    {
773  234 continue;
774    }
775   
776  842 st = new StringTokenizer(line, "\t");
777  842 token = st.nextToken();
778  842 if (token.equalsIgnoreCase("COLOUR"))
779    {
780    // TODO: use graduated colour def'n here too
781  172 colourAnnotations(al, st.nextToken(), st.nextToken());
782  172 modified = true;
783  172 continue;
784    }
785   
786  670 else if (token.equalsIgnoreCase(COMBINE))
787    {
788    // keep a record of current state and resolve groupRef at end
789  81 combineAnnotation_calls
790    .add(new Object[]
791    { st, refSeq, groupRef });
792  81 modified = true;
793  81 continue;
794    }
795  589 else if (token.equalsIgnoreCase("ROWPROPERTIES"))
796    {
797  8 addRowProperties(al, st);
798  8 modified = true;
799  8 continue;
800    }
801  581 else if (token.equalsIgnoreCase(GRAPHLINE))
802    {
803    // resolve at end
804  154 deferredAnnotation_calls
805    .add(new Object[]
806    { GRAPHLINE, st, refSeq, groupRef });
807  154 modified = true;
808  154 continue;
809    }
810   
811  427 else if (token.equalsIgnoreCase("SEQUENCE_REF"))
812    {
813  165 if (st.hasMoreTokens())
814    {
815  161 refSeq = al.findName(refSeqId = st.nextToken());
816  161 if (refSeq == null)
817    {
818  0 refSeqId = null;
819    }
820  161 try
821    {
822  161 refSeqIndex = Integer.parseInt(st.nextToken());
823  2 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  159 refSeqIndex = 1;
832    }
833    }
834    else
835    {
836  4 refSeq = null;
837  4 refSeqId = null;
838    }
839  165 continue;
840    }
841  262 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  262 else if (token.equalsIgnoreCase("SEQUENCE_GROUP"))
864    {
865  22 addGroup(al, st);
866  22 modified = true;
867  22 continue;
868    }
869   
870  240 else if (token.equalsIgnoreCase("PROPERTIES"))
871    {
872  18 addProperties(al, st);
873  18 modified = true;
874  18 continue;
875    }
876   
877  222 else if (token.equalsIgnoreCase("BELOW_ALIGNMENT"))
878    {
879  0 setBelowAlignment(al, st);
880  0 modified = true;
881  0 continue;
882    }
883  222 else if (token.equalsIgnoreCase("ALIGNMENT"))
884    {
885  5 addAlignmentDetails(al, st);
886  5 modified = true;
887  5 continue;
888    }
889    // else if (token.equalsIgnoreCase("VIEW_DEF"))
890    // {
891    // addOrSetView(al,st);
892    // modified = true;
893    // continue;
894    // }
895  217 else if (token.equalsIgnoreCase("VIEW_SETREF"))
896    {
897  2 if (refSeq != null)
898    {
899  1 al.setSeqrep(refSeq);
900    }
901  2 modified = true;
902  2 continue;
903    }
904  215 else if (token.equalsIgnoreCase("VIEW_HIDECOLS"))
905    {
906  1 if (st.hasMoreTokens())
907    {
908  1 if (hidden == null)
909    {
910  1 hidden = new HiddenColumns();
911    }
912  1 parseHideCols(hidden, st.nextToken());
913    }
914  1 modified = true;
915  1 continue;
916    }
917  214 else if (token.equalsIgnoreCase("HIDE_INSERTIONS"))
918    {
919  1 SequenceI sr = refSeq == null ? al.getSeqrep() : refSeq;
920  1 if (sr == null)
921    {
922  0 sr = al.getSequenceAt(0);
923    }
924  1 if (sr != null)
925    {
926  1 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  1 hidden.hideList(sr.getInsertions());
936    }
937    }
938  1 modified = true;
939  1 continue;
940    }
941   
942    // Parse out the annotation row
943  213 graphStyle = AlignmentAnnotation.getGraphValueFromString(token);
944  213 label = st.nextToken();
945   
946  213 index = 0;
947  213 annotations = new Annotation[alWidth];
948  213 description = null;
949  213 float score = Float.NaN;
950   
951  213 if (st.hasMoreTokens())
952    {
953  213 line = st.nextToken();
954   
955  213 if (line.indexOf("|") == -1)
956    {
957  187 description = line;
958  187 if (st.hasMoreTokens())
959    {
960  187 line = st.nextToken();
961    }
962    }
963   
964  213 if (st.hasMoreTokens())
965    {
966    // This must be the score
967  12 score = Float.valueOf(st.nextToken()).floatValue();
968    }
969   
970  213 st = new StringTokenizer(line, "|", true);
971   
972  213 boolean emptyColumn = true;
973  213 boolean onlyOneElement = (st.countTokens() == 1);
974   
975  50121 while (st.hasMoreElements() && index < alWidth)
976    {
977  49908 token = st.nextToken().trim();
978   
979  49908 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  49908 if (token.equals("|"))
991    {
992  26769 if (emptyColumn)
993    {
994  3662 index++;
995    }
996   
997  26769 emptyColumn = true;
998    }
999    else
1000    {
1001  23139 annotations[index++] = parseAnnotation(token, graphStyle);
1002  23139 emptyColumn = false;
1003    }
1004    }
1005   
1006    }
1007   
1008  213 annotation = new AlignmentAnnotation(label, description,
1009  213 (index == 0) ? null : annotations, 0, 0, graphStyle);
1010   
1011  213 annotation.score = score;
1012  213 if (!overrideAutoAnnot && autoAnnots
1013    .containsKey(autoAnnotsKey(annotation, refSeq, groupRef)))
1014    {
1015    // skip - we've already got an automatic annotation of this type.
1016  3 continue;
1017    }
1018    // otherwise add it!
1019  210 if (refSeq != null)
1020    {
1021   
1022  181 annotation.belowAlignment = false;
1023    // make a copy of refSeq so we can find other matches in the alignment
1024  181 SequenceI referedSeq = refSeq;
1025  181 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  181 AlignmentAnnotation ann = new AlignmentAnnotation(annotation);
1031  181 annotation.createSequenceMapping(referedSeq, refSeqIndex,
1032    false);
1033  181 annotation.adjustForAlignment();
1034  181 referedSeq.addAlignmentAnnotation(annotation);
1035  181 al.addAnnotation(annotation);
1036  181 al.setAnnotationIndex(annotation,
1037    al.getAlignmentAnnotation().length - existingAnnotations
1038    - 1);
1039  181 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  181 annotation = ann;
1045   
1046  ? } while (refSeqId != null && (referedSeq = al.findName(referedSeq,
1047    refSeqId, true)) != null);
1048    }
1049    else
1050    {
1051  29 al.addAnnotation(annotation);
1052  29 al.setAnnotationIndex(annotation,
1053    al.getAlignmentAnnotation().length - existingAnnotations
1054    - 1);
1055  29 if (groupRef != null)
1056    {
1057  0 ((Vector) groupRefRows.get(groupRef)).addElement(annotation);
1058    }
1059    }
1060    // and set modification flag
1061  210 modified = true;
1062    }
1063    // Resolve the groupRefs
1064  23 Hashtable<String, SequenceGroup> groupRefLookup = new Hashtable<>();
1065  23 Enumeration en = groupRefRows.keys();
1066   
1067  23 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  23 for (Object[] _deferred_args : deferredAnnotation_calls)
1106    {
1107  154 if (_deferred_args[0] == GRAPHLINE)
1108    {
1109  154 addLine(al, (StringTokenizer) _deferred_args[1], // st
1110    (SequenceI) _deferred_args[2], // refSeq
1111  154 (_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  23 int combinecount = 0;
1127  23 for (Object[] _combine_args : combineAnnotation_calls)
1128    {
1129  81 combineAnnotations(al, ++combinecount,
1130    (StringTokenizer) _combine_args[0], // st
1131    (SequenceI) _combine_args[1], // refSeq
1132  81 (_combine_args[2] == null) ? null
1133    : groupRefLookup.get(_combine_args[2]) // the reference
1134    // group,
1135    // or null
1136    );
1137    }
1138    }
1139  23 return modified;
1140    }
1141   
 
1142  1 toggle private void parseHideCols(HiddenColumns hidden, String nextToken)
1143    {
1144  1 StringTokenizer inval = new StringTokenizer(nextToken, ",");
1145  7 while (inval.hasMoreTokens())
1146    {
1147  6 String range = inval.nextToken().trim();
1148  6 int from, to = range.indexOf("-");
1149  6 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  6 from = Integer.parseInt(range.substring(0, to));
1160  6 if (to < range.length() - 1)
1161    {
1162  6 to = Integer.parseInt(range.substring(to + 1));
1163    }
1164    else
1165    {
1166  0 to = from;
1167    }
1168  6 if (from > 0 && to >= from)
1169    {
1170  6 hidden.hideColumns(from, to);
1171    }
1172    }
1173    }
1174    }
1175   
 
1176  245 toggle private Object autoAnnotsKey(AlignmentAnnotation annotation,
1177    SequenceI refSeq, String groupRef)
1178    {
1179  245 return annotation.graph + "\t" + annotation.label + "\t"
1180    + annotation.description + "\t"
1181  245 + (refSeq != null ? refSeq.getDisplayId(true) : "");
1182    }
1183   
 
1184  23139 toggle Annotation parseAnnotation(String string, int graphStyle)
1185    {
1186    // don't do the glyph test if we don't want secondary structure
1187  23139 boolean hasSymbols = (graphStyle == AlignmentAnnotation.NO_GRAPH);
1188  23139 String desc = null, displayChar = null;
1189  23139 char ss = ' '; // secondaryStructure
1190  23139 float value = 0;
1191  23139 boolean parsedValue = false, dcset = false;
1192   
1193    // find colour here
1194  23139 Color colour = null;
1195  23139 int i = string.indexOf("[");
1196  23139 int j = string.indexOf("]");
1197  23139 if (i > -1 && j > -1)
1198    {
1199  21882 colour = ColorUtils.parseColourString(string.substring(i + 1, j));
1200  21882 if (i > 0 && string.charAt(i - 1) == ',')
1201    {
1202    // clip the preceding comma as well
1203  21882 i--;
1204    }
1205  21882 string = string.substring(0, i) + string.substring(j + 1);
1206    }
1207   
1208  23139 StringTokenizer st = new StringTokenizer(string, ",", true);
1209  23139 String token;
1210  23139 boolean seenContent = false;
1211  23139 int pass = 0;
1212  94252 while (st.hasMoreTokens())
1213    {
1214  71113 pass++;
1215  71113 token = st.nextToken().trim();
1216  71113 if (token.equals(","))
1217    {
1218  23991 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  23991 seenContent = false;
1225  23991 continue;
1226    }
1227    else
1228    {
1229  47122 seenContent = true;
1230    }
1231   
1232  47122 if (!parsedValue)
1233    {
1234  23215 try
1235    {
1236  23215 displayChar = token;
1237    // foo
1238  23215 value = Float.valueOf(token).floatValue();
1239  22815 parsedValue = true;
1240  22815 continue;
1241    } catch (NumberFormatException ex)
1242    {
1243    }
1244    }
1245    else
1246    {
1247  23907 if (token.length() == 1)
1248    {
1249  1340 displayChar = token;
1250    }
1251    }
1252  24307 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  352 ss = token.charAt(0);
1259  352 if (displayChar.equals(token.substring(0, 1)))
1260    {
1261  352 displayChar = "";
1262    }
1263    }
1264  23955 else if (desc == null || (parsedValue && pass > 2))
1265    {
1266  23945 desc = token;
1267    }
1268   
1269    }
1270    // if (!dcset && string.charAt(string.length() - 1) == ',')
1271    // {
1272    // displayChar = " "; // empty display char symbol.
1273    // }
1274  23139 if (displayChar != null && desc != null && desc.length() == 1)
1275    {
1276  80 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  80 if (displayChar.equals(desc))
1286    {
1287    // duplicate label - hangover from the 'robust parser' above
1288  80 desc = null;
1289    }
1290    }
1291    }
1292  23139 Annotation anot = new Annotation(displayChar, desc, ss, value);
1293   
1294  23139 anot.colour = colour;
1295   
1296  23139 return anot;
1297    }
1298   
 
1299  172 toggle void colourAnnotations(AlignmentI al, String label, String colour)
1300    {
1301  172 Color awtColour = ColorUtils.parseColourString(colour);
1302  172 Annotation[] annotations;
1303  5322 for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
1304    {
1305  5150 if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(label))
1306    {
1307  2270 annotations = al.getAlignmentAnnotation()[i].annotations;
1308  358660 for (int j = 0; j < annotations.length; j++)
1309    {
1310  356390 if (annotations[j] != null)
1311    {
1312  303946 annotations[j].colour = awtColour;
1313    }
1314    }
1315    }
1316    }
1317    }
1318   
 
1319  81 toggle void combineAnnotations(AlignmentI al, int combineCount,
1320    StringTokenizer st, SequenceI seqRef, SequenceGroup groupRef)
1321    {
1322  81 String group = st.nextToken();
1323    // First make sure we are not overwriting the graphIndex
1324  81 int graphGroup = 0;
1325  81 if (al.getAlignmentAnnotation() != null)
1326    {
1327  1321 for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
1328    {
1329  1321 AlignmentAnnotation aa = al.getAlignmentAnnotation()[i];
1330   
1331  1321 if (aa.graphGroup > graphGroup)
1332    {
1333    // try to number graphGroups in order of occurence.
1334  113 graphGroup = aa.graphGroup + 1;
1335    }
1336  1321 if (aa.sequenceRef == seqRef && aa.groupRef == groupRef
1337    && aa.label.equalsIgnoreCase(group))
1338    {
1339  81 if (aa.graphGroup > -1)
1340    {
1341  0 graphGroup = aa.graphGroup;
1342    }
1343    else
1344    {
1345  81 if (graphGroup <= combineCount)
1346    {
1347  66 graphGroup = combineCount + 1;
1348    }
1349  81 aa.graphGroup = graphGroup;
1350    }
1351  81 break;
1352    }
1353    }
1354   
1355    // Now update groups
1356  162 while (st.hasMoreTokens())
1357    {
1358  81 group = st.nextToken();
1359  1402 for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
1360    {
1361  1402 AlignmentAnnotation aa = al.getAlignmentAnnotation()[i];
1362  1402 if (aa.sequenceRef == seqRef && aa.groupRef == groupRef
1363    && aa.label.equalsIgnoreCase(group))
1364    {
1365  81 aa.graphGroup = graphGroup;
1366  81 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  154 toggle void addLine(AlignmentI al, StringTokenizer st, SequenceI seqRef,
1379    SequenceGroup groupRef)
1380    {
1381  154 String group = st.nextToken();
1382  154 AlignmentAnnotation[] alannot = al.getAlignmentAnnotation();
1383  154 String nextToken = st.nextToken();
1384  154 float value = 0f;
1385  154 try
1386    {
1387  154 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  154 String label = st.hasMoreTokens() ? st.nextToken() : null;
1394  154 Color colour = null;
1395  154 if (st.hasMoreTokens())
1396    {
1397  154 colour = ColorUtils.parseColourString(st.nextToken());
1398    }
1399  154 if (alannot != null)
1400    {
1401  5162 for (int i = 0; i < alannot.length; i++)
1402    {
1403  5008 if (alannot[i].label.equalsIgnoreCase(group)
1404    && (seqRef == null || alannot[i].sequenceRef == seqRef)
1405    && (groupRef == null || alannot[i].groupRef == groupRef))
1406    {
1407  154 alannot[i].setThreshold(new GraphLine(value, label, colour));
1408    }
1409    }
1410    }
1411    }
1412   
 
1413  22 toggle void addGroup(AlignmentI al, StringTokenizer st)
1414    {
1415  22 SequenceGroup sg = new SequenceGroup();
1416  22 sg.setName(st.nextToken());
1417  22 String rng = "";
1418  22 try
1419    {
1420  22 rng = st.nextToken();
1421  22 if (rng.length() > 0 && !rng.startsWith("*"))
1422    {
1423  19 sg.setStartRes(Integer.parseInt(rng) - 1);
1424    }
1425    else
1426    {
1427  3 sg.setStartRes(0);
1428    }
1429  22 rng = st.nextToken();
1430  22 if (rng.length() > 0 && !rng.startsWith("*"))
1431    {
1432  19 sg.setEndRes(Integer.parseInt(rng) - 1);
1433    }
1434    else
1435    {
1436  3 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  22 String index = st.nextToken();
1449  22 if (index.equals("-1"))
1450    {
1451  99 while (st.hasMoreElements())
1452    {
1453  84 sg.addSequence(al.findName(st.nextToken()), false);
1454    }
1455    }
1456    else
1457    {
1458  7 StringTokenizer st2 = new StringTokenizer(index, ",");
1459   
1460  14 while (st2.hasMoreTokens())
1461    {
1462  7 String tmp = st2.nextToken();
1463  7 if (tmp.equals("*"))
1464    {
1465  32 for (int i = 0; i < al.getHeight(); i++)
1466    {
1467  30 sg.addSequence(al.getSequenceAt(i), false);
1468    }
1469    }
1470  5 else if (tmp.indexOf("-") >= 0)
1471    {
1472  2 StringTokenizer st3 = new StringTokenizer(tmp, "-");
1473   
1474  2 int start = (Integer.parseInt(st3.nextToken()));
1475  2 int end = (Integer.parseInt(st3.nextToken()));
1476   
1477  2 if (end > start)
1478    {
1479  10 for (int i = start; i <= end; i++)
1480    {
1481  8 sg.addSequence(al.getSequenceAt(i - 1), false);
1482    }
1483    }
1484    }
1485    else
1486    {
1487  3 sg.addSequence(al.getSequenceAt(Integer.parseInt(tmp) - 1),
1488    false);
1489    }
1490    }
1491    }
1492   
1493  22 if (refSeq != null)
1494    {
1495  10 sg.setStartRes(refSeq.findIndex(sg.getStartRes() + 1) - 1);
1496  10 sg.setEndRes(refSeq.findIndex(sg.getEndRes() + 1) - 1);
1497  10 sg.setSeqrep(refSeq);
1498    }
1499   
1500  22 if (sg.getSize() > 0)
1501    {
1502  20 al.addGroup(sg);
1503    }
1504    }
1505   
 
1506  8 toggle void addRowProperties(AlignmentI al, StringTokenizer st)
1507    {
1508  8 String label = st.nextToken(), keyValue, key, value;
1509  8 boolean scaletofit = false, centerlab = false, showalllabs = false;
1510  32 while (st.hasMoreTokens())
1511    {
1512  24 keyValue = st.nextToken();
1513  24 key = keyValue.substring(0, keyValue.indexOf("="));
1514  24 value = keyValue.substring(keyValue.indexOf("=") + 1);
1515  24 if (key.equalsIgnoreCase("scaletofit"))
1516    {
1517  8 scaletofit = Boolean.valueOf(value).booleanValue();
1518    }
1519  24 if (key.equalsIgnoreCase("showalllabs"))
1520    {
1521  8 showalllabs = Boolean.valueOf(value).booleanValue();
1522    }
1523  24 if (key.equalsIgnoreCase("centrelabs"))
1524    {
1525  8 centerlab = Boolean.valueOf(value).booleanValue();
1526    }
1527  24 AlignmentAnnotation[] alr = al.getAlignmentAnnotation();
1528  24 if (alr != null)
1529    {
1530  48 for (int i = 0; i < alr.length; i++)
1531    {
1532  24 if (alr[i].label.equalsIgnoreCase(label))
1533    {
1534  24 alr[i].centreColLabels = centerlab;
1535  24 alr[i].scaleColLabel = scaletofit;
1536  24 alr[i].showAllColLabels = showalllabs;
1537    }
1538    }
1539    }
1540    }
1541    }
1542   
 
1543  18 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  18 if (al.getGroups() == null)
1550    {
1551  0 return;
1552    }
1553   
1554  18 String name = st.nextToken();
1555   
1556  18 Map<String, String> properties = new HashMap<>();
1557  120 while (st.hasMoreTokens())
1558    {
1559  102 String keyValue = st.nextToken();
1560  102 String key = keyValue.substring(0, keyValue.indexOf("="));
1561  102 String value = keyValue.substring(keyValue.indexOf("=") + 1);
1562  102 properties.put(key, value);
1563    }
1564   
1565  18 for (SequenceGroup sg : al.getGroups())
1566    {
1567  39 if (sg.getName().equals(name))
1568    {
1569  17 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  17 toggle private void addProperties(SequenceGroup sg,
1582    Map<String, String> properties, AlignmentI al)
1583    {
1584  17 ColourSchemeI def = sg.getColourScheme();
1585  17 for (String key : properties.keySet())
1586    {
1587  102 String value = properties.get(key);
1588  102 if (key.equalsIgnoreCase("description"))
1589    {
1590  4 sg.setDescription(value);
1591    }
1592  98 else if (key.equalsIgnoreCase("colour"))
1593    {
1594    // TODO need to notify colourscheme of view reference once it is
1595    // available
1596  9 sg.cs.setColourScheme(
1597    ColourSchemeProperty.getColourScheme(null, al, value));
1598    }
1599  89 else if (key.equalsIgnoreCase("pidThreshold"))
1600    {
1601  2 sg.cs.setThreshold(Integer.parseInt(value), true);
1602   
1603    }
1604  87 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  87 else if (key.equalsIgnoreCase("outlineColour"))
1617    {
1618  17 sg.setOutlineColour(ColorUtils.parseColourString(value));
1619    }
1620  70 else if (key.equalsIgnoreCase("displayBoxes"))
1621    {
1622  13 sg.setDisplayBoxes(Boolean.valueOf(value).booleanValue());
1623    }
1624  57 else if (key.equalsIgnoreCase("showUnconserved"))
1625    {
1626  11 sg.setShowNonconserved(Boolean.valueOf(value).booleanValue());
1627    }
1628  46 else if (key.equalsIgnoreCase("displayText"))
1629    {
1630  13 sg.setDisplayText(Boolean.valueOf(value).booleanValue());
1631    }
1632  33 else if (key.equalsIgnoreCase("colourText"))
1633    {
1634  13 sg.setColourText(Boolean.valueOf(value).booleanValue());
1635    }
1636  20 else if (key.equalsIgnoreCase("textCol1"))
1637    {
1638  7 sg.textColour = ColorUtils.parseColourString(value);
1639    }
1640  13 else if (key.equalsIgnoreCase("textCol2"))
1641    {
1642  9 sg.textColour2 = ColorUtils.parseColourString(value);
1643    }
1644  4 else if (key.equalsIgnoreCase("textColThreshold"))
1645    {
1646  2 sg.thresholdTextColour = Integer.parseInt(value);
1647    }
1648  2 else if (key.equalsIgnoreCase("idColour"))
1649    {
1650  2 Color idColour = ColorUtils.parseColourString(value);
1651  2 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  102 sg.recalcConservation();
1664    }
1665   
1666  17 if (sg.getColourScheme() == null)
1667    {
1668  13 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  5 toggle void addAlignmentDetails(AlignmentI al, StringTokenizer st)
1707    {
1708  5 String keyValue, key, value;
1709  15 while (st.hasMoreTokens())
1710    {
1711  10 keyValue = st.nextToken();
1712  10 key = keyValue.substring(0, keyValue.indexOf("="));
1713  10 value = keyValue.substring(keyValue.indexOf("=") + 1);
1714  10 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  2 toggle public String printCSVAnnotations(AlignmentAnnotation[] annotations)
1726    {
1727  2 if (annotations == null)
1728    {
1729  0 return "";
1730    }
1731  2 StringBuffer sp = new StringBuffer();
1732  7 for (int i = 0; i < annotations.length; i++)
1733    {
1734  5 String atos = annotations[i].toString();
1735  5 int p = 0;
1736  5 do
1737    {
1738  6 int cp = atos.indexOf("\n", p);
1739  6 sp.append(annotations[i].label);
1740  6 sp.append(",");
1741  6 if (cp > p)
1742    {
1743  1 sp.append(atos.substring(p, cp + 1));
1744    }
1745    else
1746    {
1747  5 sp.append(atos.substring(p));
1748  5 sp.append(newline);
1749    }
1750  6 p = cp + 1;
1751  6 } while (p > 0);
1752    }
1753  2 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    }