Clover icon

Coverage Report

  1. Project Clover database Mon Nov 18 2024 09:38:20 GMT
  2. Package jalview.io

File AnnotationFile.java

 

Coverage histogram

../../img/srcFileCovDistChart4.png
40% of files have more coverage

Code metrics

426
759
27
2
1,787
1,509
299
0.39
28.11
13.5
11.07

Classes

Class Line # Actions
AnnotationFile 50 755 298
0.3206296632.1%
AnnotationFile.ViewDef 105 4 1
0.00%
 

Contributing tests

This file is covered by 5 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  9 toggle public AnnotationFile()
72    {
73  9 init();
74    }
75   
 
76  9 toggle private void init()
77    {
78  9 text = new StringBuffer("JALVIEW_ANNOTATION" + newline + "# Created: "
79    + new java.util.Date() + newline + newline);
80  9 refSeq = null;
81  9 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.isConsensusSecondaryStructureColouring())
573    {
574  0 text.append("secondaryStructureConservationThreshold=");
575  0 text.append(sg.cs.getConsensusSecondaryStructureThreshold());
576  0 text.append("\t");
577    }
578  0 if (sg.cs.conservationApplied())
579    {
580  0 text.append("consThreshold=");
581  0 text.append(sg.cs.getConservationInc());
582  0 text.append("\t");
583    }
584    }
585  0 text.append("outlineColour=");
586  0 text.append(jalview.util.Format.getHexString(sg.getOutlineColour()));
587  0 text.append("\t");
588   
589  0 text.append("displayBoxes=");
590  0 text.append(sg.getDisplayBoxes());
591  0 text.append("\t");
592  0 text.append("displayText=");
593  0 text.append(sg.getDisplayText());
594  0 text.append("\t");
595  0 text.append("colourText=");
596  0 text.append(sg.getColourText());
597  0 text.append("\t");
598  0 text.append("showUnconserved=");
599  0 text.append(sg.getShowNonconserved());
600  0 text.append("\t");
601  0 if (sg.textColour != java.awt.Color.black)
602    {
603  0 text.append("textCol1=");
604  0 text.append(jalview.util.Format.getHexString(sg.textColour));
605  0 text.append("\t");
606    }
607  0 if (sg.textColour2 != java.awt.Color.white)
608    {
609  0 text.append("textCol2=");
610  0 text.append(jalview.util.Format.getHexString(sg.textColour2));
611  0 text.append("\t");
612    }
613  0 if (sg.thresholdTextColour != 0)
614    {
615  0 text.append("textColThreshold=");
616  0 text.append(sg.thresholdTextColour);
617  0 text.append("\t");
618    }
619  0 if (sg.idColour != null)
620    {
621  0 text.append("idColour=");
622  0 text.append(jalview.util.Format.getHexString(sg.idColour));
623  0 text.append("\t");
624    }
625  0 if (sg.isHidereps())
626    {
627  0 text.append("hide=true\t");
628    }
629  0 if (sg.isHideCols())
630    {
631  0 text.append("hidecols=true\t");
632    }
633  0 if (seqrep != null)
634    {
635    // terminate the last line and clear the sequence ref for the group
636  0 text.append(newline);
637  0 text.append("SEQUENCE_REF");
638    }
639  0 text.append(newline);
640  0 text.append(newline);
641   
642    }
643    }
644   
 
645  1 toggle public boolean annotateAlignmentView(AlignViewportI viewport, Object file,
646    DataSourceType protocol)
647    {
648  1 ColumnSelection colSel = viewport.getColumnSelection();
649  1 HiddenColumns hidden = viewport.getAlignment().getHiddenColumns();
650  1 if (colSel == null)
651    {
652  0 colSel = new ColumnSelection();
653    }
654  1 if (hidden == null)
655    {
656  0 hidden = new HiddenColumns();
657    }
658  1 boolean rslt = readAnnotationFile(viewport.getAlignment(), hidden, file,
659    protocol);
660  1 if (rslt && (colSel.hasSelectedColumns() || hidden.hasHiddenColumns()))
661    {
662  0 viewport.setColumnSelection(colSel);
663  0 viewport.getAlignment().setHiddenColumns(hidden);
664    }
665   
666  1 return rslt;
667    }
668   
 
669  8 toggle public boolean readAnnotationFile(AlignmentI al, String file,
670    DataSourceType sourceType)
671    {
672  8 return readAnnotationFile(al, null, file, sourceType);
673    }
674   
 
675  9 toggle public boolean readAnnotationFile(AlignmentI al, HiddenColumns hidden,
676    Object file, DataSourceType sourceType)
677    {
678  9 BufferedReader in = null;
679  9 try
680    {
681  9 in = new FileParse().getBufferedReader(file, sourceType);
682  9 if (in != null)
683    {
684  9 return parseAnnotationFrom(al, hidden, in);
685    }
686    } catch (Exception ex)
687    {
688  0 ex.printStackTrace();
689  0 jalview.bin.Console
690    .outPrintln("Problem reading annotation file: " + ex);
691  0 if (nlinesread > 0)
692    {
693  0 jalview.bin.Console.outPrintln("Last read line " + nlinesread
694    + ": '" + lastread + "' (first 80 chars) ...");
695    }
696  0 return false;
697    }
698  0 return false;
699    }
700   
 
701  9 toggle public boolean parseAnnotationFrom(AlignmentI al, HiddenColumns hidden,
702    BufferedReader in) throws Exception
703    {
704  9 nlinesread = 0;
705  9 ArrayList<Object[]> combineAnnotation_calls = new ArrayList<>();
706  9 ArrayList<Object[]> deferredAnnotation_calls = new ArrayList<>();
707  9 boolean modified = false;
708  9 String groupRef = null;
709  9 Hashtable groupRefRows = new Hashtable();
710   
711  9 Hashtable autoAnnots = new Hashtable();
712    {
713  9 String line, label, description, token;
714  9 int graphStyle, index;
715  9 int refSeqIndex = 1;
716  9 int existingAnnotations = 0;
717    // when true - will add new rows regardless of whether they are duplicate
718    // auto-annotation like consensus or conservation graphs
719  9 boolean overrideAutoAnnot = false;
720  9 if (al.getAlignmentAnnotation() != null)
721    {
722  1 existingAnnotations = al.getAlignmentAnnotation().length;
723  1 if (existingAnnotations > 0)
724    {
725  1 AlignmentAnnotation[] aa = al.getAlignmentAnnotation();
726  5 for (int aai = 0; aai < aa.length; aai++)
727    {
728  4 if (aa[aai].autoCalculated)
729    {
730    // make a note of the name and description
731  4 autoAnnots.put(
732    autoAnnotsKey(aa[aai], aa[aai].sequenceRef,
733  4 (aa[aai].groupRef == null ? null
734    : aa[aai].groupRef.getName())),
735    Integer.valueOf(1));
736    }
737    }
738    }
739    }
740   
741  9 int alWidth = al.getWidth();
742   
743  9 StringTokenizer st;
744  9 Annotation[] annotations;
745  9 AlignmentAnnotation annotation = null;
746   
747    // First confirm this is an Annotation file
748  9 boolean jvAnnotationFile = false;
749  ? while ((line = in.readLine()) != null)
750    {
751  9 nlinesread++;
752  9 lastread = new String(line);
753  9 if (line.indexOf("#") == 0)
754    {
755  0 continue;
756    }
757   
758  9 if (line.indexOf("JALVIEW_ANNOTATION") > -1)
759    {
760  9 jvAnnotationFile = true;
761  9 break;
762    }
763    }
764   
765  9 if (!jvAnnotationFile)
766    {
767  0 in.close();
768  0 return false;
769    }
770   
771  ? while ((line = in.readLine()) != null)
772    {
773  73 nlinesread++;
774  73 lastread = new String(line);
775  73 if (line.indexOf("#") == 0
776    || line.indexOf("JALVIEW_ANNOTATION") > -1
777    || line.length() == 0)
778    {
779  39 continue;
780    }
781   
782  34 st = new StringTokenizer(line, "\t");
783  34 token = st.nextToken();
784  34 if (token.equalsIgnoreCase("COLOUR"))
785    {
786    // TODO: use graduated colour def'n here too
787  0 colourAnnotations(al, st.nextToken(), st.nextToken());
788  0 modified = true;
789  0 continue;
790    }
791   
792  34 else if (token.equalsIgnoreCase(COMBINE))
793    {
794    // keep a record of current state and resolve groupRef at end
795  0 combineAnnotation_calls
796    .add(new Object[]
797    { st, refSeq, groupRef });
798  0 modified = true;
799  0 continue;
800    }
801  34 else if (token.equalsIgnoreCase("ROWPROPERTIES"))
802    {
803  8 addRowProperties(al, st);
804  8 modified = true;
805  8 continue;
806    }
807  26 else if (token.equalsIgnoreCase(GRAPHLINE))
808    {
809    // resolve at end
810  0 deferredAnnotation_calls
811    .add(new Object[]
812    { GRAPHLINE, st, refSeq, groupRef });
813  0 modified = true;
814  0 continue;
815    }
816   
817  26 else if (token.equalsIgnoreCase("SEQUENCE_REF"))
818    {
819  3 if (st.hasMoreTokens())
820    {
821  3 refSeq = al.findName(refSeqId = st.nextToken());
822  3 if (refSeq == null)
823    {
824  0 refSeqId = null;
825    }
826  3 try
827    {
828  3 refSeqIndex = Integer.parseInt(st.nextToken());
829  0 if (refSeqIndex < 1)
830    {
831  0 refSeqIndex = 1;
832  0 jalview.bin.Console.outPrintln(
833    "WARNING: SEQUENCE_REF index must be > 0 in AnnotationFile");
834    }
835    } catch (Exception ex)
836    {
837  3 refSeqIndex = 1;
838    }
839    }
840    else
841    {
842  0 refSeq = null;
843  0 refSeqId = null;
844    }
845  3 continue;
846    }
847  23 else if (token.equalsIgnoreCase("GROUP_REF"))
848    {
849    // Group references could be forward or backwards, so they are
850    // resolved after the whole file is read in
851  0 groupRef = null;
852  0 if (st.hasMoreTokens())
853    {
854  0 groupRef = st.nextToken();
855  0 if (groupRef.length() < 1)
856    {
857  0 groupRef = null; // empty string
858    }
859    else
860    {
861  0 if (groupRefRows.get(groupRef) == null)
862    {
863  0 groupRefRows.put(groupRef, new Vector());
864    }
865    }
866    }
867  0 continue;
868    }
869  23 else if (token.equalsIgnoreCase("SEQUENCE_GROUP"))
870    {
871  5 addGroup(al, st);
872  5 modified = true;
873  5 continue;
874    }
875   
876  18 else if (token.equalsIgnoreCase("PROPERTIES"))
877    {
878  5 addProperties(al, st);
879  5 modified = true;
880  5 continue;
881    }
882   
883  13 else if (token.equalsIgnoreCase("BELOW_ALIGNMENT"))
884    {
885  0 setBelowAlignment(al, st);
886  0 modified = true;
887  0 continue;
888    }
889  13 else if (token.equalsIgnoreCase("ALIGNMENT"))
890    {
891  5 addAlignmentDetails(al, st);
892  5 modified = true;
893  5 continue;
894    }
895    // else if (token.equalsIgnoreCase("VIEW_DEF"))
896    // {
897    // addOrSetView(al,st);
898    // modified = true;
899    // continue;
900    // }
901  8 else if (token.equalsIgnoreCase("VIEW_SETREF"))
902    {
903  0 if (refSeq != null)
904    {
905  0 al.setSeqrep(refSeq);
906    }
907  0 modified = true;
908  0 continue;
909    }
910  8 else if (token.equalsIgnoreCase("VIEW_HIDECOLS"))
911    {
912  0 if (st.hasMoreTokens())
913    {
914  0 if (hidden == null)
915    {
916  0 hidden = new HiddenColumns();
917    }
918  0 parseHideCols(hidden, st.nextToken());
919    }
920  0 modified = true;
921  0 continue;
922    }
923  8 else if (token.equalsIgnoreCase("HIDE_INSERTIONS"))
924    {
925  0 SequenceI sr = refSeq == null ? al.getSeqrep() : refSeq;
926  0 if (sr == null)
927    {
928  0 sr = al.getSequenceAt(0);
929    }
930  0 if (sr != null)
931    {
932  0 if (hidden == null)
933    {
934  0 jalview.bin.Console.errPrintln(
935    "Cannot process HIDE_INSERTIONS without an alignment view: Ignoring line: "
936    + line);
937    }
938    else
939    {
940    // consider deferring this till after the file has been parsed ?
941  0 hidden.hideList(sr.getInsertions());
942    }
943    }
944  0 modified = true;
945  0 continue;
946    }
947   
948    // Parse out the annotation row
949  8 graphStyle = AlignmentAnnotation.getGraphValueFromString(token);
950  8 label = st.nextToken();
951   
952  8 index = 0;
953  8 annotations = new Annotation[alWidth];
954  8 description = null;
955  8 float score = Float.NaN;
956   
957  8 if (st.hasMoreTokens())
958    {
959  8 line = st.nextToken();
960   
961  8 if (line.indexOf("|") == -1)
962    {
963  8 description = line;
964  8 if (st.hasMoreTokens())
965    {
966  8 line = st.nextToken();
967    }
968    }
969   
970  8 if (st.hasMoreTokens())
971    {
972    // This must be the score
973  8 score = Float.valueOf(st.nextToken()).floatValue();
974    }
975   
976  8 st = new StringTokenizer(line, "|", true);
977   
978  8 boolean emptyColumn = true;
979  8 boolean onlyOneElement = (st.countTokens() == 1);
980   
981  239 while (st.hasMoreElements() && index < alWidth)
982    {
983  231 token = st.nextToken().trim();
984   
985  231 if (onlyOneElement)
986    {
987  0 try
988    {
989  0 score = Float.valueOf(token).floatValue();
990  0 break;
991    } catch (NumberFormatException ex)
992    {
993    }
994    }
995   
996  231 if (token.equals("|"))
997    {
998  117 if (emptyColumn)
999    {
1000  8 index++;
1001    }
1002   
1003  117 emptyColumn = true;
1004    }
1005    else
1006    {
1007  114 annotations[index++] = parseAnnotation(token, graphStyle);
1008  114 emptyColumn = false;
1009    }
1010    }
1011   
1012    }
1013   
1014  8 annotation = new AlignmentAnnotation(label, description,
1015  8 (index == 0) ? null : annotations, 0, 0, graphStyle);
1016   
1017  8 annotation.score = score;
1018  8 if (!overrideAutoAnnot && autoAnnots
1019    .containsKey(autoAnnotsKey(annotation, refSeq, groupRef)))
1020    {
1021    // skip - we've already got an automatic annotation of this type.
1022  0 continue;
1023    }
1024    // otherwise add it!
1025  8 if (refSeq != null)
1026    {
1027   
1028  3 annotation.belowAlignment = false;
1029    // make a copy of refSeq so we can find other matches in the alignment
1030  3 SequenceI referedSeq = refSeq;
1031  3 do
1032    {
1033    // copy before we do any mapping business.
1034    // TODO: verify that undo/redo with 1:many sequence associated
1035    // annotations can be undone correctly
1036  3 AlignmentAnnotation ann = new AlignmentAnnotation(annotation);
1037  3 annotation.createSequenceMapping(referedSeq, refSeqIndex,
1038    false);
1039  3 annotation.adjustForAlignment();
1040  3 referedSeq.addAlignmentAnnotation(annotation);
1041  3 al.addAnnotation(annotation);
1042  3 al.setAnnotationIndex(annotation,
1043    al.getAlignmentAnnotation().length - existingAnnotations
1044    - 1);
1045  3 if (groupRef != null)
1046    {
1047  0 ((Vector) groupRefRows.get(groupRef)).addElement(annotation);
1048    }
1049    // and recover our virgin copy to use again if necessary.
1050  3 annotation = ann;
1051   
1052  ? } while (refSeqId != null && (referedSeq = al.findName(referedSeq,
1053    refSeqId, true)) != null);
1054    }
1055    else
1056    {
1057  5 al.addAnnotation(annotation);
1058  5 al.setAnnotationIndex(annotation,
1059    al.getAlignmentAnnotation().length - existingAnnotations
1060    - 1);
1061  5 if (groupRef != null)
1062    {
1063  0 ((Vector) groupRefRows.get(groupRef)).addElement(annotation);
1064    }
1065    }
1066    // and set modification flag
1067  8 modified = true;
1068    }
1069    // Resolve the groupRefs
1070  9 Hashtable<String, SequenceGroup> groupRefLookup = new Hashtable<>();
1071  9 Enumeration en = groupRefRows.keys();
1072   
1073  9 while (en.hasMoreElements())
1074    {
1075  0 groupRef = (String) en.nextElement();
1076  0 boolean matched = false;
1077    // Resolve group: TODO: add a getGroupByName method to alignments
1078  0 for (SequenceGroup theGroup : al.getGroups())
1079    {
1080  0 if (theGroup.getName().equals(groupRef))
1081    {
1082  0 if (matched)
1083    {
1084    // TODO: specify and implement duplication of alignment annotation
1085    // for multiple group references.
1086  0 jalview.bin.Console.errPrintln(
1087    "Ignoring 1:many group reference mappings for group name '"
1088    + groupRef + "'");
1089    }
1090    else
1091    {
1092  0 matched = true;
1093  0 Vector rowset = (Vector) groupRefRows.get(groupRef);
1094  0 groupRefLookup.put(groupRef, theGroup);
1095  0 if (rowset != null && rowset.size() > 0)
1096    {
1097  0 AlignmentAnnotation alan = null;
1098  0 for (int elm = 0, elmSize = rowset
1099  0 .size(); elm < elmSize; elm++)
1100    {
1101  0 alan = (AlignmentAnnotation) rowset.elementAt(elm);
1102  0 alan.groupRef = theGroup;
1103    }
1104    }
1105    }
1106    }
1107    }
1108  0 ((Vector) groupRefRows.get(groupRef)).removeAllElements();
1109    }
1110    // process any deferred attribute settings for each context
1111  9 for (Object[] _deferred_args : deferredAnnotation_calls)
1112    {
1113  0 if (_deferred_args[0] == GRAPHLINE)
1114    {
1115  0 addLine(al, (StringTokenizer) _deferred_args[1], // st
1116    (SequenceI) _deferred_args[2], // refSeq
1117  0 (_deferred_args[3] == null) ? null
1118    : groupRefLookup.get(_deferred_args[3]) // the
1119    // reference
1120    // group, or
1121    // null
1122    );
1123    }
1124    }
1125   
1126    // finally, combine all the annotation rows within each context.
1127    /**
1128    * number of combine statements in this annotation file. Used to create
1129    * new groups for combined annotation graphs without disturbing existing
1130    * ones
1131    */
1132  9 int combinecount = 0;
1133  9 for (Object[] _combine_args : combineAnnotation_calls)
1134    {
1135  0 combineAnnotations(al, ++combinecount,
1136    (StringTokenizer) _combine_args[0], // st
1137    (SequenceI) _combine_args[1], // refSeq
1138  0 (_combine_args[2] == null) ? null
1139    : groupRefLookup.get(_combine_args[2]) // the reference
1140    // group,
1141    // or null
1142    );
1143    }
1144    }
1145  9 return modified;
1146    }
1147   
 
1148  0 toggle private void parseHideCols(HiddenColumns hidden, String nextToken)
1149    {
1150  0 StringTokenizer inval = new StringTokenizer(nextToken, ",");
1151  0 while (inval.hasMoreTokens())
1152    {
1153  0 String range = inval.nextToken().trim();
1154  0 int from, to = range.indexOf("-");
1155  0 if (to == -1)
1156    {
1157  0 from = to = Integer.parseInt(range);
1158  0 if (from >= 0)
1159    {
1160  0 hidden.hideColumns(from, to);
1161    }
1162    }
1163    else
1164    {
1165  0 from = Integer.parseInt(range.substring(0, to));
1166  0 if (to < range.length() - 1)
1167    {
1168  0 to = Integer.parseInt(range.substring(to + 1));
1169    }
1170    else
1171    {
1172  0 to = from;
1173    }
1174  0 if (from > 0 && to >= from)
1175    {
1176  0 hidden.hideColumns(from, to);
1177    }
1178    }
1179    }
1180    }
1181   
 
1182  12 toggle private Object autoAnnotsKey(AlignmentAnnotation annotation,
1183    SequenceI refSeq, String groupRef)
1184    {
1185  12 return annotation.graph + "\t" + annotation.label + "\t"
1186    + annotation.description + "\t"
1187  12 + (refSeq != null ? refSeq.getDisplayId(true) : "");
1188    }
1189   
 
1190  114 toggle Annotation parseAnnotation(String string, int graphStyle)
1191    {
1192    // don't do the glyph test if we don't want secondary structure
1193  114 boolean hasSymbols = (graphStyle == AlignmentAnnotation.NO_GRAPH);
1194  114 String desc = null, displayChar = null;
1195  114 char ss = ' '; // secondaryStructure
1196  114 float value = 0;
1197  114 boolean parsedValue = false, dcset = false;
1198   
1199    // find colour here
1200  114 Color colour = null;
1201  114 int i = string.indexOf("[");
1202  114 int j = string.indexOf("]");
1203  114 if (i > -1 && j > -1)
1204    {
1205  0 colour = ColorUtils.parseColourString(string.substring(i + 1, j));
1206  0 if (i > 0 && string.charAt(i - 1) == ',')
1207    {
1208    // clip the preceding comma as well
1209  0 i--;
1210    }
1211  0 string = string.substring(0, i) + string.substring(j + 1);
1212    }
1213   
1214  114 StringTokenizer st = new StringTokenizer(string, ",", true);
1215  114 String token;
1216  114 boolean seenContent = false;
1217  114 int pass = 0;
1218  368 while (st.hasMoreTokens())
1219    {
1220  254 pass++;
1221  254 token = st.nextToken().trim();
1222  254 if (token.equals(","))
1223    {
1224  74 if (!seenContent && parsedValue && !dcset)
1225    {
1226    // allow the value below the bar/line to be empty
1227  0 dcset = true;
1228  0 displayChar = " ";
1229    }
1230  74 seenContent = false;
1231  74 continue;
1232    }
1233    else
1234    {
1235  180 seenContent = true;
1236    }
1237   
1238  180 if (!parsedValue)
1239    {
1240  180 try
1241    {
1242  180 displayChar = token;
1243    // foo
1244  180 value = Float.valueOf(token).floatValue();
1245  0 parsedValue = true;
1246  0 continue;
1247    } catch (NumberFormatException ex)
1248    {
1249    }
1250    }
1251    else
1252    {
1253  0 if (token.length() == 1)
1254    {
1255  0 displayChar = token;
1256    }
1257    }
1258  180 if (hasSymbols && (token.length() == 1
1259    && "()<>[]{}AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
1260    .contains(token)))
1261    {
1262    // Either this character represents a helix or sheet
1263    // or an integer which can be displayed
1264  160 ss = token.charAt(0);
1265  160 if (displayChar.equals(token.substring(0, 1)))
1266    {
1267  160 displayChar = "";
1268    }
1269    }
1270  20 else if (desc == null || (parsedValue && pass > 2))
1271    {
1272  12 desc = token;
1273    }
1274   
1275    }
1276    // if (!dcset && string.charAt(string.length() - 1) == ',')
1277    // {
1278    // displayChar = " "; // empty display char symbol.
1279    // }
1280  114 if (displayChar != null && desc != null && desc.length() == 1)
1281    {
1282  12 if (displayChar.length() > 1)
1283    {
1284    // switch desc and displayChar - legacy support
1285  0 String tmp = displayChar;
1286  0 displayChar = desc;
1287  0 desc = tmp;
1288    }
1289    else
1290    {
1291  12 if (displayChar.equals(desc))
1292    {
1293    // duplicate label - hangover from the 'robust parser' above
1294  12 desc = null;
1295    }
1296    }
1297    }
1298  114 Annotation anot = new Annotation(displayChar, desc, ss, value);
1299   
1300  114 anot.colour = colour;
1301   
1302  114 return anot;
1303    }
1304   
 
1305  0 toggle void colourAnnotations(AlignmentI al, String label, String colour)
1306    {
1307  0 Color awtColour = ColorUtils.parseColourString(colour);
1308  0 Annotation[] annotations;
1309  0 for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
1310    {
1311  0 if (al.getAlignmentAnnotation()[i].label.equalsIgnoreCase(label))
1312    {
1313  0 annotations = al.getAlignmentAnnotation()[i].annotations;
1314  0 for (int j = 0; j < annotations.length; j++)
1315    {
1316  0 if (annotations[j] != null)
1317    {
1318  0 annotations[j].colour = awtColour;
1319    }
1320    }
1321    }
1322    }
1323    }
1324   
 
1325  0 toggle void combineAnnotations(AlignmentI al, int combineCount,
1326    StringTokenizer st, SequenceI seqRef, SequenceGroup groupRef)
1327    {
1328  0 String group = st.nextToken();
1329    // First make sure we are not overwriting the graphIndex
1330  0 int graphGroup = 0;
1331  0 if (al.getAlignmentAnnotation() != null)
1332    {
1333  0 for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
1334    {
1335  0 AlignmentAnnotation aa = al.getAlignmentAnnotation()[i];
1336   
1337  0 if (aa.graphGroup > graphGroup)
1338    {
1339    // try to number graphGroups in order of occurence.
1340  0 graphGroup = aa.graphGroup + 1;
1341    }
1342  0 if (aa.sequenceRef == seqRef && aa.groupRef == groupRef
1343    && aa.label.equalsIgnoreCase(group))
1344    {
1345  0 if (aa.graphGroup > -1)
1346    {
1347  0 graphGroup = aa.graphGroup;
1348    }
1349    else
1350    {
1351  0 if (graphGroup <= combineCount)
1352    {
1353  0 graphGroup = combineCount + 1;
1354    }
1355  0 aa.graphGroup = graphGroup;
1356    }
1357  0 break;
1358    }
1359    }
1360   
1361    // Now update groups
1362  0 while (st.hasMoreTokens())
1363    {
1364  0 group = st.nextToken();
1365  0 for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
1366    {
1367  0 AlignmentAnnotation aa = al.getAlignmentAnnotation()[i];
1368  0 if (aa.sequenceRef == seqRef && aa.groupRef == groupRef
1369    && aa.label.equalsIgnoreCase(group))
1370    {
1371  0 aa.graphGroup = graphGroup;
1372  0 break;
1373    }
1374    }
1375    }
1376    }
1377    else
1378    {
1379  0 jalview.bin.Console.errPrintln(
1380    "Couldn't combine annotations. None are added to alignment yet!");
1381    }
1382    }
1383   
 
1384  0 toggle void addLine(AlignmentI al, StringTokenizer st, SequenceI seqRef,
1385    SequenceGroup groupRef)
1386    {
1387  0 String group = st.nextToken();
1388  0 AlignmentAnnotation[] alannot = al.getAlignmentAnnotation();
1389  0 String nextToken = st.nextToken();
1390  0 float value = 0f;
1391  0 try
1392    {
1393  0 value = Float.valueOf(nextToken);
1394    } catch (NumberFormatException e)
1395    {
1396  0 jalview.bin.Console.errPrintln("line " + nlinesread + ": Threshold '"
1397    + nextToken + "' invalid, setting to zero");
1398    }
1399  0 String label = st.hasMoreTokens() ? st.nextToken() : null;
1400  0 Color colour = null;
1401  0 if (st.hasMoreTokens())
1402    {
1403  0 colour = ColorUtils.parseColourString(st.nextToken());
1404    }
1405  0 if (alannot != null)
1406    {
1407  0 for (int i = 0; i < alannot.length; i++)
1408    {
1409  0 if (alannot[i].label.equalsIgnoreCase(group)
1410    && (seqRef == null || alannot[i].sequenceRef == seqRef)
1411    && (groupRef == null || alannot[i].groupRef == groupRef))
1412    {
1413  0 alannot[i].setThreshold(new GraphLine(value, label, colour));
1414    }
1415    }
1416    }
1417    }
1418   
 
1419  5 toggle void addGroup(AlignmentI al, StringTokenizer st)
1420    {
1421  5 SequenceGroup sg = new SequenceGroup();
1422  5 sg.setName(st.nextToken());
1423  5 String rng = "";
1424  5 try
1425    {
1426  5 rng = st.nextToken();
1427  5 if (rng.length() > 0 && !rng.startsWith("*"))
1428    {
1429  5 sg.setStartRes(Integer.parseInt(rng) - 1);
1430    }
1431    else
1432    {
1433  0 sg.setStartRes(0);
1434    }
1435  5 rng = st.nextToken();
1436  5 if (rng.length() > 0 && !rng.startsWith("*"))
1437    {
1438  5 sg.setEndRes(Integer.parseInt(rng) - 1);
1439    }
1440    else
1441    {
1442  0 sg.setEndRes(al.getWidth() - 1);
1443    }
1444    } catch (Exception e)
1445    {
1446  0 jalview.bin.Console.errPrintln(
1447    "Couldn't parse Group Start or End Field as '*' or a valid column or sequence index: '"
1448    + rng + "' - assuming alignment width for group.");
1449    // assume group is full width
1450  0 sg.setStartRes(0);
1451  0 sg.setEndRes(al.getWidth() - 1);
1452    }
1453   
1454  5 String index = st.nextToken();
1455  5 if (index.equals("-1"))
1456    {
1457  38 while (st.hasMoreElements())
1458    {
1459  33 sg.addSequence(al.findName(st.nextToken()), false);
1460    }
1461    }
1462    else
1463    {
1464  0 StringTokenizer st2 = new StringTokenizer(index, ",");
1465   
1466  0 while (st2.hasMoreTokens())
1467    {
1468  0 String tmp = st2.nextToken();
1469  0 if (tmp.equals("*"))
1470    {
1471  0 for (int i = 0; i < al.getHeight(); i++)
1472    {
1473  0 sg.addSequence(al.getSequenceAt(i), false);
1474    }
1475    }
1476  0 else if (tmp.indexOf("-") >= 0)
1477    {
1478  0 StringTokenizer st3 = new StringTokenizer(tmp, "-");
1479   
1480  0 int start = (Integer.parseInt(st3.nextToken()));
1481  0 int end = (Integer.parseInt(st3.nextToken()));
1482   
1483  0 if (end > start)
1484    {
1485  0 for (int i = start; i <= end; i++)
1486    {
1487  0 sg.addSequence(al.getSequenceAt(i - 1), false);
1488    }
1489    }
1490    }
1491    else
1492    {
1493  0 sg.addSequence(al.getSequenceAt(Integer.parseInt(tmp) - 1),
1494    false);
1495    }
1496    }
1497    }
1498   
1499  5 if (refSeq != null)
1500    {
1501  0 sg.setStartRes(refSeq.findIndex(sg.getStartRes() + 1) - 1);
1502  0 sg.setEndRes(refSeq.findIndex(sg.getEndRes() + 1) - 1);
1503  0 sg.setSeqrep(refSeq);
1504    }
1505   
1506  5 if (sg.getSize() > 0)
1507    {
1508  5 al.addGroup(sg);
1509    }
1510    }
1511   
 
1512  8 toggle void addRowProperties(AlignmentI al, StringTokenizer st)
1513    {
1514  8 String label = st.nextToken(), keyValue, key, value;
1515  8 boolean scaletofit = false, centerlab = false, showalllabs = false;
1516  32 while (st.hasMoreTokens())
1517    {
1518  24 keyValue = st.nextToken();
1519  24 key = keyValue.substring(0, keyValue.indexOf("="));
1520  24 value = keyValue.substring(keyValue.indexOf("=") + 1);
1521  24 if (key.equalsIgnoreCase("scaletofit"))
1522    {
1523  8 scaletofit = Boolean.valueOf(value).booleanValue();
1524    }
1525  24 if (key.equalsIgnoreCase("showalllabs"))
1526    {
1527  8 showalllabs = Boolean.valueOf(value).booleanValue();
1528    }
1529  24 if (key.equalsIgnoreCase("centrelabs"))
1530    {
1531  8 centerlab = Boolean.valueOf(value).booleanValue();
1532    }
1533  24 AlignmentAnnotation[] alr = al.getAlignmentAnnotation();
1534  24 if (alr != null)
1535    {
1536  48 for (int i = 0; i < alr.length; i++)
1537    {
1538  24 if (alr[i].label.equalsIgnoreCase(label))
1539    {
1540  24 alr[i].centreColLabels = centerlab;
1541  24 alr[i].scaleColLabel = scaletofit;
1542  24 alr[i].showAllColLabels = showalllabs;
1543    }
1544    }
1545    }
1546    }
1547    }
1548   
 
1549  5 toggle void addProperties(AlignmentI al, StringTokenizer st)
1550    {
1551   
1552    // So far we have only added groups to the annotationHash,
1553    // the idea is in the future properties can be added to
1554    // alignments, other annotations etc
1555  5 if (al.getGroups() == null)
1556    {
1557  0 return;
1558    }
1559   
1560  5 String name = st.nextToken();
1561   
1562  5 Map<String, String> properties = new HashMap<>();
1563  40 while (st.hasMoreTokens())
1564    {
1565  35 String keyValue = st.nextToken();
1566  35 String key = keyValue.substring(0, keyValue.indexOf("="));
1567  35 String value = keyValue.substring(keyValue.indexOf("=") + 1);
1568  35 properties.put(key, value);
1569    }
1570   
1571  5 for (SequenceGroup sg : al.getGroups())
1572    {
1573  15 if (sg.getName().equals(name))
1574    {
1575  5 addProperties(sg, properties, al);
1576    }
1577    }
1578    }
1579   
1580    /**
1581    * Helper method that applies any specified properties to a SequenceGroup
1582    *
1583    * @param sg
1584    * @param properties
1585    * @param al
1586    */
 
1587  5 toggle private void addProperties(SequenceGroup sg,
1588    Map<String, String> properties, AlignmentI al)
1589    {
1590  5 ColourSchemeI def = sg.getColourScheme();
1591  5 for (String key : properties.keySet())
1592    {
1593  35 String value = properties.get(key);
1594  35 if (key.equalsIgnoreCase("description"))
1595    {
1596  0 sg.setDescription(value);
1597    }
1598  35 else if (key.equalsIgnoreCase("colour"))
1599    {
1600    // TODO need to notify colourscheme of view reference once it is
1601    // available
1602  0 sg.cs.setColourScheme(
1603    ColourSchemeProperty.getColourScheme(null, al, value));
1604    }
1605  35 else if (key.equalsIgnoreCase("pidThreshold"))
1606    {
1607  0 sg.cs.setThreshold(Integer.parseInt(value), true);
1608   
1609    }
1610  35 else if (key
1611    .equalsIgnoreCase("secondaryStructureConservationThreshold"))
1612    {
1613  0 sg.cs.setConsensusSecondaryStructureThreshold(
1614    Integer.parseInt(value));
1615  0 sg.cs.setConsensusSecondaryStructureColouring(true);
1616   
1617    }
1618  35 else if (key.equalsIgnoreCase("consThreshold"))
1619    {
1620  0 sg.cs.setConservationInc(Integer.parseInt(value));
1621  0 Conservation c = new Conservation("Group", sg.getSequences(null),
1622    sg.getStartRes(), sg.getEndRes() + 1);
1623   
1624  0 c.calculate();
1625  0 c.verdict(false, 25); // TODO: refer to conservation percent threshold
1626   
1627  0 sg.cs.setConservation(c);
1628   
1629    }
1630  35 else if (key.equalsIgnoreCase("outlineColour"))
1631    {
1632  5 sg.setOutlineColour(ColorUtils.parseColourString(value));
1633    }
1634  30 else if (key.equalsIgnoreCase("displayBoxes"))
1635    {
1636  5 sg.setDisplayBoxes(Boolean.valueOf(value).booleanValue());
1637    }
1638  25 else if (key.equalsIgnoreCase("showUnconserved"))
1639    {
1640  5 sg.setShowNonconserved(Boolean.valueOf(value).booleanValue());
1641    }
1642  20 else if (key.equalsIgnoreCase("displayText"))
1643    {
1644  5 sg.setDisplayText(Boolean.valueOf(value).booleanValue());
1645    }
1646  15 else if (key.equalsIgnoreCase("colourText"))
1647    {
1648  5 sg.setColourText(Boolean.valueOf(value).booleanValue());
1649    }
1650  10 else if (key.equalsIgnoreCase("textCol1"))
1651    {
1652  5 sg.textColour = ColorUtils.parseColourString(value);
1653    }
1654  5 else if (key.equalsIgnoreCase("textCol2"))
1655    {
1656  5 sg.textColour2 = ColorUtils.parseColourString(value);
1657    }
1658  0 else if (key.equalsIgnoreCase("textColThreshold"))
1659    {
1660  0 sg.thresholdTextColour = Integer.parseInt(value);
1661    }
1662  0 else if (key.equalsIgnoreCase("idColour"))
1663    {
1664  0 Color idColour = ColorUtils.parseColourString(value);
1665  0 sg.setIdColour(idColour == null ? Color.black : idColour);
1666    }
1667  0 else if (key.equalsIgnoreCase("hide"))
1668    {
1669    // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847
1670  0 sg.setHidereps(true);
1671    }
1672  0 else if (key.equalsIgnoreCase("hidecols"))
1673    {
1674    // see bug https://mantis.lifesci.dundee.ac.uk/view.php?id=25847
1675  0 sg.setHideCols(true);
1676    }
1677  35 sg.recalcConservation();
1678    }
1679   
1680  5 if (sg.getColourScheme() == null)
1681    {
1682  5 sg.setColourScheme(def);
1683    }
1684    }
1685   
 
1686  0 toggle void setBelowAlignment(AlignmentI al, StringTokenizer st)
1687    {
1688  0 String token;
1689  0 AlignmentAnnotation aa, ala[] = al.getAlignmentAnnotation();
1690  0 if (ala == null)
1691    {
1692  0 System.err.print(
1693    "Warning - no annotation to set below for sequence associated annotation:");
1694    }
1695  0 while (st.hasMoreTokens())
1696    {
1697  0 token = st.nextToken();
1698  0 if (ala == null)
1699    {
1700  0 System.err.print(" " + token);
1701    }
1702    else
1703    {
1704  0 for (int i = 0; i < al.getAlignmentAnnotation().length; i++)
1705    {
1706  0 aa = al.getAlignmentAnnotation()[i];
1707  0 if (aa.sequenceRef == refSeq && aa.label.equals(token))
1708    {
1709  0 aa.belowAlignment = true;
1710    }
1711    }
1712    }
1713    }
1714  0 if (ala == null)
1715    {
1716  0 System.err.print("\n");
1717    }
1718    }
1719   
 
1720  5 toggle void addAlignmentDetails(AlignmentI al, StringTokenizer st)
1721    {
1722  5 String keyValue, key, value;
1723  15 while (st.hasMoreTokens())
1724    {
1725  10 keyValue = st.nextToken();
1726  10 key = keyValue.substring(0, keyValue.indexOf("="));
1727  10 value = keyValue.substring(keyValue.indexOf("=") + 1);
1728  10 al.setProperty(key, value);
1729    }
1730    }
1731   
1732    /**
1733    * Write annotations as a CSV file of the form 'label, value, value, ...' for
1734    * each row.
1735    *
1736    * @param annotations
1737    * @return CSV file as a string.
1738    */
 
1739  0 toggle public String printCSVAnnotations(AlignmentAnnotation[] annotations)
1740    {
1741  0 if (annotations == null)
1742    {
1743  0 return "";
1744    }
1745  0 StringBuffer sp = new StringBuffer();
1746  0 for (int i = 0; i < annotations.length; i++)
1747    {
1748  0 String atos = annotations[i].toString();
1749  0 int p = 0;
1750  0 do
1751    {
1752  0 int cp = atos.indexOf("\n", p);
1753  0 sp.append(annotations[i].label);
1754  0 sp.append(",");
1755  0 if (cp > p)
1756    {
1757  0 sp.append(atos.substring(p, cp + 1));
1758    }
1759    else
1760    {
1761  0 sp.append(atos.substring(p));
1762  0 sp.append(newline);
1763    }
1764  0 p = cp + 1;
1765  0 } while (p > 0);
1766    }
1767  0 return sp.toString();
1768    }
1769   
 
1770  0 toggle public String printAnnotationsForView(AlignViewportI viewport)
1771    {
1772  0 return printAnnotations(
1773  0 viewport.isShowAnnotation()
1774    ? viewport.getAlignment().getAlignmentAnnotation()
1775    : null,
1776    viewport.getAlignment().getGroups(),
1777    viewport.getAlignment().getProperties(),
1778    viewport.getAlignment().getHiddenColumns(),
1779    viewport.getAlignment(), null);
1780    }
1781   
 
1782  0 toggle public String printAnnotationsForAlignment(AlignmentI al)
1783    {
1784  0 return printAnnotations(al.getAlignmentAnnotation(), al.getGroups(),
1785    al.getProperties(), null, al, null);
1786    }
1787    }