Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 GMT
  2. Package jalview.datamodel

File AlignmentAnnotation.java

 

Coverage histogram

../../img/srcFileCovDistChart8.png
20% of files have more coverage

Code metrics

302
499
79
2
1,950
1,295
341
0.68
6.32
39.5
4.32

Classes

Class Line # Actions
AlignmentAnnotation 46 488 324
0.800703480.1%
AlignmentAnnotation.AnnotCharSequence 580 11 17
0.925925992.6%
 

Contributing tests

This file is covered by 405 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.datamodel;
22   
23    import java.awt.Color;
24    import java.util.ArrayList;
25    import java.util.Arrays;
26    import java.util.Collection;
27    import java.util.Collections;
28    import java.util.HashMap;
29    import java.util.Iterator;
30    import java.util.List;
31    import java.util.Locale;
32    import java.util.Map;
33    import java.util.Map.Entry;
34   
35    import jalview.analysis.Rna;
36    import jalview.analysis.SecStrConsensus.SimpleBP;
37    import jalview.analysis.WUSSParseException;
38    import jalview.structure.StructureImportSettings;
39   
40    /**
41    * DOCUMENT ME!
42    *
43    * @author $author$
44    * @version $Revision$
45    */
 
46    public class AlignmentAnnotation
47    {
48   
49    private static final String ANNOTATION_ID_PREFIX = "ann";
50   
51    // The property key for annotation property values like
52    // PDB id, chain code, etc
53    public static final String ANNOTATION_DETAILS = "ANNOTATION_DETAILS";
54   
55    /*
56    * Identifers for different types of profile data
57    */
58    public static final int SEQUENCE_PROFILE = 0;
59   
60    public static final int STRUCTURE_PROFILE = 1;
61   
62    public static final int CDNA_PROFILE = 2;
63   
64    private static long counter = 0;
65   
66    private long noOfSequencesIncluded = -1;
67   
68    private long noOfTracksIncluded = -1;
69   
70   
71   
72    /**
73    * If true, this annotations is calculated every edit, eg consensus, quality
74    * or conservation graphs
75    */
76    public boolean autoCalculated = false;
77   
78    /**
79    * unique ID for this annotation, used to match up the same annotation row
80    * shown in multiple views and alignments
81    */
82    public String annotationId;
83   
84    /**
85    * the sequence this annotation is associated with (or null)
86    */
87    public SequenceI sequenceRef;
88   
89    /** label shown in dropdown menus and in the annotation label area */
90    public String label;
91   
92    /** longer description text shown as a tooltip */
93    public String description;
94   
95    /** Array of annotations placed in the current coordinate system */
96    public Annotation[] annotations;
97   
98    public List<SimpleBP> bps = null;
99   
100    /**
101    * RNA secondary structure contact positions
102    */
103    public SequenceFeature[] _rnasecstr = null;
104   
105    /**
106    * position of annotation resulting in invalid WUSS parsing or -1. -2 means
107    * there was no RNA structure in this annotation
108    */
109    private long invalidrnastruc = -2;
110   
111    /**
112    * the type of temperature factor plot (if it is one)
113    */
114    private StructureImportSettings.TFType tfType = StructureImportSettings.TFType.DEFAULT;
115   
116    /**
117    * stores the colour of the group to which the annotation belongs.
118    * The label of the annotation is highlighted with this colour.
119    */
120    private Color annotationGroupColour = null;
121   
 
122  198 toggle public void setTFType(StructureImportSettings.TFType t)
123    {
124  198 tfType = t;
125    }
126   
 
127  0 toggle public StructureImportSettings.TFType getTFType()
128    {
129  0 return tfType;
130    }
131   
132    private double bitScore;
133   
134    private double eValue;
135   
136    /**
137    * Updates the _rnasecstr field Determines the positions that base pair and
138    * the positions of helices based on secondary structure from a Stockholm file
139    *
140    * @param rnaAnnotation
141    */
 
142  1380 toggle private void _updateRnaSecStr(CharSequence rnaAnnotation)
143    {
144  1380 try
145    {
146  1380 _rnasecstr = Rna.getHelixMap(rnaAnnotation);
147  980 invalidrnastruc = -1;
148    } catch (WUSSParseException px)
149    {
150    // DEBUG jalview.bin.Console.outPrintln(px);
151  400 invalidrnastruc = px.getProblemPos();
152    }
153  1380 if (invalidrnastruc > -1)
154    {
155  400 return;
156    }
157   
158  980 if (_rnasecstr != null && _rnasecstr.length > 0)
159    {
160    // show all the RNA secondary structure annotation symbols.
161  980 isrna = true;
162  980 showAllColLabels = true;
163  980 scaleColLabel = true;
164  980 _markRnaHelices();
165    }
166    // jalview.bin.Console.outPrintln("featuregroup " +
167    // _rnasecstr[0].getFeatureGroup());
168   
169    }
170   
 
171  980 toggle private void _markRnaHelices()
172    {
173  980 int mxval = 0;
174    // Figure out number of helices
175    // Length of rnasecstr is the number of pairs of positions that base pair
176    // with each other in the secondary structure
177  19837 for (int x = 0; x < _rnasecstr.length; x++)
178    {
179   
180    /*
181    * jalview.bin.Console.outPrintln(this.annotation._rnasecstr[x] + " Begin" +
182    * this.annotation._rnasecstr[x].getBegin());
183    */
184    // jalview.bin.Console.outPrintln(this.annotation._rnasecstr[x].getFeatureGroup());
185  18857 int val = 0;
186  18857 try
187    {
188  18857 val = Integer.valueOf(_rnasecstr[x].getFeatureGroup());
189  18857 if (mxval < val)
190    {
191  311 mxval = val;
192    }
193    } catch (NumberFormatException q)
194    {
195    }
196  18857 ;
197   
198  18857 annotations[_rnasecstr[x].getBegin()].value = val;
199  18857 annotations[_rnasecstr[x].getEnd()].value = val;
200   
201    // annotations[_rnasecstr[x].getBegin()].displayCharacter = "" + val;
202    // annotations[_rnasecstr[x].getEnd()].displayCharacter = "" + val;
203    }
204  980 setScore(mxval);
205    }
206   
207   
 
208  3317 toggle public Color getAnnotationGroupColour()
209    {
210  3317 return annotationGroupColour;
211    }
212   
 
213  442 toggle public void setAnnotationGroupColour(Color annotationGroupColour)
214    {
215  442 this.annotationGroupColour = annotationGroupColour;
216    }
217   
218    /**
219    * Get the RNA Secondary Structure SequenceFeature Array if present
220    */
 
221  12 toggle public SequenceFeature[] getRnaSecondaryStructure()
222    {
223  12 return this._rnasecstr;
224    }
225   
226    /**
227    * Check the RNA Secondary Structure is equivalent to one in given
228    * AlignmentAnnotation param
229    */
 
230  4 toggle public boolean rnaSecondaryStructureEquivalent(AlignmentAnnotation that)
231    {
232  4 return rnaSecondaryStructureEquivalent(that, true);
233    }
234   
 
235  4 toggle public boolean rnaSecondaryStructureEquivalent(AlignmentAnnotation that,
236    boolean compareType)
237    {
238  4 SequenceFeature[] thisSfArray = this.getRnaSecondaryStructure();
239  4 SequenceFeature[] thatSfArray = that.getRnaSecondaryStructure();
240  4 if (thisSfArray == null || thatSfArray == null)
241    {
242  0 return thisSfArray == null && thatSfArray == null;
243    }
244  4 if (thisSfArray.length != thatSfArray.length)
245    {
246  1 return false;
247    }
248  3 Arrays.sort(thisSfArray, new SFSortByEnd()); // probably already sorted
249    // like this
250  3 Arrays.sort(thatSfArray, new SFSortByEnd()); // probably already sorted
251    // like this
252  15 for (int i = 0; i < thisSfArray.length; i++)
253    {
254  13 SequenceFeature thisSf = thisSfArray[i];
255  13 SequenceFeature thatSf = thatSfArray[i];
256  13 if (compareType)
257    {
258  13 if (thisSf.getType() == null || thatSf.getType() == null)
259    {
260  0 if (thisSf.getType() == null && thatSf.getType() == null)
261    {
262  0 continue;
263    }
264    else
265    {
266  0 return false;
267    }
268    }
269  13 if (!thisSf.getType().equals(thatSf.getType()))
270    {
271  0 return false;
272    }
273    }
274  13 if (!(thisSf.getBegin() == thatSf.getBegin()
275    && thisSf.getEnd() == thatSf.getEnd()))
276    {
277  1 return false;
278    }
279    }
280  2 return true;
281   
282    }
283   
284    /**
285    * map of positions in the associated annotation
286    */
287    private Map<Integer, Annotation> sequenceMapping;
288   
289    /**
290    * lower range for quantitative data
291    */
292    public float graphMin;
293   
294    /**
295    * Upper range for quantitative data
296    */
297    public float graphMax;
298   
299    /**
300    * Score associated with label and description.
301    */
302    public double score = Double.NaN;
303   
304    /**
305    * flag indicating if annotation has a score.
306    */
307    public boolean hasScore = false;
308   
309    public GraphLine threshold;
310   
311    // Graphical hints and tips
312   
313    /** Can this row be edited by the user ? */
314    public boolean editable = false;
315   
316    /** Indicates if annotation has a graphical symbol track */
317    public boolean hasIcons; //
318   
319    /** Indicates if annotation has a text character label */
320    public boolean hasText;
321   
322    /** is the row visible */
323    public boolean visible = true;
324   
325    /**
326    * is there data for this annotation row to display ? if not then hide it!
327    * For rows that are only shown when data is present (default true)
328    */
329    public boolean hasData=true;
330   
331   
332   
333    public int graphGroup = -1;
334   
335    /** Displayed height of row in pixels */
336    public int height = 0;
337   
338    public int graph = 0;
339   
340    public int graphHeight = 40;
341   
342    public boolean padGaps = false;
343   
344    public static final int NO_GRAPH = 0;
345   
346    public static final int BAR_GRAPH = 1;
347   
348    public static final int LINE_GRAPH = 2;
349   
350    public static final int CONTACT_MAP = 4;
351   
352    /**
353    * property that when set to non-empty string disables display of column
354    * groups defined on the contact matrix
355    */
356    public static final String CONTACT_MAP_NOGROUPS = "CMNOGRPS";
357   
358    public boolean belowAlignment = true;
359   
360    public SequenceGroup groupRef = null;
361   
362    /**
363    * display every column label, even if there is a row of identical labels
364    */
365    public boolean showAllColLabels = false;
366   
367    /**
368    * scale the column label to fit within the alignment column.
369    */
370    public boolean scaleColLabel = false;
371   
372    /**
373    * centre the column labels relative to the alignment column
374    */
375    public boolean centreColLabels = false;
376   
377    private boolean isrna;
378   
 
379  260 toggle public static int getGraphValueFromString(String string)
380    {
381  260 if (string.equalsIgnoreCase("BAR_GRAPH"))
382    {
383  32 return BAR_GRAPH;
384    }
385  228 else if (string.equalsIgnoreCase("LINE_GRAPH"))
386    {
387  171 return LINE_GRAPH;
388    }
389    else
390    {
391  57 return NO_GRAPH;
392    }
393    }
394   
395    /**
396    * Creates a new AlignmentAnnotation object.
397    *
398    * @param label
399    * short label shown under sequence labels
400    * @param description
401    * text displayed on mouseover
402    * @param annotations
403    * set of positional annotation elements
404    */
 
405  36859 toggle public AlignmentAnnotation(String label, String description,
406    Annotation[] annotations)
407    {
408  36859 setAnnotationId();
409    // always editable?
410  36859 editable = true;
411  36859 this.label = label;
412  36859 this.description = description;
413  36859 this.annotations = annotations;
414   
415  36859 validateRangeAndDisplay();
416    }
417   
418    /**
419    * Checks if annotation labels represent secondary structures
420    *
421    */
 
422  8539 toggle void areLabelsSecondaryStructure()
423    {
424  8539 boolean nonSSLabel = false;
425  8539 isrna = false;
426  8539 StringBuffer rnastring = new StringBuffer();
427   
428  8539 char firstChar = 0;
429  988540 for (int i = 0; i < annotations.length; i++)
430    {
431    // DEBUG jalview.bin.Console.outPrintln(i + ": " + annotations[i]);
432  980001 if (annotations[i] == null)
433    {
434  311324 continue;
435    }
436  668677 if (annotations[i].secondaryStructure == 'H'
437    || annotations[i].secondaryStructure == 'E')
438    {
439    // DEBUG jalview.bin.Console.outPrintln( "/H|E/ '" +
440    // annotations[i].secondaryStructure + "'");
441  53967 hasIcons |= true;
442    }
443    else
444    // Check for RNA secondary structure
445    {
446    // DEBUG jalview.bin.Console.outPrintln( "/else/ '" +
447    // annotations[i].secondaryStructure + "'");
448    // TODO: 2.8.2 should this ss symbol validation check be a function in
449    // RNA/ResidueProperties ?
450    // allow for DSSP extended code:
451    // https://www.wikidoc.org/index.php/Secondary_structure#The_DSSP_code
452    // GHITEBS as well as C and X (for missing?)
453  614710 if (annotations[i].secondaryStructure == '('
454    || annotations[i].secondaryStructure == '['
455    || annotations[i].secondaryStructure == '<'
456    || annotations[i].secondaryStructure == '{'
457    || annotations[i].secondaryStructure == 'A'
458    // || annotations[i].secondaryStructure == 'B'
459    // || annotations[i].secondaryStructure == 'C'
460    || annotations[i].secondaryStructure == 'D'
461    // || annotations[i].secondaryStructure == 'E' // ambiguous on
462    // its own -- already checked above
463    || annotations[i].secondaryStructure == 'F'
464    // || annotations[i].secondaryStructure == 'G'
465    // || annotations[i].secondaryStructure == 'H' // ambiguous on
466    // its own -- already checked above
467    // || annotations[i].secondaryStructure == 'I'
468    || annotations[i].secondaryStructure == 'J'
469    || annotations[i].secondaryStructure == 'K'
470    || annotations[i].secondaryStructure == 'L'
471    || annotations[i].secondaryStructure == 'M'
472    || annotations[i].secondaryStructure == 'N'
473    || annotations[i].secondaryStructure == 'O'
474    || annotations[i].secondaryStructure == 'P'
475    || annotations[i].secondaryStructure == 'Q'
476    || annotations[i].secondaryStructure == 'R'
477    // || annotations[i].secondaryStructure == 'S'
478    // || annotations[i].secondaryStructure == 'T'
479    || annotations[i].secondaryStructure == 'U'
480    || annotations[i].secondaryStructure == 'V'
481    || annotations[i].secondaryStructure == 'W'
482    // || annotations[i].secondaryStructure == 'X'
483    || annotations[i].secondaryStructure == 'Y'
484    || annotations[i].secondaryStructure == 'Z')
485    {
486  14582 hasIcons |= true;
487  14582 isrna |= true;
488    }
489    }
490   
491    // jalview.bin.Console.outPrintln("displaychar " +
492    // annotations[i].displayCharacter);
493   
494  668677 if (annotations[i].displayCharacter == null
495    || annotations[i].displayCharacter.length() == 0)
496    {
497  300905 rnastring.append('.');
498  300905 continue;
499    }
500  367772 if (annotations[i].displayCharacter.length() == 1)
501    {
502  313506 firstChar = annotations[i].displayCharacter.charAt(0);
503    // check to see if it looks like a sequence or is secondary structure
504    // labelling.
505  313506 if (annotations[i].secondaryStructure != ' ' && !hasIcons &&
506    // Uncomment to only catch case where
507    // displayCharacter==secondary
508    // Structure
509    // to correctly redisplay SS annotation imported from Stockholm,
510    // exported to JalviewXML and read back in again.
511    // &&
512    // annotations[i].displayCharacter.charAt(0)==annotations[i].secondaryStructure
513    firstChar != ' ' && firstChar != '$' && firstChar != 0xCE
514    && firstChar != '(' && firstChar != '[' && firstChar != '<'
515    && firstChar != '{' && firstChar != 'A' && firstChar != 'B'
516    && firstChar != 'C' && firstChar != 'D' && firstChar != 'E'
517    && firstChar != 'F' && firstChar != 'G' && firstChar != 'H'
518    && firstChar != 'I' && firstChar != 'J' && firstChar != 'K'
519    && firstChar != 'L' && firstChar != 'M' && firstChar != 'N'
520    && firstChar != 'O' && firstChar != 'P' && firstChar != 'Q'
521    && firstChar != 'R' && firstChar != 'S' && firstChar != 'T'
522    && firstChar != 'U' && firstChar != 'V' && firstChar != 'W'
523    && firstChar != 'X' && firstChar != 'Y' && firstChar != 'Z'
524    && firstChar != '-'
525    && firstChar < jalview.schemes.ResidueProperties.aaIndex.length)
526    {
527  4724 if (jalview.schemes.ResidueProperties.aaIndex[firstChar] < 23) // TODO:
528    // parameterise
529    // to
530    // gap
531    // symbol
532    // number
533    {
534  11 nonSSLabel = true;
535    }
536    }
537    }
538    else
539    {
540  54266 rnastring.append(annotations[i].displayCharacter.charAt(1));
541    }
542   
543  367772 if (annotations[i].displayCharacter.length() > 0)
544    {
545  367772 hasText = true;
546    }
547    }
548   
549  8539 if (nonSSLabel)
550    {
551  1 hasIcons = false;
552  12 for (int j = 0; j < annotations.length; j++)
553    {
554  11 if (annotations[j] != null
555    && annotations[j].secondaryStructure != ' ')
556    {
557  11 annotations[j].displayCharacter = String
558    .valueOf(annotations[j].secondaryStructure);
559  11 annotations[j].secondaryStructure = ' ';
560    }
561   
562    }
563    }
564    else
565    {
566  8538 if (isrna)
567    {
568  955 _updateRnaSecStr(new AnnotCharSequence());
569    }
570    }
571    }
572   
573    /**
574    * flyweight access to positions in the alignment annotation row for RNA
575    * processing
576    *
577    * @author jimp
578    *
579    */
 
580    private class AnnotCharSequence implements CharSequence
581    {
582    int offset = 0;
583   
584    int max = 0;
585   
 
586  1385 toggle public AnnotCharSequence()
587    {
588  1385 this(0, annotations.length);
589    }
590   
 
591  1385 toggle AnnotCharSequence(int start, int end)
592    {
593  1385 offset = start;
594  1385 max = end;
595    }
596   
 
597  0 toggle @Override
598    public CharSequence subSequence(int start, int end)
599    {
600  0 return new AnnotCharSequence(offset + start, offset + end);
601    }
602   
 
603  66345 toggle @Override
604    public int length()
605    {
606  66345 return max - offset;
607    }
608   
 
609  65390 toggle @Override
610    public char charAt(int index)
611    {
612  65390 return ((index + offset < 0) || (index + offset) >= max
613    || annotations[index + offset] == null
614    || (annotations[index + offset].secondaryStructure <= ' ')
615    ? ' '
616  27230 : annotations[index + offset].displayCharacter == null
617    || annotations[index
618    + offset].displayCharacter
619    .length() == 0
620    ? annotations[index
621    + offset].secondaryStructure
622    : annotations[index
623    + offset].displayCharacter
624    .charAt(0));
625    }
626   
 
627  430 toggle @Override
628    public String toString()
629    {
630  430 char[] string = new char[max - offset];
631  430 int mx = annotations.length;
632   
633  31623 for (int i = offset; i < mx; i++)
634    {
635  31193 string[i] = (annotations[i] == null
636    || (annotations[i].secondaryStructure <= 32))
637    ? ' '
638  13274 : (annotations[i].displayCharacter == null
639    || annotations[i].displayCharacter
640    .length() == 0
641    ? annotations[i].secondaryStructure
642    : annotations[i].displayCharacter
643    .charAt(0));
644    }
645  430 return new String(string);
646    }
647    };
648   
649    private long _lastrnaannot = -1;
650   
 
651  6303 toggle public String getRNAStruc()
652    {
653  6303 if (isrna)
654    {
655  430 String rnastruc = new AnnotCharSequence().toString();
656  430 if (_lastrnaannot != rnastruc.hashCode())
657    {
658    // ensure rna structure contacts are up to date
659  425 _lastrnaannot = rnastruc.hashCode();
660  425 _updateRnaSecStr(rnastruc);
661    }
662  430 return rnastruc;
663    }
664  5873 return null;
665    }
666   
667    /**
668    * Creates a new AlignmentAnnotation object.
669    *
670    * @param label
671    * DOCUMENT ME!
672    * @param description
673    * DOCUMENT ME!
674    * @param annotations
675    * DOCUMENT ME!
676    * @param min
677    * DOCUMENT ME!
678    * @param max
679    * DOCUMENT ME!
680    * @param winLength
681    * DOCUMENT ME!
682    */
 
683  3948 toggle public AlignmentAnnotation(String label, String description,
684    Annotation[] annotations, float min, float max, int graphType)
685    {
686  3948 setAnnotationId();
687    // graphs are not editable
688  3948 editable = graphType == 0;
689   
690  3948 this.label = label;
691  3948 this.description = description;
692  3948 this.annotations = annotations;
693  3948 graph = graphType;
694  3948 graphMin = min;
695  3948 graphMax = max;
696  3948 validateRangeAndDisplay();
697    }
698   
699    /**
700    * checks graphMin and graphMax, secondary structure symbols, sets graphType
701    * appropriately, sets null labels to the empty string if appropriate.
702    */
 
703  43209 toggle public void validateRangeAndDisplay()
704    {
705   
706  43209 if (annotations == null)
707    {
708  34670 visible = false; // try to prevent renderer from displaying.
709  34670 invalidrnastruc = -1;
710  34670 return; // this is a non-annotation row annotation - ie a sequence score.
711    }
712   
713  8539 int graphType = graph;
714  8539 float min = graphMin;
715  8539 float max = graphMax;
716  8539 boolean drawValues = true;
717  8539 _linecolour = null;
718  8539 if (min == max)
719    {
720  4275 min = 999999999;
721  655850 for (int i = 0; i < annotations.length; i++)
722    {
723  651575 if (annotations[i] == null)
724    {
725  134283 continue;
726    }
727   
728  517292 if (drawValues && annotations[i].displayCharacter != null
729    && annotations[i].displayCharacter.length() > 1)
730    {
731  1280 drawValues = false;
732    }
733   
734  517292 if (annotations[i].value > max)
735    {
736  6456 max = annotations[i].value;
737    }
738   
739  517292 if (annotations[i].value < min)
740    {
741  7976 min = annotations[i].value;
742    }
743  517292 if (_linecolour == null && annotations[i].colour != null)
744    {
745  1379 _linecolour = annotations[i].colour;
746    }
747    }
748    // ensure zero is origin for min/max ranges on only one side of zero
749  4275 if (min > 0)
750    {
751  2206 min = 0;
752    }
753    else
754    {
755  2069 if (max < 0)
756    {
757  0 max = 0;
758    }
759    }
760    }
761   
762  8539 graphMin = min;
763  8539 graphMax = max;
764   
765  8539 areLabelsSecondaryStructure();
766   
767  8539 if (!drawValues && graphType != NO_GRAPH)
768    {
769  28597 for (int i = 0; i < annotations.length; i++)
770    {
771  28416 if (annotations[i] != null)
772    {
773  22147 annotations[i].displayCharacter = "";
774    }
775    }
776    }
777    }
778   
779    /**
780    * Copy constructor creates a new independent annotation row with the same
781    * associated sequenceRef
782    *
783    * @param annotation
784    */
 
785  1132 toggle public AlignmentAnnotation(AlignmentAnnotation annotation)
786    {
787  1132 setAnnotationId();
788  1132 updateAlignmentAnnotationFrom(annotation);
789    }
790   
791    /**
792    * copy attributes and annotation from an existing annotation (used by copy
793    * constructor). This method does not update the unique annotationId
794    *
795    * @param annotation
796    */
 
797  1134 toggle public void updateAlignmentAnnotationFrom(AlignmentAnnotation annotation)
798    {
799  1134 this.label = new String(annotation.label);
800  1134 if (annotation.description != null)
801    {
802  1044 this.description = new String(annotation.description);
803    }
804  1134 this.graphMin = annotation.graphMin;
805  1134 this.graphMax = annotation.graphMax;
806  1134 this.graph = annotation.graph;
807  1134 this.graphHeight = annotation.graphHeight;
808  1134 this.graphGroup = annotation.graphGroup;
809  1134 this.groupRef = annotation.groupRef;
810  1134 this.editable = annotation.editable;
811  1134 this.autoCalculated = annotation.autoCalculated;
812  1134 this.hasIcons = annotation.hasIcons;
813  1134 this.hasText = annotation.hasText;
814  1134 this.height = annotation.height;
815  1134 this.label = annotation.label;
816  1134 this.padGaps = annotation.padGaps;
817  1134 this.visible = annotation.visible;
818  1134 this.hasData = annotation.hasData;
819  1134 this.centreColLabels = annotation.centreColLabels;
820  1134 this.scaleColLabel = annotation.scaleColLabel;
821  1134 this.showAllColLabels = annotation.showAllColLabels;
822  1134 this.calcId = annotation.calcId;
823  1134 this.bitScore = annotation.bitScore;
824  1134 this.eValue = annotation.eValue;
825   
826  1134 if (annotation.properties != null)
827    {
828  1134 properties = new HashMap<>();
829  1134 for (Map.Entry<String, String> val : annotation.properties.entrySet())
830    {
831  708 properties.put(val.getKey(), val.getValue());
832    }
833    }
834  ? if (this.hasScore = annotation.hasScore)
835    {
836  136 this.score = annotation.score;
837    }
838  1134 if (annotation.threshold != null)
839    {
840  0 threshold = new GraphLine(annotation.threshold);
841    }
842  1134 Annotation[] ann = annotation.annotations;
843  1134 if (annotation.annotations != null)
844    {
845  1131 this.annotations = new Annotation[ann.length];
846  130765 for (int i = 0; i < ann.length; i++)
847    {
848  129634 if (ann[i] != null)
849    {
850  90097 annotations[i] = new Annotation(ann[i]);
851  90097 if (_linecolour != null)
852    {
853  0 _linecolour = annotations[i].colour;
854    }
855    }
856    }
857    }
858  1134 if (annotation.sequenceRef != null)
859    {
860  919 this.sequenceRef = annotation.sequenceRef;
861  919 if (annotation.sequenceMapping != null)
862    {
863  917 Integer p = null;
864  917 sequenceMapping = new HashMap<>();
865  917 Iterator<Integer> pos = annotation.sequenceMapping.keySet()
866    .iterator();
867  69974 while (pos.hasNext())
868    {
869    // could optimise this!
870  69057 p = pos.next();
871  69057 Annotation a = annotation.sequenceMapping.get(p);
872  69057 if (a == null)
873    {
874  0 continue;
875    }
876  69057 if (ann != null)
877    {
878  10530877 for (int i = 0; i < ann.length; i++)
879    {
880  10461820 if (ann[i] == a)
881    {
882  69039 sequenceMapping.put(p, annotations[i]);
883    }
884    }
885    }
886    }
887    }
888    else
889    {
890  2 this.sequenceMapping = null;
891    }
892   
893    }
894    // TODO: check if we need to do this: JAL-952
895    // if (this.isrna=annotation.isrna)
896    {
897    // _rnasecstr=new SequenceFeature[annotation._rnasecstr];
898    }
899  1134 validateRangeAndDisplay(); // construct hashcodes, etc.
900    }
901   
902    /**
903    * clip the annotation to the columns given by startRes and endRes (inclusive)
904    * and prune any existing sequenceMapping to just those columns.
905    *
906    * @param startRes
907    * @param endRes
908    */
 
909  129 toggle public void restrict(int startRes, int endRes)
910    {
911  129 if (annotations == null)
912    {
913    // non-positional
914  0 return;
915    }
916  129 if (startRes < 0)
917    {
918  2 startRes = 0;
919    }
920  129 if (startRes >= annotations.length)
921    {
922  5 startRes = annotations.length;
923    }
924  129 if (endRes < 0)
925    {
926  1 endRes = -1;
927    }
928  129 if (endRes >= annotations.length)
929    {
930  111 endRes = annotations.length - 1;
931    }
932  129 Annotation[] temp = new Annotation[endRes - startRes + 1];
933  129 if (startRes < annotations.length)
934    {
935  124 System.arraycopy(annotations, startRes, temp, 0,
936    endRes - startRes + 1);
937    }
938  129 if (sequenceRef != null)
939    {
940    // Clip the mapping, if it exists.
941  117 int spos = sequenceRef.findPosition(startRes);
942  117 int epos = sequenceRef.findPosition(endRes);
943  117 if (sequenceMapping != null)
944    {
945  117 Map<Integer, Annotation> newmapping = new HashMap<>();
946  117 Iterator<Integer> e = sequenceMapping.keySet().iterator();
947  8375 while (e.hasNext())
948    {
949  8258 Integer pos = e.next();
950  8258 if (pos.intValue() >= spos && pos.intValue() <= epos)
951    {
952  8214 newmapping.put(pos, sequenceMapping.get(pos));
953    }
954    }
955  117 sequenceMapping.clear();
956  117 sequenceMapping = newmapping;
957    }
958    }
959  129 annotations = temp;
960    }
961   
962    /**
963    * set the annotation row to be at least length Annotations
964    *
965    * @param length
966    * minimum number of columns required in the annotation row
967    * @return false if the annotation row is greater than length
968    */
 
969  0 toggle public boolean padAnnotation(int length)
970    {
971  0 if (annotations == null)
972    {
973  0 return true; // annotation row is correct - null == not visible and
974    // undefined length
975    }
976  0 if (annotations.length < length)
977    {
978  0 Annotation[] na = new Annotation[length];
979  0 System.arraycopy(annotations, 0, na, 0, annotations.length);
980  0 annotations = na;
981  0 return true;
982    }
983  0 return annotations.length > length;
984   
985    }
986   
987    /**
988    * DOCUMENT ME!
989    *
990    * @return DOCUMENT ME!
991    */
 
992  377 toggle @Override
993    public String toString()
994    {
995  377 if (annotations == null)
996    {
997  207 return "";
998    }
999  170 StringBuilder buffer = new StringBuilder(256);
1000   
1001  383 for (int i = 0; i < annotations.length; i++)
1002    {
1003  213 if (annotations[i] != null)
1004    {
1005  157 if (graph != 0)
1006    {
1007  25 buffer.append(annotations[i].value);
1008    }
1009  132 else if (hasIcons)
1010    {
1011  84 buffer.append(annotations[i].secondaryStructure);
1012    }
1013    else
1014    {
1015  48 buffer.append(annotations[i].displayCharacter);
1016    }
1017    }
1018   
1019  213 buffer.append(", ");
1020    }
1021    // TODO: remove disgusting hack for 'special' treatment of consensus line.
1022  170 if (label.indexOf("Consensus") == 0)
1023    {
1024  10 buffer.append("\n");
1025   
1026  15 for (int i = 0; i < annotations.length; i++)
1027    {
1028  5 if (annotations[i] != null)
1029    {
1030  5 buffer.append(annotations[i].description);
1031    }
1032   
1033  5 buffer.append(", ");
1034    }
1035    }
1036   
1037  170 return buffer.toString();
1038    }
1039   
 
1040  2 toggle public void setThreshold(GraphLine line)
1041    {
1042  2 threshold = line;
1043    }
1044   
 
1045  519 toggle public GraphLine getThreshold()
1046    {
1047  519 return threshold;
1048    }
1049   
1050    /**
1051    * Attach the annotation to seqRef, starting from startRes position. If
1052    * alreadyMapped is true then the indices of the annotation[] array are
1053    * sequence positions rather than alignment column positions.
1054    *
1055    * @param seqRef
1056    * @param startRes
1057    * @param alreadyMapped
1058    * - annotation are at aligned columns
1059    */
 
1060  4083 toggle public void createSequenceMapping(SequenceI seqRef, int startRes,
1061    boolean alreadyMapped)
1062    {
1063   
1064  4083 if (seqRef == null)
1065    {
1066  0 return;
1067    }
1068  4083 sequenceRef = seqRef;
1069  4083 if (annotations == null)
1070    {
1071  1270 return;
1072    }
1073  2813 sequenceMapping = new HashMap<>();
1074   
1075  2813 int seqPos;
1076   
1077  403613 for (int i = 0; i < annotations.length; i++)
1078    {
1079  400800 if (annotations[i] != null)
1080    {
1081  336178 if (alreadyMapped)
1082    {
1083  203771 seqPos = seqRef.findPosition(i);
1084    }
1085    else
1086    {
1087  132407 seqPos = i + startRes;
1088    }
1089   
1090  336178 sequenceMapping.put(Integer.valueOf(seqPos), annotations[i]);
1091    }
1092    }
1093   
1094    }
1095   
1096    /**
1097    * When positional annotation and a sequence reference is present, clears and
1098    * resizes the annotations array to the current alignment width, and adds
1099    * annotation according to aligned positions of the sequenceRef given by
1100    * sequenceMapping.
1101    */
 
1102  4183 toggle public void adjustForAlignment()
1103    {
1104  4183 if (sequenceRef == null)
1105    {
1106  191 return;
1107    }
1108   
1109  3992 if (annotations == null)
1110    {
1111  1270 return;
1112    }
1113   
1114  2722 int a = 0, aSize = sequenceRef.getLength();
1115   
1116  2722 if (aSize == 0)
1117    {
1118    // Its been deleted
1119  1 return;
1120    }
1121   
1122  2721 int position;
1123  2721 Annotation[] temp = new Annotation[aSize];
1124  2721 Integer index;
1125  2721 if (sequenceMapping != null)
1126    {
1127  318506 for (a = sequenceRef.getStart(); a <= sequenceRef.getEnd(); a++)
1128    {
1129  315785 index = Integer.valueOf(a);
1130  315785 Annotation annot = sequenceMapping.get(index);
1131  315785 if (annot != null)
1132    {
1133  250703 position = sequenceRef.findIndex(a) - 1;
1134   
1135  250703 temp[position] = annot;
1136    }
1137    }
1138    }
1139  2721 annotations = temp;
1140    }
1141   
1142    /**
1143    * remove any null entries in annotation row and return the number of non-null
1144    * annotation elements.
1145    *
1146    * @return
1147    */
 
1148  0 toggle public int compactAnnotationArray()
1149    {
1150  0 int i = 0, iSize = annotations.length;
1151  0 while (i < iSize)
1152    {
1153  0 if (annotations[i] == null)
1154    {
1155  0 if (i + 1 < iSize)
1156    {
1157  0 System.arraycopy(annotations, i + 1, annotations, i,
1158    iSize - i - 1);
1159    }
1160  0 iSize--;
1161    }
1162    else
1163    {
1164  0 i++;
1165    }
1166    }
1167  0 Annotation[] ann = annotations;
1168  0 annotations = new Annotation[i];
1169  0 System.arraycopy(ann, 0, annotations, 0, i);
1170  0 ann = null;
1171  0 return iSize;
1172    }
1173   
1174    /**
1175    * Associate this annotation with the aligned residues of a particular
1176    * sequence. sequenceMapping will be updated in the following way: null
1177    * sequenceI - existing mapping will be discarded but annotations left in
1178    * mapped positions. valid sequenceI not equal to current sequenceRef: mapping
1179    * is discarded and rebuilt assuming 1:1 correspondence TODO: overload with
1180    * parameter to specify correspondence between current and new sequenceRef
1181    *
1182    * @param sequenceI
1183    */
 
1184  5426 toggle public void setSequenceRef(SequenceI sequenceI)
1185    {
1186  5426 if (sequenceI != null)
1187    {
1188  5363 if (sequenceRef != null)
1189    {
1190  3076 boolean rIsDs = sequenceRef.getDatasetSequence() == null,
1191    tIsDs = sequenceI.getDatasetSequence() == null;
1192  3076 if (sequenceRef != sequenceI
1193    && (rIsDs && !tIsDs
1194    && sequenceRef != sequenceI.getDatasetSequence())
1195    && (!rIsDs && tIsDs
1196    && sequenceRef.getDatasetSequence() != sequenceI)
1197    && (!rIsDs && !tIsDs
1198    && sequenceRef.getDatasetSequence() != sequenceI
1199    .getDatasetSequence())
1200    && !sequenceRef.equals(sequenceI))
1201    {
1202    // if sequenceRef isn't intersecting with sequenceI
1203    // throw away old mapping and reconstruct.
1204  0 sequenceRef = null;
1205  0 if (sequenceMapping != null)
1206    {
1207  0 sequenceMapping = null;
1208    // compactAnnotationArray();
1209    }
1210  0 createSequenceMapping(sequenceI, 1, true);
1211  0 adjustForAlignment();
1212    }
1213    else
1214    {
1215    // Mapping carried over
1216  3076 sequenceRef = sequenceI;
1217    }
1218    }
1219    else
1220    {
1221    // No mapping exists
1222  2287 createSequenceMapping(sequenceI, 1, true);
1223  2287 adjustForAlignment();
1224    }
1225    }
1226    else
1227    {
1228    // throw away the mapping without compacting.
1229  63 sequenceMapping = null;
1230  63 sequenceRef = null;
1231    }
1232    }
1233   
1234    /**
1235    * @return the score
1236    */
 
1237  156 toggle public double getScore()
1238    {
1239  156 return score;
1240    }
1241   
1242    /**
1243    * @param score
1244    * the score to set
1245    */
 
1246  36363 toggle public void setScore(double score)
1247    {
1248  36363 hasScore = true;
1249  36363 this.score = score;
1250    }
1251   
1252    /**
1253    *
1254    * @return true if annotation has an associated score
1255    */
 
1256  1437 toggle public boolean hasScore()
1257    {
1258  1437 return hasScore || !Double.isNaN(score);
1259    }
1260   
1261    /**
1262    * Score only annotation
1263    *
1264    * @param label
1265    * @param description
1266    * @param score
1267    */
 
1268  34620 toggle public AlignmentAnnotation(String label, String description, double score)
1269    {
1270  34620 this(label, description, null);
1271  34620 setScore(score);
1272    }
1273   
1274    /**
1275    * copy constructor with edit based on the hidden columns marked in colSel
1276    *
1277    * @param alignmentAnnotation
1278    * @param colSel
1279    */
 
1280  18 toggle public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation,
1281    HiddenColumns hidden)
1282    {
1283  18 this(alignmentAnnotation);
1284  18 if (annotations == null)
1285    {
1286  0 return;
1287    }
1288  18 makeVisibleAnnotation(hidden);
1289    }
1290   
1291   
 
1292  0 toggle public void setPadGaps(boolean padgaps, char gapchar)
1293    {
1294  0 this.padGaps = padgaps;
1295  0 if (padgaps)
1296    {
1297  0 hasText = true;
1298  0 for (int i = 0; i < annotations.length; i++)
1299    {
1300  0 if (annotations[i] == null)
1301    {
1302  0 annotations[i] = new Annotation(String.valueOf(gapchar), null,
1303    ' ', 0f, null);
1304    }
1305  0 else if (annotations[i].displayCharacter == null
1306    || annotations[i].displayCharacter.equals(" "))
1307    {
1308  0 annotations[i].displayCharacter = String.valueOf(gapchar);
1309    }
1310    }
1311    }
1312    }
1313   
1314    /**
1315    * format description string for display
1316    *
1317    * @param seqname
1318    * @return Get the annotation description string optionally prefixed by
1319    * associated sequence name (if any)
1320    */
 
1321  10 toggle public String getDescription(boolean seqname)
1322    {
1323  10 if (seqname && this.sequenceRef != null)
1324    {
1325  3 int i = description.toLowerCase(Locale.ROOT).indexOf("<html>");
1326  3 if (i > -1)
1327    {
1328    // move the html tag to before the sequence reference.
1329  1 return "<html>" + sequenceRef.getName() + " : "
1330    + description.substring(i + 6);
1331    }
1332  2 return sequenceRef.getName() + " : " + description;
1333    }
1334  7 return description;
1335    }
1336   
 
1337  228 toggle public boolean isValidStruc()
1338    {
1339  228 return invalidrnastruc == -1;
1340    }
1341   
 
1342  1442223 toggle public long getInvalidStrucPos()
1343    {
1344  1442223 return invalidrnastruc;
1345    }
1346   
1347    /**
1348    * machine readable ID string indicating what generated this annotation
1349    */
1350    protected String calcId = "";
1351   
1352    /**
1353    * properties associated with the calcId
1354    */
1355    protected Map<String, String> properties = new HashMap<>();
1356   
1357    /**
1358    * base colour for line graphs. If null, will be set automatically by
1359    * searching the alignment annotation
1360    */
1361    public java.awt.Color _linecolour;
1362   
 
1363  71330 toggle public String getCalcId()
1364    {
1365  71330 return calcId;
1366    }
1367   
 
1368  3763 toggle public void setCalcId(String calcId)
1369    {
1370  3763 this.calcId = calcId;
1371    }
1372   
 
1373  18145 toggle public boolean isRNA()
1374    {
1375  18145 return isrna;
1376    }
1377   
1378    /**
1379    * transfer annotation to the given sequence using the given mapping from the
1380    * current positions or an existing sequence mapping
1381    *
1382    * @param sq
1383    * @param sp2sq
1384    * map involving sq as To or From
1385    */
 
1386  224 toggle public void liftOver(SequenceI sq, Mapping sp2sq)
1387    {
1388  224 if (sp2sq.getMappedWidth() != sp2sq.getWidth())
1389    {
1390    // TODO: employ getWord/MappedWord to transfer annotation between cDNA and
1391    // Protein reference frames
1392  0 throw new Error(
1393    "liftOver currently not implemented for transfer of annotation between different types of seqeunce");
1394    }
1395  224 boolean mapIsTo = (sp2sq != null)
1396    ? (sp2sq.getTo() == sq
1397    || sp2sq.getTo() == sq.getDatasetSequence())
1398    : false;
1399   
1400    // TODO build a better annotation element map and get rid of annotations[]
1401  224 Map<Integer, Annotation> mapForsq = new HashMap<>();
1402  224 if (sequenceMapping != null)
1403    {
1404  224 if (sp2sq != null)
1405    {
1406  224 for (Entry<Integer, Annotation> ie : sequenceMapping.entrySet())
1407    {
1408  18202 Integer mpos = Integer
1409  18202 .valueOf(mapIsTo ? sp2sq.getMappedPosition(ie.getKey())
1410    : sp2sq.getPosition(ie.getKey()));
1411  18202 if (mpos >= sq.getStart() && mpos <= sq.getEnd())
1412    {
1413  18196 mapForsq.put(mpos, ie.getValue());
1414    }
1415    }
1416  224 sequenceMapping = mapForsq;
1417  224 sequenceRef = sq;
1418  224 adjustForAlignment();
1419    }
1420    else
1421    {
1422    // trim positions
1423    }
1424    }
1425    }
1426   
1427    /**
1428    * like liftOver but more general.
1429    *
1430    * Takes an array of int pairs that will be used to update the internal
1431    * sequenceMapping and so shuffle the annotated positions
1432    *
1433    * @param newref
1434    * - new sequence reference for the annotation row - if null,
1435    * sequenceRef is left unchanged
1436    * @param mapping
1437    * array of ints containing corresponding positions
1438    * @param from
1439    * - column for current coordinate system (-1 for index+1)
1440    * @param to
1441    * - column for destination coordinate system (-1 for index+1)
1442    * @param idxoffset
1443    * - offset added to index when referencing either coordinate system
1444    * @note no checks are made as to whether from and/or to are sensible
1445    * @note caller should add the remapped annotation to newref if they have not
1446    * already
1447    */
 
1448  0 toggle public void remap(SequenceI newref, HashMap<Integer, int[]> mapping,
1449    int from, int to, int idxoffset)
1450    {
1451  0 if (mapping != null)
1452    {
1453  0 Map<Integer, Annotation> old = sequenceMapping;
1454  0 Map<Integer, Annotation> remap = new HashMap<>();
1455  0 int index = -1;
1456  0 for (int mp[] : mapping.values())
1457    {
1458  0 if (index++ < 0)
1459    {
1460  0 continue;
1461    }
1462  0 Annotation ann = null;
1463  0 if (from == -1)
1464    {
1465  0 ann = sequenceMapping.get(Integer.valueOf(idxoffset + index));
1466    }
1467    else
1468    {
1469  0 if (mp != null && mp.length > from)
1470    {
1471  0 ann = sequenceMapping.get(Integer.valueOf(mp[from]));
1472    }
1473    }
1474  0 if (ann != null)
1475    {
1476  0 if (to == -1)
1477    {
1478  0 remap.put(Integer.valueOf(idxoffset + index), ann);
1479    }
1480    else
1481    {
1482  0 if (to > -1 && to < mp.length)
1483    {
1484  0 remap.put(Integer.valueOf(mp[to]), ann);
1485    }
1486    }
1487    }
1488    }
1489  0 sequenceMapping = remap;
1490  0 old.clear();
1491  0 if (newref != null)
1492    {
1493  0 sequenceRef = newref;
1494    }
1495  0 adjustForAlignment();
1496    }
1497    }
1498   
 
1499  403796 toggle public String getProperty(String property)
1500    {
1501  403792 if (properties == null)
1502    {
1503  0 return null;
1504    }
1505  403792 return properties.get(property);
1506    }
1507   
 
1508  1972 toggle public void setProperty(String property, String value)
1509    {
1510  1972 if (properties == null)
1511    {
1512  0 properties = new HashMap<>();
1513    }
1514  1972 properties.put(property, value);
1515    }
1516   
 
1517  754 toggle public boolean hasProperties()
1518    {
1519  754 return properties != null && properties.size() > 0;
1520    }
1521   
 
1522  301 toggle public Collection<String> getProperties()
1523    {
1524  301 if (properties == null)
1525    {
1526  0 return Collections.emptyList();
1527    }
1528  301 return properties.keySet();
1529    }
1530   
1531    /**
1532    * Returns the Annotation for the given sequence position (base 1) if any,
1533    * else null
1534    *
1535    * @param position
1536    * @return
1537    */
 
1538  155899 toggle public Annotation getAnnotationForPosition(int position)
1539    {
1540  155894 return sequenceMapping == null ? null : sequenceMapping.get(position);
1541   
1542    }
1543   
1544    /**
1545    * Set the id to "ann" followed by a counter that increments so as to be
1546    * unique for the lifetime of the JVM
1547    */
 
1548  41939 toggle protected final void setAnnotationId()
1549    {
1550  41939 this.annotationId = ANNOTATION_ID_PREFIX + Long.toString(nextId());
1551    }
1552   
1553    /**
1554    * Returns the match for the last unmatched opening RNA helix pair symbol
1555    * preceding the given column, or '(' if nothing found to match.
1556    *
1557    * @param column
1558    * @return
1559    */
 
1560  43 toggle public String getDefaultRnaHelixSymbol(int column)
1561    {
1562  43 String result = "(";
1563  43 if (annotations == null)
1564    {
1565  1 return result;
1566    }
1567   
1568    /*
1569    * for each preceding column, if it contains an open bracket,
1570    * count whether it is still unmatched at column, if so return its pair
1571    * (likely faster than the fancy alternative using stacks)
1572    */
1573  150 for (int col = column - 1; col >= 0; col--)
1574    {
1575  142 Annotation annotation = annotations[col];
1576  142 if (annotation == null)
1577    {
1578  66 continue;
1579    }
1580  76 String displayed = annotation.displayCharacter;
1581  76 if (displayed == null || displayed.length() != 1)
1582    {
1583  0 continue;
1584    }
1585  76 char symbol = displayed.charAt(0);
1586  76 if (!Rna.isOpeningParenthesis(symbol))
1587    {
1588  24 continue;
1589    }
1590   
1591    /*
1592    * found an opening bracket symbol
1593    * count (closing-opening) symbols of this type that follow it,
1594    * up to and excluding the target column; if the count is less
1595    * than 1, the opening bracket is unmatched, so return its match
1596    */
1597  52 String closer = String
1598    .valueOf(Rna.getMatchingClosingParenthesis(symbol));
1599  52 String opener = String.valueOf(symbol);
1600  52 int count = 0;
1601  256 for (int j = col + 1; j < column; j++)
1602    {
1603  204 if (annotations[j] != null)
1604    {
1605  90 String s = annotations[j].displayCharacter;
1606  90 if (closer.equals(s))
1607    {
1608  18 count++;
1609    }
1610  72 else if (opener.equals(s))
1611    {
1612  0 count--;
1613    }
1614    }
1615    }
1616  52 if (count < 1)
1617    {
1618  34 return closer;
1619    }
1620    }
1621  8 return result;
1622    }
1623   
 
1624  41939 toggle protected static synchronized long nextId()
1625    {
1626  41939 return counter++;
1627    }
1628   
1629    /**
1630    *
1631    * @return true for rows that have a range of values in their annotation set
1632    */
 
1633  5 toggle public boolean isQuantitative()
1634    {
1635  5 return graphMin < graphMax;
1636    }
1637   
1638    /**
1639    * @return true if hasData and visible are true
1640    */
 
1641  163853 toggle public boolean isForDisplay()
1642    {
1643  163855 return hasData && visible;
1644    }
1645   
1646    /**
1647    * delete any columns in alignmentAnnotation that are hidden (including
1648    * sequence associated annotation).
1649    *
1650    * @param hiddenColumns
1651    * the set of hidden columns
1652    */
 
1653  27 toggle public void makeVisibleAnnotation(HiddenColumns hiddenColumns)
1654    {
1655  27 if (annotations != null)
1656    {
1657  25 makeVisibleAnnotation(0, annotations.length - 1, hiddenColumns);
1658    }
1659    }
1660   
1661    /**
1662    * delete any columns in alignmentAnnotation that are hidden (including
1663    * sequence associated annotation).
1664    *
1665    * @param start
1666    * remove any annotation to the right of this column
1667    * @param end
1668    * remove any annotation to the left of this column
1669    * @param hiddenColumns
1670    * the set of hidden columns
1671    */
 
1672  45 toggle public void makeVisibleAnnotation(int start, int end,
1673    HiddenColumns hiddenColumns)
1674    {
1675  45 if (annotations != null)
1676    {
1677  43 if (hiddenColumns.hasHiddenColumns())
1678    {
1679  22 removeHiddenAnnotation(start, end, hiddenColumns);
1680    }
1681    else
1682    {
1683  21 restrict(start, end);
1684    }
1685    }
1686    }
1687   
1688    /**
1689    * The actual implementation of deleting hidden annotation columns
1690    *
1691    * @param start
1692    * remove any annotation to the right of this column
1693    * @param end
1694    * remove any annotation to the left of this column
1695    * @param hiddenColumns
1696    * the set of hidden columns
1697    */
 
1698  22 toggle private void removeHiddenAnnotation(int start, int end,
1699    HiddenColumns hiddenColumns)
1700    {
1701  22 start = Math.min(Math.max(0, start), annotations.length);
1702  22 end = Math.min(Math.max(-1, end), annotations.length - 1);
1703    // mangle the alignmentAnnotation annotation array
1704  22 ArrayList<Annotation[]> annels = new ArrayList<>();
1705  22 Annotation[] els = null;
1706   
1707  22 int w = 0;
1708   
1709  22 Iterator<int[]> blocks = hiddenColumns.getVisContigsIterator(start,
1710    end + 1, false);
1711   
1712  22 int copylength;
1713  22 int annotationLength;
1714  62 while (blocks.hasNext())
1715    {
1716  40 int[] block = blocks.next();
1717  40 annotationLength = block[1] - block[0] + 1;
1718   
1719  40 if (blocks.hasNext())
1720    {
1721    // copy just the visible segment of the annotation row
1722  18 copylength = annotationLength;
1723    }
1724    else
1725    {
1726  22 if (annotationLength + block[0] <= annotations.length)
1727    {
1728    // copy just the visible segment of the annotation row
1729  22 copylength = annotationLength;
1730    }
1731    else
1732    {
1733    // copy to the end of the annotation row
1734  0 copylength = annotations.length - block[0];
1735    }
1736    }
1737   
1738  40 els = new Annotation[annotationLength];
1739  40 annels.add(els);
1740  40 System.arraycopy(annotations, block[0], els, 0, copylength);
1741  40 w += annotationLength;
1742    }
1743   
1744  22 if (w != 0)
1745    {
1746  22 annotations = new Annotation[w];
1747   
1748  22 w = 0;
1749  22 for (Annotation[] chnk : annels)
1750    {
1751  40 System.arraycopy(chnk, 0, annotations, w, chnk.length);
1752  40 w += chnk.length;
1753    }
1754    }
1755    }
1756   
 
1757  168 toggle public static Iterable<AlignmentAnnotation> findAnnotations(
1758    Iterable<AlignmentAnnotation> list, SequenceI seq, String calcId,
1759    String label)
1760    {
1761  168 ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
1762  168 for (AlignmentAnnotation ann : list)
1763    {
1764  1114 if ((calcId == null || (ann.getCalcId() != null
1765    && ann.getCalcId().equals(calcId)))
1766    && (seq == null || (ann.sequenceRef != null
1767    && ann.sequenceRef == seq))
1768    && (label == null
1769    || (ann.label != null && ann.label.equals(label))))
1770    {
1771  174 aa.add(ann);
1772    }
1773    }
1774  168 return aa;
1775    }
1776   
1777    /**
1778    * Answer true if any annotation matches the calcId passed in (if not null).
1779    *
1780    * @param list
1781    * annotation to search
1782    * @param calcId
1783    * @return
1784    */
 
1785  0 toggle public static boolean hasAnnotation(List<AlignmentAnnotation> list,
1786    String calcId)
1787    {
1788   
1789  0 if (calcId != null && !"".equals(calcId))
1790    {
1791  0 for (AlignmentAnnotation a : list)
1792    {
1793  0 if (a.getCalcId() == calcId)
1794    {
1795  0 return true;
1796    }
1797    }
1798    }
1799  0 return false;
1800    }
1801   
 
1802  530 toggle public static Iterable<AlignmentAnnotation> findAnnotation(
1803    List<AlignmentAnnotation> list, String calcId)
1804    {
1805  530 List<AlignmentAnnotation> aa = new ArrayList<>();
1806  530 if (calcId == null)
1807    {
1808  1 return aa;
1809    }
1810  529 for (AlignmentAnnotation a : list)
1811    {
1812   
1813  3040 if (a.getCalcId() == calcId || (a.getCalcId() != null
1814    && calcId != null && a.getCalcId().equals(calcId)))
1815    {
1816  554 aa.add(a);
1817    }
1818    }
1819  529 return aa;
1820    }
1821   
1822    /**
1823    * convenience method to check for the 'CONTACT_MAP_NOGROUPS' property for
1824    * this alignment annotation row
1825    *
1826    * @return true if no CONTACT_MAP_NOGROUPS property is found, or it is set to
1827    * ""
1828    */
 
1829  391 toggle public boolean isShowGroupsForContactMatrix()
1830    {
1831  391 return getProperty(AlignmentAnnotation.CONTACT_MAP_NOGROUPS) == null
1832    || "".equals(
1833    getProperty(AlignmentAnnotation.CONTACT_MAP_NOGROUPS));
1834    }
1835   
1836    /**
1837    * set the 'CONTACT_MAP_NOGROUPS' property for this alignment annotation row
1838    *
1839    * @see isShowGroupsForContactMatrix
1840    */
 
1841  2 toggle public void setShowGroupsForContactMatrix(boolean showGroups)
1842    {
1843  2 setProperty(AlignmentAnnotation.CONTACT_MAP_NOGROUPS,
1844  2 showGroups ? "" : "nogroups");
1845    }
1846   
 
1847  169227 toggle public long getNoOfSequencesIncluded()
1848    {
1849  169227 return noOfSequencesIncluded;
1850    }
1851   
 
1852  5302 toggle public void setNoOfSequencesIncluded(long noOfSequencesIncluded)
1853    {
1854  5302 this.noOfSequencesIncluded = noOfSequencesIncluded;
1855    }
1856   
 
1857  897 toggle public long getNoOfTracksIncluded()
1858    {
1859    // TODO Auto-generated method stub
1860  897 return noOfTracksIncluded;
1861    }
 
1862  1755 toggle public void setNoOfTracksIncluded(long noOfTracks)
1863    {
1864  1755 this.noOfTracksIncluded = noOfTracks;
1865    }
1866   
1867   
1868    /**
1869    * This method matches the label and calcid with the
1870    * label and calcid of the AlignmentAnnotation object
1871    */
 
1872  8370 toggle public boolean labelAndCalcIdMatches(String label, String calcId)
1873    {
1874  8370 return this.label.equalsIgnoreCase(label)
1875    && ((this.getCalcId() == null && calcId == null)
1876    || (this.getCalcId() != null && calcId != null
1877    && this.getCalcId().equals(calcId)));
1878    }
1879   
 
1880  72 toggle public void setAnnotationDetailsProperty(String annotDetails) {
1881  72 this.setProperty(ANNOTATION_DETAILS, annotDetails);
1882    }
1883   
 
1884  23 toggle public String getAnnotationDetailsProperty() {
1885  23 if(hasAnnotationDetailsProperty())
1886    {
1887  18 return this.getProperty(ANNOTATION_DETAILS);
1888    }
1889   
1890  5 return null;
1891    }
1892   
 
1893  42823 toggle public boolean hasAnnotationDetailsProperty() {
1894  42823 if(this.getProperty(ANNOTATION_DETAILS) != null
1895    && this.getProperty(ANNOTATION_DETAILS).length() > 0)
1896    {
1897  42788 return true;
1898    }
1899   
1900  35 return false;
1901    }
 
1902  18 toggle public String getLabel()
1903    {
1904  18 return label;
1905    }
1906   
 
1907  18 toggle public Annotation[] getAnnotations()
1908    {
1909  18 return annotations;
1910    }
1911   
 
1912  0 toggle public double getBitScore()
1913    {
1914  0 return bitScore;
1915    }
1916   
 
1917  0 toggle public void setBitScore(double bitScore)
1918    {
1919  0 this.bitScore = bitScore;
1920    }
1921   
 
1922  0 toggle public double getEValue()
1923    {
1924  0 return eValue;
1925    }
1926   
 
1927  0 toggle public void setEValue(double eValue)
1928    {
1929  0 this.eValue = eValue;
1930    }
1931   
 
1932  21 toggle public static AlignmentAnnotation findFirstAnnotation(
1933    Iterable<AlignmentAnnotation> alignmentAnnotation, String name,
1934    String calcId, boolean autoCalc, SequenceI seqRef,
1935    SequenceGroup groupRef)
1936    {
1937   
1938  21 for (AlignmentAnnotation annot : alignmentAnnotation)
1939    {
1940  192 if (annot.autoCalculated == autoCalc && (name.equals(annot.label))
1941    && (calcId == null || annot.getCalcId().equals(calcId))
1942    && annot.sequenceRef == seqRef && annot.groupRef == groupRef)
1943    {
1944  3 return annot;
1945    }
1946    }
1947  18 return null;
1948    }
1949   
1950    }