Clover icon

Coverage Report

  1. Project Clover database Thu Nov 7 2024 10:11:34 GMT
  2. Package jalview.datamodel

File AlignmentAnnotation.java

 

Coverage histogram

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

Code metrics

296
470
62
2
1,794
1,194
315
0.67
7.58
31
5.08

Classes

Class Line # Actions
AlignmentAnnotation 45 459 298
0.779026277.9%
AlignmentAnnotation.AnnotCharSequence 542 11 17
0.925925992.6%
 

Contributing tests

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