Clover icon

Coverage Report

  1. Project Clover database Thu Aug 13 2020 12:04:21 BST
  2. Package jalview.datamodel

File AlignmentAnnotation.java

 

Coverage histogram

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

Code metrics

294
464
56
2
1,717
1,160
315
0.68
8.29
28
5.62

Classes

Class Line # Actions
AlignmentAnnotation 43 453 298
0.740787874.1%
AlignmentAnnotation.AnnotCharSequence 501 11 17
0.925925992.6%
 

Contributing tests

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