Clover icon

Coverage Report

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

File SequenceGroup.java

 

Coverage histogram

../../img/srcFileCovDistChart6.png
36% of files have more coverage

Code metrics

184
415
97
1
1,728
1,055
209
0.5
4.28
97
2.15

Classes

Class Line # Actions
SequenceGroup 48 415 209
0.557471355.7%
 

Contributing tests

This file is covered by 104 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.datamodel;
22   
23    import java.awt.Color;
24    import java.beans.PropertyChangeListener;
25    import java.beans.PropertyChangeSupport;
26    import java.util.ArrayList;
27    import java.util.Arrays;
28    import java.util.Collection;
29    import java.util.Collections;
30    import java.util.HashMap;
31    import java.util.List;
32    import java.util.Map;
33   
34    import jalview.analysis.AAFrequency;
35    import jalview.analysis.AlignmentUtils;
36    import jalview.analysis.Conservation;
37    import jalview.renderer.ResidueShader;
38    import jalview.renderer.ResidueShaderI;
39    import jalview.schemes.ColourSchemeI;
40    import jalview.util.Constants;
41   
42    /**
43    * Collects a set contiguous ranges on a set of sequences
44    *
45    * @author $author$
46    * @version $Revision$
47    */
 
48    public class SequenceGroup implements AnnotatedCollectionI
49    {
50    // TODO ideally this event notification functionality should be separated into
51    // a
52    // subclass of ViewportProperties similarly to ViewportRanges. Done here as
53    // quick fix for JAL-2665
54    public static final String SEQ_GROUP_CHANGED = "Sequence group changed";
55   
56    protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
57    this);
58   
 
59  0 toggle public void addPropertyChangeListener(PropertyChangeListener listener)
60    {
61  0 changeSupport.addPropertyChangeListener(listener);
62    }
63   
 
64  0 toggle public void removePropertyChangeListener(PropertyChangeListener listener)
65    {
66  0 changeSupport.removePropertyChangeListener(listener);
67    }
68    // end of event notification functionality initialisation
69   
70    String groupName;
71   
72    String description;
73   
74    Conservation conserve;
75   
76    boolean displayBoxes = true;
77   
78    boolean displayText = true;
79   
80    boolean colourText = false;
81   
82    /**
83    * True if the group is defined as a group on the alignment, false if it is
84    * just a selection.
85    */
86    boolean isDefined = false;
87   
88    /**
89    * after Olivier's non-conserved only character display
90    */
91    boolean showNonconserved = false;
92   
93    /**
94    * group members
95    */
96    private List<SequenceI> sequences;
97   
98    /**
99    * representative sequence for this group (if any)
100    */
101    private SequenceI seqrep = null;
102   
103    int width = -1;
104   
105    /**
106    * Colourscheme applied to group if any
107    */
108    public ResidueShaderI cs;
109   
110    /**
111    * start column (base 0)
112    */
113    private int startRes = 0;
114   
115    /**
116    * end column (base 0)
117    */
118    private int endRes = 0;
119   
120    public Color outlineColour = Color.black;
121   
122    public Color idColour = null;
123   
124    public int thresholdTextColour = 0;
125   
126    public Color textColour = Color.black;
127   
128    public Color textColour2 = Color.white;
129   
130    /**
131    * consensus calculation property
132    */
133    private boolean ignoreGapsInConsensus = true;
134   
135    /**
136    * consensus calculation property
137    */
138    private boolean showSequenceLogo = false;
139   
140    /**
141    * flag indicating if logo should be rendered normalised
142    */
143    private boolean normaliseSequenceLogo;
144   
145    /*
146    * visibility of rows or represented rows covered by group
147    */
148    private boolean hidereps = false;
149   
150    /*
151    * visibility of columns intersecting this group
152    */
153    private boolean hidecols = false;
154   
155    AlignmentAnnotation consensus = null;
156   
157    List<AlignmentAnnotation> ssConsensus = null;
158   
159    List<String> secondaryStructureSources = null;
160   
161    AlignmentAnnotation conservation = null;
162   
163    private boolean showConsensusHistogram;
164   
165    private AnnotatedCollectionI context;
166   
167    public Map<String, ProfilesI> hSSConsensusProfileMap;
168   
169    /**
170    * Creates a new SequenceGroup object.
171    */
 
172  971 toggle public SequenceGroup()
173    {
174  971 groupName = "JGroup:" + this.hashCode();
175  971 cs = new ResidueShader();
176  971 sequences = new ArrayList<>();
177    }
178   
179    /**
180    * Creates a new SequenceGroup object.
181    *
182    * @param sequences
183    * @param groupName
184    * @param scheme
185    * @param displayBoxes
186    * @param displayText
187    * @param colourText
188    * @param start
189    * first column of group
190    * @param end
191    * last column of group
192    */
 
193  79 toggle public SequenceGroup(List<SequenceI> sequences, String groupName,
194    ColourSchemeI scheme, boolean displayBoxes, boolean displayText,
195    boolean colourText, int start, int end)
196    {
197  79 this();
198  79 this.sequences = sequences;
199  79 this.groupName = groupName;
200  79 this.displayBoxes = displayBoxes;
201  79 this.displayText = displayText;
202  79 this.colourText = colourText;
203  79 this.cs = new ResidueShader(scheme);
204  79 startRes = start;
205  79 endRes = end;
206  79 recalcConservation();
207    }
208   
209    /**
210    * copy constructor
211    *
212    * @param seqsel
213    */
 
214  107 toggle public SequenceGroup(SequenceGroup seqsel)
215    {
216  107 this();
217  107 if (seqsel != null)
218    {
219  99 sequences = new ArrayList<>();
220  99 sequences.addAll(seqsel.sequences);
221  99 if (seqsel.groupName != null)
222    {
223  99 groupName = new String(seqsel.groupName);
224    }
225  99 displayBoxes = seqsel.displayBoxes;
226  99 displayText = seqsel.displayText;
227  99 colourText = seqsel.colourText;
228   
229  99 startRes = seqsel.startRes;
230  99 endRes = seqsel.endRes;
231  99 cs = new ResidueShader((ResidueShader) seqsel.cs);
232  99 if (seqsel.description != null)
233    {
234  1 description = new String(seqsel.description);
235    }
236  99 hidecols = seqsel.hidecols;
237  99 hidereps = seqsel.hidereps;
238  99 showNonconserved = seqsel.showNonconserved;
239  99 showSequenceLogo = seqsel.showSequenceLogo;
240  99 normaliseSequenceLogo = seqsel.normaliseSequenceLogo;
241  99 showConsensusHistogram = seqsel.showConsensusHistogram;
242  99 idColour = seqsel.idColour;
243  99 outlineColour = seqsel.outlineColour;
244  99 seqrep = seqsel.seqrep;
245  99 textColour = seqsel.textColour;
246  99 textColour2 = seqsel.textColour2;
247  99 thresholdTextColour = seqsel.thresholdTextColour;
248  99 width = seqsel.width;
249  99 ignoreGapsInConsensus = seqsel.ignoreGapsInConsensus;
250  99 if (seqsel.conserve != null)
251    {
252  0 recalcConservation(); // safer than
253    // aaFrequency = (Vector) seqsel.aaFrequency.clone(); // ??
254    }
255    }
256    }
257   
258    /**
259    * Constructor that copies the given list of sequences
260    *
261    * @param seqs
262    */
 
263  11 toggle public SequenceGroup(List<SequenceI> seqs)
264    {
265  11 this();
266  11 this.sequences.addAll(seqs);
267    }
268   
 
269  45269 toggle public boolean isShowSequenceLogo()
270    {
271  45269 return showSequenceLogo;
272    }
273   
 
274  2 toggle public SequenceI[] getSelectionAsNewSequences(AlignmentI align)
275    {
276  2 int iSize = sequences.size();
277  2 SequenceI[] seqs = new SequenceI[iSize];
278  2 SequenceI[] inorder = getSequencesInOrder(align);
279   
280  18 for (int i = 0, ipos = 0; i < inorder.length; i++)
281    {
282  16 SequenceI seq = inorder[i];
283  16 SequenceI seqipos = seqs[ipos] = seq.getSubSequence(startRes,
284    endRes + 1);
285  16 if (seqipos != null)
286    {
287  16 if (seq.getAnnotation() != null)
288    {
289  1 AlignmentAnnotation[] alann = align.getAlignmentAnnotation();
290    // Only copy annotation that is either a score or referenced by the
291    // alignment's annotation vector
292  2 for (int a = 0; a < seq.getAnnotation().length; a++)
293    {
294  1 AlignmentAnnotation tocopy = seq.getAnnotation()[a];
295  1 if (alann != null)
296    {
297  1 boolean found = false;
298  1 for (int pos = 0, np = alann.length; pos < np; pos++)
299    {
300  1 if (alann[pos] == tocopy)
301    {
302  1 found = true;
303  1 break;
304    }
305    }
306  1 if (!found)
307    {
308  0 continue;
309    }
310    }
311  1 AlignmentAnnotation newannot = new AlignmentAnnotation(
312    seq.getAnnotation()[a]);
313  1 newannot.restrict(startRes, endRes);
314  1 newannot.setSequenceRef(seqs[ipos]);
315  1 newannot.adjustForAlignment();
316  1 ContactMatrixI cm = seq
317    .getContactMatrixFor(seq.getAnnotation()[a]);
318  1 if (cm != null)
319    {
320  1 seqs[ipos].addContactListFor(newannot, cm);
321    }
322  1 seqipos.addAlignmentAnnotation(newannot);
323    }
324    }
325  16 ipos++;
326    }
327    else
328    {
329  0 iSize--;
330    }
331    }
332  2 if (iSize != inorder.length)
333    {
334  0 SequenceI[] nseqs = new SequenceI[iSize];
335  0 System.arraycopy(seqs, 0, nseqs, 0, iSize);
336  0 seqs = nseqs;
337    }
338  2 return seqs;
339   
340    }
341   
342    /**
343    * If sequence ends in gaps, the end residue can be correctly calculated here
344    *
345    * @param seq
346    * SequenceI
347    * @return int
348    */
 
349  0 toggle public int findEndRes(SequenceI seq)
350    {
351  0 int eres = 0;
352  0 char ch;
353   
354  0 for (int j = 0; j < endRes + 1 && j < seq.getLength(); j++)
355    {
356  0 ch = seq.getCharAt(j);
357  0 if (!jalview.util.Comparison.isGap((ch)))
358    {
359  0 eres++;
360    }
361    }
362   
363  0 if (eres > 0)
364    {
365  0 eres += seq.getStart() - 1;
366    }
367   
368  0 return eres;
369    }
370   
 
371  18418 toggle @Override
372    public List<SequenceI> getSequences()
373    {
374  18418 return sequences;
375    }
376   
 
377  1686 toggle @Override
378    public List<SequenceI> getSequences(
379    Map<SequenceI, SequenceCollectionI> hiddenReps)
380    {
381  1686 if (hiddenReps == null)
382    {
383    // TODO: need a synchronizedCollection here ?
384  1686 return sequences;
385    }
386    else
387    {
388  0 List<SequenceI> allSequences = new ArrayList<>();
389  0 for (SequenceI seq : sequences)
390    {
391  0 allSequences.add(seq);
392  0 if (hiddenReps.containsKey(seq))
393    {
394  0 SequenceCollectionI hsg = hiddenReps.get(seq);
395  0 for (SequenceI seq2 : hsg.getSequences())
396    {
397  0 if (seq2 != seq && !allSequences.contains(seq2))
398    {
399  0 allSequences.add(seq2);
400    }
401    }
402    }
403    }
404   
405  0 return allSequences;
406    }
407    }
408   
 
409  5 toggle public SequenceI[] getSequencesAsArray(
410    Map<SequenceI, SequenceCollectionI> map)
411    {
412  5 List<SequenceI> tmp = getSequences(map);
413  5 if (tmp == null)
414    {
415  0 return null;
416    }
417  5 return tmp.toArray(new SequenceI[tmp.size()]);
418    }
419   
 
420  19 toggle public List<String> getSecondaryStructureSources()
421    {
422  19 return secondaryStructureSources;
423    }
424   
 
425  47 toggle public void setSecondaryStructureSources(
426    List<String> secondaryStructureSources)
427    {
428  47 this.secondaryStructureSources = secondaryStructureSources;
429    }
430   
431    /**
432    * DOCUMENT ME!
433    *
434    * @param col
435    * DOCUMENT ME!
436    *
437    * @return DOCUMENT ME!
438    */
 
439  0 toggle public boolean adjustForRemoveLeft(int col)
440    {
441    // return value is true if the group still exists
442  0 if (startRes >= col)
443    {
444  0 startRes = startRes - col;
445    }
446   
447  0 if (endRes >= col)
448    {
449  0 endRes = endRes - col;
450   
451  0 if (startRes > endRes)
452    {
453  0 startRes = 0;
454    }
455    }
456    else
457    {
458    // must delete this group!!
459  0 return false;
460    }
461   
462  0 return true;
463    }
464   
465    /**
466    * DOCUMENT ME!
467    *
468    * @param col
469    * DOCUMENT ME!
470    *
471    * @return DOCUMENT ME!
472    */
 
473  0 toggle public boolean adjustForRemoveRight(int col)
474    {
475  0 if (startRes > col)
476    {
477    // delete this group
478  0 return false;
479    }
480   
481  0 if (endRes >= col)
482    {
483  0 endRes = col;
484    }
485   
486  0 return true;
487    }
488   
489    /**
490    * DOCUMENT ME!
491    *
492    * @return DOCUMENT ME!
493    */
 
494  247 toggle public String getName()
495    {
496  247 return groupName;
497    }
498   
 
499  16 toggle public String getDescription()
500    {
501  16 return description;
502    }
503   
504    /**
505    * DOCUMENT ME!
506    *
507    * @param name
508    * DOCUMENT ME!
509    */
 
510  23 toggle public void setName(String name)
511    {
512  23 groupName = name;
513    // TODO: URGENT: update dependent objects (annotation row)
514    }
515   
 
516  20 toggle public void setDescription(String desc)
517    {
518  20 description = desc;
519    }
520   
521    /**
522    * DOCUMENT ME!
523    *
524    * @return DOCUMENT ME!
525    */
 
526  0 toggle public Conservation getConservation()
527    {
528  0 return conserve;
529    }
530   
531    /**
532    * DOCUMENT ME!
533    *
534    * @param c
535    * DOCUMENT ME!
536    */
 
537  0 toggle public void setConservation(Conservation c)
538    {
539  0 conserve = c;
540    }
541   
542    /**
543    * Add s to this sequence group. If aligment sequence is already contained in
544    * group, it will not be added again, but recalculation may happen if the flag
545    * is set.
546    *
547    * @param s
548    * alignment sequence to be added
549    * @param recalc
550    * true means Group's conservation should be recalculated
551    */
 
552  623 toggle public void addSequence(SequenceI s, boolean recalc)
553    {
554  623 synchronized (sequences)
555    {
556  623 if (s != null && !sequences.contains(s))
557    {
558  612 sequences.add(s);
559  612 changeSupport.firePropertyChange(SEQ_GROUP_CHANGED,
560    sequences.size() - 1, sequences.size());
561    }
562   
563  623 if (recalc)
564    {
565  1 recalcConservation();
566    }
567    }
568    }
569   
570    /**
571    * Max Gaps Threshold (percent) for performing a conservation calculation
572    */
573    private int consPercGaps = 25;
574   
575    /**
576    * @return Max Gaps Threshold for performing a conservation calculation
577    */
 
578  0 toggle public int getConsPercGaps()
579    {
580  0 return consPercGaps;
581    }
582   
583    /**
584    * set Max Gaps Threshold (percent) for performing a conservation calculation
585    *
586    * @param consPercGaps
587    */
 
588  0 toggle public void setConsPercGaps(int consPercGaps)
589    {
590  0 this.consPercGaps = consPercGaps;
591    }
592   
593    /**
594    * calculate residue conservation and colourschemes for group - but only if
595    * necessary. returns true if the calculation resulted in a visible change to
596    * group
597    */
 
598  381 toggle public boolean recalcConservation()
599    {
600  381 return recalcConservation(false);
601    }
602   
603    /**
604    * calculate residue conservation for group - but only if necessary. returns
605    * true if the calculation resulted in a visible change to group
606    *
607    * @param defer
608    * when set, colourschemes for this group are not refreshed after
609    * recalculation
610    */
 
611  381 toggle public boolean recalcConservation(boolean defer)
612    {
613  381 if (cs == null && consensus == null && conservation == null)
614    {
615  0 return false;
616    }
617    // TODO: try harder to detect changes in state in order to minimise
618    // recalculation effort
619  381 boolean upd = false;
620  381 try
621    {
622  381 ProfilesI cnsns = AAFrequency.calculate(sequences, startRes,
623    endRes + 1, showSequenceLogo);
624  381 if (consensus != null)
625    {
626  120 _updateConsensusRow(cnsns, sequences.size());
627  120 upd = true;
628    }
629  381 if (cs != null)
630    {
631  381 cs.setConsensus(cnsns);
632  381 upd = true;
633    }
634   
635  381 hSSConsensusProfileMap = new HashMap<String, ProfilesI>();
636  381 List<String> ssSources = new ArrayList<String>();
637  381 AnnotatedCollectionI aa = this.getContext();
638   
639  381 if (aa != null)
640    {
641  302 ssSources = AlignmentUtils.extractSSSourceInAlignmentAnnotation(
642    aa.getAlignmentAnnotation());
643    }
644  381 if (ssSources != null)
645    {
646  381 ssSources.add(Constants.SS_ALL_PROVIDERS);
647   
648  381 for (String ssSource : ssSources)
649    {
650  381 ProfilesI hSSConsensus = AAFrequency.calculateSS(sequences,
651    startRes, endRes + 1, showSequenceLogo, ssSource);
652  381 hSSConsensusProfileMap.put(ssSource, hSSConsensus);
653    }
654    }
655   
656  381 if (ssConsensus != null)
657    {
658  0 _updateSSConsensusRow(hSSConsensusProfileMap, sequences.size());
659  0 upd = true;
660    }
661   
662  381 if (cs != null)
663    {
664  381 cs.setSSConsensusProfileMap(hSSConsensusProfileMap);
665  381 upd = true;
666    }
667   
668  381 if ((conservation != null)
669    || (cs != null && cs.conservationApplied()))
670    {
671  3 Conservation c = new Conservation(groupName, sequences, startRes,
672    endRes + 1);
673  3 c.calculate();
674  3 c.verdict(false, consPercGaps);
675  3 if (conservation != null)
676    {
677  0 _updateConservationRow(c);
678    }
679  3 if (cs != null)
680    {
681  3 if (cs.conservationApplied())
682    {
683  3 cs.setConservation(c);
684    }
685    }
686    // eager update - will cause a refresh of overview regardless
687  3 upd = true;
688    }
689  381 if (cs != null && !defer)
690    {
691    // TODO: JAL-2034 should cs.alignmentChanged modify return state
692  381 cs.alignmentChanged(context != null ? context : this, null);
693  381 return true;
694    }
695    else
696    {
697  0 return upd;
698    }
699    } catch (java.lang.OutOfMemoryError err)
700    {
701    // TODO: catch OOM
702  0 jalview.bin.Console
703    .outPrintln("Out of memory loading groups: " + err);
704    }
705  0 return upd;
706    }
707   
 
708  0 toggle private void _updateConservationRow(Conservation c)
709    {
710  0 if (conservation == null)
711    {
712  0 getConservation();
713    }
714    // update Labels
715  0 conservation.label = "Conservation for " + getName();
716  0 conservation.description = "Conservation for group " + getName()
717    + " less than " + consPercGaps + "% gaps";
718    // preserve width if already set
719  0 int aWidth = (conservation.annotations != null)
720  0 ? (endRes < conservation.annotations.length
721    ? conservation.annotations.length
722    : endRes + 1)
723    : endRes + 1;
724  0 conservation.annotations = null;
725  0 conservation.annotations = new Annotation[aWidth]; // should be alignment
726    // width
727  0 c.completeAnnotations(conservation, null, startRes, endRes + 1);
728    }
729   
730    public ProfilesI consensusData = null;
731   
 
732  120 toggle private void _updateConsensusRow(ProfilesI cnsns, long nseq)
733    {
734  120 if (consensus == null)
735    {
736  0 getConsensus();
737    }
738  120 consensus.label = "Consensus for " + getName();
739  120 consensus.description = "Percent Identity";
740  120 consensusData = cnsns;
741    // preserve width if already set
742  120 int aWidth = (consensus.annotations != null)
743  120 ? (endRes < consensus.annotations.length
744    ? consensus.annotations.length
745    : endRes + 1)
746    : endRes + 1;
747  120 consensus.annotations = null;
748  120 consensus.annotations = new Annotation[aWidth]; // should be alignment width
749   
750  120 AAFrequency.completeConsensus(consensus, cnsns, startRes, endRes + 1,
751    ignoreGapsInConsensus, showSequenceLogo, nseq); // TODO: setting
752    // container
753    // for
754    // ignoreGapsInConsensusCalculation);
755    }
756   
757    /**
758    * Updates the secondary structure consensus row based on the provided
759    * profiles map and the number of sequences.
760    *
761    * @param hSSConsensusProfileMap
762    * A map containing secondary structure consensus profiles for each
763    * providers.
764    * @param nseq
765    * The number of sequences.
766    */
 
767  0 toggle private void _updateSSConsensusRow(
768    Map<String, ProfilesI> hSSConsensusProfileMap, long nseq)
769    {
770    // Get a list of secondary structure sources from the profile map keys
771  0 List<String> ssSources = new ArrayList<>(
772    hSSConsensusProfileMap.keySet());
773  0 secondaryStructureSources = new ArrayList<String>();
774   
775    // Sort the secondary structure sources alphabetically
776  0 Collections.sort(ssSources);
777   
778    // Initialize ssConsensus if it is null
779  0 if (ssConsensus == null)
780    {
781  0 getSSConsensus(ssSources);
782    }
783   
784    // Iterate through each alignment annotation in the ssConsensus list
785  0 for (AlignmentAnnotation aa : ssConsensus)
786    {
787  0 ProfilesI profile = null;
788  0 String ssSource = null;
789   
790    // Find the matching profile for the current annotation based on its
791    // description
792  0 for (String source : ssSources)
793    {
794  0 if (aa.description.startsWith(source))
795    {
796  0 profile = hSSConsensusProfileMap.get(source);
797  0 ssSource = source;
798    }
799    }
800   
801    // If no matching profile is found, continue to the next annotation
802  0 if (profile == null)
803    {
804  0 continue;
805    }
806   
807    // Update the label and description of the annotation with the
808    // source/provider
809  0 aa.label = Constants.SECONDARY_STRUCTURE_CONSENSUS_LABEL + " "
810    + ssSource + " " + getName();
811  0 aa.description = ssSource
812    + Constants.SECONDARY_STRUCTURE_CONSENSUS_LABEL + " for "
813    + getName();
814   
815    // Get the width of the annotations array
816  0 int aWidth = (aa.annotations != null)
817  0 ? (endRes < aa.annotations.length ? aa.annotations.length
818    : endRes + 1)
819    : endRes + 1;
820  0 aa.annotations = new Annotation[aWidth];
821   
822    // Complete the secondary structure consensus
823  0 AAFrequency.completeSSConsensus(aa, profile, startRes, endRes + 1,
824    ignoreGapsInConsensus, showSequenceLogo, nseq);
825   
826    // Add the provider to the list if the no of sequences
827    // contributed to the secondary structure consensus is
828    // more than 0.
829  0 if (aa.getNoOfSequencesIncluded() > 0
830    && !Constants.SS_ALL_PROVIDERS.equals(ssSource))
831    {
832    // Remove "All" from the hidden types list{
833  0 secondaryStructureSources.add(ssSource);
834    }
835    }
836    }
837   
838    /**
839    * @param s
840    * sequence to either add or remove from group
841    * @param recalc
842    * flag passed to delete/addSequence to indicate if group properties
843    * should be recalculated
844    */
 
845  4 toggle public void addOrRemove(SequenceI s, boolean recalc)
846    {
847  4 synchronized (sequences)
848    {
849  4 if (sequences.contains(s))
850    {
851  1 deleteSequence(s, recalc);
852    }
853    else
854    {
855  3 addSequence(s, recalc);
856    }
857    }
858    }
859   
860    /**
861    * remove
862    *
863    * @param s
864    * to be removed
865    * @param recalc
866    * true means recalculate conservation
867    */
 
868  35 toggle public void deleteSequence(SequenceI s, boolean recalc)
869    {
870  35 synchronized (sequences)
871    {
872  35 sequences.remove(s);
873  35 changeSupport.firePropertyChange(SEQ_GROUP_CHANGED,
874    sequences.size() + 1, sequences.size());
875   
876  35 if (recalc)
877    {
878  0 recalcConservation();
879    }
880    }
881    }
882   
883    /**
884    *
885    *
886    * @return the first column selected by this group. Runs from 0<=i<N_cols
887    */
 
888  849281 toggle @Override
889    public int getStartRes()
890    {
891  849282 return startRes;
892    }
893   
894    /**
895    *
896    * @return the groups last selected column. Runs from 0<=i<N_cols
897    */
 
898  742047 toggle @Override
899    public int getEndRes()
900    {
901  742051 return endRes;
902    }
903   
904    /**
905    * Set the first column selected by this group. Runs from 0<=i<N_cols
906    *
907    * @param newStart
908    */
 
909  91 toggle public void setStartRes(int newStart)
910    {
911  91 int before = startRes;
912  91 startRes = Math.max(0, newStart); // sanity check for negative start column
913    // positions
914  91 changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, startRes);
915   
916    }
917   
918    /**
919    * Set the groups last selected column. Runs from 0<=i<N_cols
920    *
921    * @param i
922    */
 
923  112 toggle public void setEndRes(int i)
924    {
925  112 int before = endRes;
926  112 endRes = i;
927  112 changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, endRes);
928    }
929   
930    /**
931    * @return number of sequences in group
932    */
 
933  466 toggle public int getSize()
934    {
935  466 return sequences.size();
936    }
937   
938    /**
939    * @param i
940    * @return the ith sequence
941    */
 
942  58 toggle public SequenceI getSequenceAt(int i)
943    {
944  58 return sequences.get(i);
945    }
946   
947    /**
948    * @param state
949    * colourText
950    */
 
951  18 toggle public void setColourText(boolean state)
952    {
953  18 colourText = state;
954    }
955   
956    /**
957    * DOCUMENT ME!
958    *
959    * @return DOCUMENT ME!
960    */
 
961  275415 toggle public boolean getColourText()
962    {
963  275415 return colourText;
964    }
965   
966    /**
967    * DOCUMENT ME!
968    *
969    * @param state
970    * DOCUMENT ME!
971    */
 
972  14 toggle public void setDisplayText(boolean state)
973    {
974  14 displayText = state;
975    }
976   
977    /**
978    * DOCUMENT ME!
979    *
980    * @return DOCUMENT ME!
981    */
 
982  275400 toggle public boolean getDisplayText()
983    {
984  275400 return displayText;
985    }
986   
987    /**
988    * DOCUMENT ME!
989    *
990    * @param state
991    * DOCUMENT ME!
992    */
 
993  14 toggle public void setDisplayBoxes(boolean state)
994    {
995  14 displayBoxes = state;
996    }
997   
998    /**
999    * DOCUMENT ME!
1000    *
1001    * @return DOCUMENT ME!
1002    */
 
1003  275409 toggle public boolean getDisplayBoxes()
1004    {
1005  275409 return displayBoxes;
1006    }
1007   
1008    /**
1009    * computes the width of current set of sequences and returns it
1010    *
1011    * @return DOCUMENT ME!
1012    */
 
1013  741 toggle @Override
1014    public int getWidth()
1015    {
1016  741 synchronized (sequences)
1017    {
1018    // MC This needs to get reset when characters are inserted and deleted
1019  741 boolean first = true;
1020  741 for (SequenceI seq : sequences)
1021    {
1022  2460 if (first || seq.getLength() > width)
1023    {
1024  741 width = seq.getLength();
1025  741 first = false;
1026    }
1027    }
1028  741 return width;
1029    }
1030    }
1031   
1032    /**
1033    * DOCUMENT ME!
1034    *
1035    * @param c
1036    * DOCUMENT ME!
1037    */
 
1038  69 toggle public void setOutlineColour(Color c)
1039    {
1040  69 outlineColour = c;
1041    }
1042   
1043    /**
1044    * DOCUMENT ME!
1045    *
1046    * @return DOCUMENT ME!
1047    */
 
1048  1570 toggle public Color getOutlineColour()
1049    {
1050  1570 return outlineColour;
1051    }
1052   
1053    /**
1054    *
1055    * returns the sequences in the group ordered by the ordering given by al.
1056    * this used to return an array with null entries regardless, new behaviour is
1057    * below. TODO: verify that this does not affect use in applet or application
1058    *
1059    * @param al
1060    * Alignment
1061    * @return SequenceI[] intersection of sequences in group with al, ordered by
1062    * al, or null if group does not intersect with al
1063    */
 
1064  121 toggle public SequenceI[] getSequencesInOrder(AlignmentI al)
1065    {
1066  121 return getSequencesInOrder(al, true);
1067    }
1068   
1069    /**
1070    * return an array representing the intersection of the group with al,
1071    * optionally returning an array the size of al.getHeight() where nulls mark
1072    * the non-intersected sequences
1073    *
1074    * @param al
1075    * @param trim
1076    * @return null or array
1077    */
 
1078  127 toggle public SequenceI[] getSequencesInOrder(AlignmentI al, boolean trim)
1079    {
1080  127 synchronized (sequences)
1081    {
1082  127 int sSize = sequences.size();
1083  127 int alHeight = al.getHeight();
1084   
1085  127 SequenceI[] seqs = new SequenceI[(trim) ? sSize : alHeight];
1086   
1087  127 int index = 0;
1088  975 for (int i = 0; i < alHeight && index < sSize; i++)
1089    {
1090  848 if (sequences.contains(al.getSequenceAt(i)))
1091    {
1092  281 seqs[(trim) ? index : i] = al.getSequenceAt(i);
1093  281 index++;
1094    }
1095    }
1096  127 if (index == 0)
1097    {
1098  57 return null;
1099    }
1100  70 if (!trim)
1101    {
1102  0 return seqs;
1103    }
1104  70 if (index < seqs.length)
1105    {
1106  0 SequenceI[] dummy = seqs;
1107  0 seqs = new SequenceI[index];
1108  0 while (--index >= 0)
1109    {
1110  0 seqs[index] = dummy[index];
1111  0 dummy[index] = null;
1112    }
1113    }
1114  70 return seqs;
1115    }
1116    }
1117   
1118    /**
1119    * @return the idColour
1120    */
 
1121  18 toggle public Color getIdColour()
1122    {
1123  18 return idColour;
1124    }
1125   
1126    /**
1127    * @param idColour
1128    * the idColour to set
1129    */
 
1130  7 toggle public void setIdColour(Color idColour)
1131    {
1132  7 this.idColour = idColour;
1133    }
1134   
1135    /**
1136    * @return the representative sequence for this group
1137    */
 
1138  275374 toggle @Override
1139    public SequenceI getSeqrep()
1140    {
1141  275374 return seqrep;
1142    }
1143   
1144    /**
1145    * set the representative sequence for this group. Note - this affects the
1146    * interpretation of the Hidereps attribute.
1147    *
1148    * @param seqrep
1149    * the seqrep to set (null means no sequence representative)
1150    */
 
1151  17 toggle @Override
1152    public void setSeqrep(SequenceI seqrep)
1153    {
1154  17 this.seqrep = seqrep;
1155    }
1156   
1157    /**
1158    *
1159    * @return true if group has a sequence representative
1160    */
 
1161  6 toggle @Override
1162    public boolean hasSeqrep()
1163    {
1164  6 return seqrep != null;
1165    }
1166   
1167    /**
1168    * set visibility of sequences covered by (if no sequence representative is
1169    * defined) or represented by this group.
1170    *
1171    * @param visibility
1172    */
 
1173  6 toggle public void setHidereps(boolean visibility)
1174    {
1175  6 hidereps = visibility;
1176    }
1177   
1178    /**
1179    *
1180    * @return true if sequences represented (or covered) by this group should be
1181    * hidden
1182    */
 
1183  8 toggle public boolean isHidereps()
1184    {
1185  8 return hidereps;
1186    }
1187   
1188    /**
1189    * set intended visibility of columns covered by this group
1190    *
1191    * @param visibility
1192    */
 
1193  1 toggle public void setHideCols(boolean visibility)
1194    {
1195  1 hidecols = visibility;
1196    }
1197   
1198    /**
1199    *
1200    * @return true if columns covered by group should be hidden
1201    */
 
1202  8 toggle public boolean isHideCols()
1203    {
1204  8 return hidecols;
1205    }
1206   
1207    /**
1208    * create a new sequence group from the intersection of this group with an
1209    * alignment Hashtable of hidden representatives
1210    *
1211    * @param alignment
1212    * (may not be null)
1213    * @param map
1214    * (may be null)
1215    * @return new group containing sequences common to this group and alignment
1216    */
 
1217  57 toggle public SequenceGroup intersect(AlignmentI alignment,
1218    Map<SequenceI, SequenceCollectionI> map)
1219    {
1220  57 SequenceGroup sgroup = new SequenceGroup(this);
1221  57 SequenceI[] insect = getSequencesInOrder(alignment);
1222  57 sgroup.sequences = new ArrayList<>();
1223  57 for (int s = 0; insect != null && s < insect.length; s++)
1224    {
1225  0 if (map == null || map.containsKey(insect[s]))
1226    {
1227  0 sgroup.sequences.add(insect[s]);
1228    }
1229    }
1230  57 return sgroup;
1231    }
1232   
1233    /**
1234    * @return the showUnconserved
1235    */
 
1236  270885 toggle public boolean getShowNonconserved()
1237    {
1238  270885 return showNonconserved;
1239    }
1240   
1241    /**
1242    * @param showNonconserved
1243    * the showUnconserved to set
1244    */
 
1245  74 toggle public void setShowNonconserved(boolean displayNonconserved)
1246    {
1247  74 this.showNonconserved = displayNonconserved;
1248    }
1249   
1250    /**
1251    * set this alignmentAnnotation object as the one used to render consensus
1252    * annotation
1253    *
1254    * @param aan
1255    */
 
1256  24 toggle public void setConsensus(AlignmentAnnotation aan)
1257    {
1258  24 if (consensus == null)
1259    {
1260  24 consensus = aan;
1261    }
1262    }
1263   
 
1264  0 toggle public void setSSConsensusRow(AlignmentAnnotation aan)
1265    {
1266   
1267  0 if (ssConsensus == null)
1268    {
1269  0 ssConsensus = new ArrayList<AlignmentAnnotation>();
1270  0 ssConsensus.add(aan);
1271    }
1272    else
1273    {
1274  0 boolean annotExists = ssConsensus.stream()
1275    .anyMatch(ssa -> ssa.label.equals(aan.label));
1276  0 if (!annotExists)
1277    {
1278  0 ssConsensus.add(aan);
1279    }
1280    }
1281    }
1282   
1283    /**
1284    *
1285    * @return automatically calculated consensus row note: the row is a stub if a
1286    * consensus calculation has not yet been performed on the group
1287    */
 
1288  735 toggle public AlignmentAnnotation getConsensus()
1289    {
1290    // TODO get or calculate and get consensus annotation row for this group
1291  735 int aWidth = this.getWidth();
1292    // pointer
1293    // possibility
1294    // here.
1295  735 if (aWidth < 0)
1296    {
1297  0 return null;
1298    }
1299  735 if (consensus == null)
1300    {
1301  0 consensus = new AlignmentAnnotation("", "", new Annotation[1], 0f,
1302    100f, AlignmentAnnotation.BAR_GRAPH);
1303  0 consensus.hasText = true;
1304  0 consensus.autoCalculated = true;
1305  0 consensus.groupRef = this;
1306  0 consensus.label = "Consensus for " + getName();
1307  0 consensus.description = "Percent Identity";
1308    }
1309  735 return consensus;
1310    }
1311   
 
1312  0 toggle public List<AlignmentAnnotation> getSSConsensus(List<String> ssSources)
1313    {
1314    // TODO get or calculate and get consensus annotation row for this group
1315  0 int aWidth = this.getWidth();
1316    // pointer
1317    // possibility
1318    // here.
1319  0 if (aWidth < 0)
1320    {
1321  0 return null;
1322    }
1323  0 if (ssConsensus == null && ssSources != null)
1324    {
1325  0 ssConsensus = new ArrayList<AlignmentAnnotation>();
1326   
1327  0 for (String ssSource : ssSources)
1328    {
1329  0 AlignmentAnnotation aa = new AlignmentAnnotation("", "",
1330    new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
1331    // Setting the annotation visibility to true of the provider is "All"
1332    // and false otherwise.
1333  0 aa.visible = Constants.SS_ALL_PROVIDERS.equals(ssSource);
1334  0 aa.hasText = true;
1335  0 aa.autoCalculated = true;
1336  0 aa.groupRef = this;
1337   
1338  0 aa.label = Constants.SECONDARY_STRUCTURE_CONSENSUS_LABEL + " "
1339    + ssSource + " " + getName();
1340  0 aa.description = ssSource
1341    + Constants.SECONDARY_STRUCTURE_CONSENSUS_LABEL + " for "
1342    + getName();
1343  0 ssConsensus.add(aa);
1344    }
1345   
1346    }
1347  0 return ssConsensus;
1348    }
1349   
1350    /**
1351    * set this alignmentAnnotation object as the one used to render consensus
1352    * annotation
1353    *
1354    * @param aan
1355    */
 
1356  0 toggle public void setConservationRow(AlignmentAnnotation aan)
1357    {
1358  0 if (conservation == null)
1359    {
1360  0 conservation = aan;
1361    }
1362    }
1363   
1364    /**
1365    * get the conservation annotation row for this group
1366    *
1367    * @return autoCalculated annotation row
1368    */
 
1369  0 toggle public AlignmentAnnotation getConservationRow()
1370    {
1371  0 if (conservation == null)
1372    {
1373  0 conservation = new AlignmentAnnotation("", "", new Annotation[1], 0f,
1374    11f, AlignmentAnnotation.BAR_GRAPH);
1375    }
1376   
1377  0 conservation.hasText = true;
1378  0 conservation.autoCalculated = true;
1379  0 conservation.groupRef = this;
1380  0 conservation.label = "Conservation for " + getName();
1381  0 conservation.description = "Conservation for group " + getName()
1382    + " less than " + consPercGaps + "% gaps";
1383  0 return conservation;
1384    }
1385   
1386    /**
1387    *
1388    * @return true if annotation rows have been instantiated for this group
1389    */
 
1390  0 toggle public boolean hasAnnotationRows()
1391    {
1392  0 return consensus != null || conservation != null;
1393    }
1394   
 
1395  0 toggle public SequenceI getConsensusSeq()
1396    {
1397  0 getConsensus();
1398  0 StringBuffer seqs = new StringBuffer();
1399  0 for (int i = 0; i < consensus.annotations.length; i++)
1400    {
1401  0 if (consensus.annotations[i] != null)
1402    {
1403  0 String desc = consensus.annotations[i].description;
1404  0 if (desc.length() > 1 && desc.charAt(0) == '[')
1405    {
1406  0 seqs.append(desc.charAt(1));
1407    }
1408    else
1409    {
1410  0 seqs.append(consensus.annotations[i].displayCharacter);
1411    }
1412    }
1413    }
1414   
1415  0 SequenceI sq = new Sequence("Group" + getName() + " Consensus",
1416    seqs.toString());
1417  0 sq.setDescription("Percentage Identity Consensus "
1418  0 + ((ignoreGapsInConsensus) ? " without gaps" : ""));
1419  0 return sq;
1420    }
1421   
 
1422  48 toggle public void setIgnoreGapsConsensus(boolean state)
1423    {
1424  48 if (this.ignoreGapsInConsensus != state && consensus != null)
1425    {
1426  0 ignoreGapsInConsensus = state;
1427  0 recalcConservation();
1428    }
1429  48 ignoreGapsInConsensus = state;
1430    }
1431   
 
1432  44566 toggle public boolean getIgnoreGapsConsensus()
1433    {
1434  44566 return ignoreGapsInConsensus;
1435    }
1436   
1437    /**
1438    * @param showSequenceLogo
1439    * indicates if a sequence logo is shown for consensus annotation
1440    */
 
1441  57 toggle public void setshowSequenceLogo(boolean showSequenceLogo)
1442    {
1443    // TODO: decouple calculation from settings update
1444  57 if (this.showSequenceLogo != showSequenceLogo && consensus != null)
1445    {
1446  0 this.showSequenceLogo = showSequenceLogo;
1447  0 recalcConservation();
1448    }
1449  57 this.showSequenceLogo = showSequenceLogo;
1450    }
1451   
1452    /**
1453    *
1454    * @param showConsHist
1455    * flag indicating if the consensus histogram for this group should
1456    * be rendered
1457    */
 
1458  57 toggle public void setShowConsensusHistogram(boolean showConsHist)
1459    {
1460   
1461  57 if (showConsensusHistogram != showConsHist && consensus != null)
1462    {
1463  0 this.showConsensusHistogram = showConsHist;
1464  0 recalcConservation();
1465    }
1466  57 this.showConsensusHistogram = showConsHist;
1467    }
1468   
1469   
1470    /**
1471    * @return the showConsensusHistogram
1472    */
 
1473  728 toggle public boolean isShowConsensusHistogram()
1474    {
1475  728 return showConsensusHistogram;
1476    }
1477   
1478    /**
1479    * set flag indicating if logo should be normalised when rendered
1480    *
1481    * @param norm
1482    */
 
1483  57 toggle public void setNormaliseSequenceLogo(boolean norm)
1484    {
1485  57 normaliseSequenceLogo = norm;
1486    }
1487   
 
1488  728 toggle public boolean isNormaliseSequenceLogo()
1489    {
1490  728 return normaliseSequenceLogo;
1491    }
1492   
 
1493  0 toggle @Override
1494    /**
1495    * returns a new array with all annotation involving this group
1496    */
1497    public AlignmentAnnotation[] getAlignmentAnnotation()
1498    {
1499    // TODO add in other methods like 'getAlignmentAnnotation(String label),
1500    // etc'
1501  0 ArrayList<AlignmentAnnotation> annot = new ArrayList<>();
1502  0 synchronized (sequences)
1503    {
1504  0 for (SequenceI seq : sequences)
1505    {
1506  0 AlignmentAnnotation[] aa = seq.getAnnotation();
1507  0 if (aa != null)
1508    {
1509  0 for (AlignmentAnnotation al : aa)
1510    {
1511  0 if (al.groupRef == this)
1512    {
1513  0 annot.add(al);
1514    }
1515    }
1516    }
1517    }
1518  0 if (consensus != null)
1519    {
1520  0 annot.add(consensus);
1521    }
1522  0 if (conservation != null)
1523    {
1524  0 annot.add(conservation);
1525    }
1526    }
1527  0 return annot.toArray(new AlignmentAnnotation[0]);
1528    }
1529   
 
1530  0 toggle @Override
1531    public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
1532    {
1533  0 return AlignmentAnnotation.findAnnotation(
1534    Arrays.asList(getAlignmentAnnotation()), calcId);
1535    }
1536   
 
1537  0 toggle @Override
1538    public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
1539    String calcId, String label)
1540    {
1541  0 return AlignmentAnnotation.findAnnotations(
1542    Arrays.asList(getAlignmentAnnotation()), seq, calcId, label);
1543    }
1544   
1545    /**
1546    * Answer true if any annotation matches the calcId passed in (if not null).
1547    *
1548    * @param calcId
1549    * @return
1550    */
 
1551  0 toggle public boolean hasAnnotation(String calcId)
1552    {
1553  0 return AlignmentAnnotation
1554    .hasAnnotation(Arrays.asList(getAlignmentAnnotation()), calcId);
1555    }
1556   
1557    /**
1558    * Remove all sequences from the group (leaving other properties unchanged).
1559    */
 
1560  15 toggle public void clear()
1561    {
1562  15 synchronized (sequences)
1563    {
1564  15 int before = sequences.size();
1565  15 sequences.clear();
1566  15 changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before,
1567    sequences.size());
1568    }
1569    }
1570   
1571    /**
1572    * Sets the alignment or group context for this group, and whether it is
1573    * defined as a group
1574    *
1575    * @param ctx
1576    * the context for the group
1577    * @param defined
1578    * whether the group is defined on the alignment or is just a
1579    * selection
1580    * @throws IllegalArgumentException
1581    * if setting the context would result in a circular reference chain
1582    */
 
1583  107 toggle public void setContext(AnnotatedCollectionI ctx, boolean defined)
1584    {
1585  107 setContext(ctx);
1586  106 this.isDefined = defined;
1587    }
1588   
1589    /**
1590    * Sets the alignment or group context for this group
1591    *
1592    * @param ctx
1593    * the context for the group
1594    * @throws IllegalArgumentException
1595    * if setting the context would result in a circular reference chain
1596    */
 
1597  151 toggle public void setContext(AnnotatedCollectionI ctx)
1598    {
1599  151 AnnotatedCollectionI ref = ctx;
1600  397 while (ref != null)
1601    {
1602  249 if (ref == this || ref.getContext() == ctx)
1603    {
1604  3 throw new IllegalArgumentException(
1605    "Circular reference in SequenceGroup.context");
1606    }
1607  246 ref = ref.getContext();
1608    }
1609  148 this.context = ctx;
1610    }
1611   
1612    /*
1613    * (non-Javadoc)
1614    *
1615    * @see jalview.datamodel.AnnotatedCollectionI#getContext()
1616    */
 
1617  517 toggle @Override
1618    public AnnotatedCollectionI getContext()
1619    {
1620  517 return context;
1621    }
1622   
 
1623  9 toggle public boolean isDefined()
1624    {
1625  9 return isDefined;
1626    }
1627   
 
1628  51 toggle public void setColourScheme(ColourSchemeI scheme)
1629    {
1630  51 if (cs == null)
1631    {
1632  1 cs = new ResidueShader();
1633    }
1634  51 cs.setColourScheme(scheme);
1635    }
1636   
 
1637  2 toggle public void setGroupColourScheme(ResidueShaderI scheme)
1638    {
1639  2 cs = scheme;
1640    }
1641   
 
1642  73 toggle public ColourSchemeI getColourScheme()
1643    {
1644  73 return cs == null ? null : cs.getColourScheme();
1645    }
1646   
 
1647  411597 toggle public ResidueShaderI getGroupColourScheme()
1648    {
1649  411597 return cs;
1650    }
1651   
 
1652  72 toggle @Override
1653    public boolean isNucleotide()
1654    {
1655  72 if (context != null)
1656    {
1657  72 return context.isNucleotide();
1658    }
1659  0 return false;
1660    }
1661   
1662    /**
1663    * @param seq
1664    * @return true if seq is a member of the group
1665    */
1666   
 
1667  35 toggle public boolean contains(SequenceI seq1)
1668    {
1669  35 return sequences.contains(seq1);
1670    }
1671   
1672    /**
1673    * @param seq
1674    * @param apos
1675    * @return true if startRes<=apos and endRes>=apos and seq is in the group
1676    */
 
1677  15 toggle public boolean contains(SequenceI seq, int apos)
1678    {
1679  15 return (startRes <= apos && endRes >= apos) && sequences.contains(seq);
1680    }
1681   
1682    ////
1683    //// Contact Matrix Holder Boilerplate
1684    ////
1685    ContactMapHolder cmholder = new ContactMapHolder();
1686   
 
1687  0 toggle @Override
1688    public Collection<ContactMatrixI> getContactMaps()
1689    {
1690  0 return cmholder.getContactMaps();
1691    }
1692   
 
1693  0 toggle @Override
1694    public ContactMatrixI getContactMatrixFor(AlignmentAnnotation ann)
1695    {
1696  0 return cmholder.getContactMatrixFor(ann);
1697    }
1698   
 
1699  0 toggle @Override
1700    public ContactListI getContactListFor(AlignmentAnnotation _aa, int column)
1701    {
1702  0 return cmholder.getContactListFor(_aa, column);
1703    }
1704   
 
1705  0 toggle @Override
1706    public AlignmentAnnotation addContactList(ContactMatrixI cm)
1707    {
1708  0 AlignmentAnnotation aa = cmholder.addContactList(cm);
1709   
1710  0 Annotation _aa[] = new Annotation[getWidth()];
1711  0 Annotation dummy = new Annotation(0.0f);
1712  0 for (int i = 0; i < _aa.length; _aa[i++] = dummy)
1713    {
1714  0 ;
1715    }
1716  0 aa.annotations = _aa;
1717    // TODO passing annotations back to context to be added
1718  0 return aa;
1719    }
1720   
 
1721  0 toggle @Override
1722    public void addContactListFor(AlignmentAnnotation annotation,
1723    ContactMatrixI cm)
1724    {
1725  0 cmholder.addContactListFor(annotation, cm);
1726    }
1727   
1728    }