Clover icon

Coverage Report

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

File SequenceGroup.java

 

Coverage histogram

../../img/srcFileCovDistChart5.png
33% of files have more coverage

Code metrics

188
425
99
1
1,756
1,078
215
0.51
4.29
99
2.17

Classes

Class Line # Actions
SequenceGroup 48 425 215
0.4859550648.6%
 

Contributing tests

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