Clover icon

Coverage Report

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

File AlignmentAnnotation.java

 

Coverage histogram

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

Code metrics

296
472
63
2
1,811
1,200
316
0.67
7.49
31.5
5.02

Classes

Class Line # Actions
AlignmentAnnotation 45 461 299
0.743781174.4%
AlignmentAnnotation.AnnotCharSequence 550 11 17
0.925925992.6%
 

Contributing tests

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