1. Project Clover database Fri Dec 6 2024 13:47:14 GMT
  2. Package jalview.datamodel

File SequenceGroup.java

 

Coverage histogram

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

Code metrics

186
425
101
1
1,764
1,086
214
0.5
4.21
101
2.12

Classes

Class
Line #
Actions
SequenceGroup 48 425 214
0.5463483354.6%
 

Contributing tests

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