Clover icon

Coverage Report

  1. Project Clover database Mon Nov 11 2024 20:42:03 GMT
  2. Package jalview.datamodel

File AlignmentView.java

 

Coverage histogram

../../img/srcFileCovDistChart4.png
49% of files have more coverage

Code metrics

240
423
29
2
1,240
935
178
0.42
14.59
14.5
6.14

Classes

Class Line # Actions
AlignmentView 35 412 172
0.34621134.6%
AlignmentView.ScGroup 69 11 6
0.4210526342.1%
 

Contributing tests

This file is covered by 16 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 jalview.util.MessageManager;
24    import jalview.util.ShiftList;
25   
26    import java.io.PrintStream;
27    import java.util.ArrayList;
28    import java.util.List;
29   
30    /**
31    * Transient object compactly representing a 'view' of an alignment - with
32    * discontinuities marked. Extended in Jalview 2.7 to optionally record sequence
33    * groups and specific selected regions on the alignment.
34    */
 
35    public class AlignmentView
36    {
37    private SeqCigar[] sequences = null;
38   
39    private int[] contigs = null;
40   
41    private int width = 0;
42   
43    private int firstCol = 0;
44   
45    /**
46    * one or more ScGroup objects, which are referenced by each seqCigar's group
47    * membership
48    */
49    private List<ScGroup> scGroups = null;
50   
51    private boolean isNa = false;
52   
53    /**
54    * false if the view concerns peptides
55    *
56    * @return
57    */
 
58  0 toggle public boolean isNa()
59    {
60  0 return isNa;
61    }
62   
63    /**
64    * Group defined over SeqCigars. Unlike AlignmentI associated groups, each
65    * SequenceGroup hold just the essential properties for the group, but no
66    * references to the sequences involved. SeqCigars hold references to the
67    * seuqenceGroup entities themselves.
68    */
 
69    private class ScGroup
70    {
71    public List<SeqCigar> seqs;
72   
73    public SequenceGroup sg;
74   
 
75  11 toggle ScGroup()
76    {
77  11 seqs = new ArrayList<>();
78    }
79   
80    /**
81    * @param seq
82    * @return true if seq was not a member before and was added to group
83    */
 
84  33 toggle public boolean add(SeqCigar seq)
85    {
86  33 if (!seq.isMemberOf(this))
87    {
88  33 seqs.add(seq);
89  33 seq.setGroupMembership(this);
90  33 return true;
91    }
92    else
93    {
94  0 return false;
95    }
96    }
97   
98    /**
99    *
100    * @param seq
101    * @return true if seq was a member and was removed from group
102    */
 
103  0 toggle public boolean remove(SeqCigar seq)
104    {
105  0 if (seq.removeGroupMembership(this))
106    {
107  0 seqs.remove(seq);
108  0 return true;
109    }
110  0 return false;
111    }
112   
 
113  0 toggle public int size()
114    {
115  0 return seqs.size();
116    }
117    }
118   
119    /**
120    * vector of selected seqCigars. This vector is also referenced by each
121    * seqCigar contained in it.
122    */
123    private ScGroup selected;
124   
125    /**
126    * Construct an alignmentView from a live jalview alignment view. Note -
127    * hidden rows will be excluded from alignmentView Note: JAL-1179
128    *
129    * @param alignment
130    * - alignment as referenced by an AlignViewport
131    * @param columnSelection
132    * -
133    * @param selection
134    * @param hasHiddenColumns
135    * - mark the hidden columns in columnSelection as hidden in the view
136    * @param selectedRegionOnly
137    * - when set, only include the selected region in the view,
138    * otherwise just mark the selected region on the constructed view.
139    * @param recordGroups
140    * - when set, any groups on the given alignment will be marked on
141    * the view
142    */
 
143  24 toggle public AlignmentView(AlignmentI alignment, HiddenColumns hidden,
144    SequenceGroup selection, boolean hasHiddenColumns,
145    boolean selectedRegionOnly, boolean recordGroups)
146    {
147    // refactored from AlignViewport.getAlignmentView(selectedOnly);
148  24 this(new jalview.datamodel.CigarArray(alignment,
149  24 (hasHiddenColumns ? hidden : null),
150  24 (selectedRegionOnly ? selection : null)),
151  24 (selectedRegionOnly && selection != null)
152    ? selection.getStartRes()
153    : 0);
154  24 isNa = alignment.isNucleotide();
155    // walk down SeqCigar array and Alignment Array - optionally restricted by
156    // selected region.
157    // test group membership for each sequence in each group, store membership
158    // and record non-empty groups in group list.
159    // record / sub-select selected region on the alignment view
160  24 SequenceI[] selseqs;
161  24 if (selection != null && selection.getSize() > 0)
162    {
163  6 this.selected = new ScGroup();
164  6 selseqs = selection.getSequencesInOrder(alignment,
165    selectedRegionOnly);
166    }
167    else
168    {
169  18 selseqs = alignment.getSequencesArray();
170    }
171   
172  24 List<List<SequenceI>> seqsets = new ArrayList<>();
173    // get the alignment's group list and make a copy
174  24 List<SequenceGroup> grps = new ArrayList<>();
175  24 List<SequenceGroup> gg = alignment.getGroups();
176  24 grps.addAll(gg);
177  24 ScGroup[] sgrps = null;
178  24 boolean addedgps[] = null;
179  24 if (grps != null)
180    {
181  24 if (selection != null && selectedRegionOnly)
182    {
183    // trim annotation to the region being stored.
184    // strip out any groups that do not actually intersect with the
185    // visible and selected region
186  6 int ssel = selection.getStartRes(), esel = selection.getEndRes();
187  6 List<SequenceGroup> isg = new ArrayList<>();
188  6 for (SequenceGroup sg : grps)
189    {
190  0 if (!(sg.getStartRes() > esel || sg.getEndRes() < ssel))
191    {
192    // adjust bounds of new group, if necessary.
193  0 if (sg.getStartRes() < ssel)
194    {
195  0 sg.setStartRes(ssel);
196    }
197  0 if (sg.getEndRes() > esel)
198    {
199  0 sg.setEndRes(esel);
200    }
201  0 sg.setStartRes(sg.getStartRes() - ssel + 1);
202  0 sg.setEndRes(sg.getEndRes() - ssel + 1);
203   
204  0 isg.add(sg);
205    }
206    }
207  6 grps = isg;
208    }
209   
210  24 sgrps = new ScGroup[grps.size()];
211  24 addedgps = new boolean[grps.size()];
212  29 for (int g = 0; g < sgrps.length; g++)
213    {
214  5 SequenceGroup sg = grps.get(g);
215  5 sgrps[g] = new ScGroup();
216  5 sgrps[g].sg = new SequenceGroup(sg);
217  5 addedgps[g] = false;
218    // can't set entry 0 in an empty list
219    // seqsets.set(g, sg.getSequences(null));
220  5 seqsets.add(sg.getSequences());
221    }
222    // seqsets now contains vectors (should be sets) for each group, so we can
223    // track when we've done with the group
224    }
225  24 int csi = 0;
226  125 for (int i = 0; i < selseqs.length; i++)
227    {
228  101 if (selseqs[i] != null)
229    {
230  101 if (selection != null && selection.getSize() > 0
231    && !selectedRegionOnly)
232    {
233  0 selected.add(sequences[csi]);
234    }
235  101 if (seqsets != null)
236    {
237  266 for (int sg = 0; sg < sgrps.length; sg++)
238    {
239  165 if ((seqsets.get(sg)).contains(selseqs[i]))
240    {
241  33 sgrps[sg].sg.deleteSequence(selseqs[i], false);
242  33 sgrps[sg].add(sequences[csi]);
243  33 if (!addedgps[sg])
244    {
245  5 if (scGroups == null)
246    {
247  1 scGroups = new ArrayList<>();
248    }
249  5 addedgps[sg] = true;
250  5 scGroups.add(sgrps[sg]);
251    }
252    }
253    }
254    }
255  101 csi++;
256    }
257    }
258    // finally, delete the remaining sequences (if any) not selected
259  29 for (int sg = 0; sg < sgrps.length; sg++)
260    {
261  5 SequenceI[] sqs = sgrps[sg].sg.getSequencesAsArray(null);
262  5 for (int si = 0; si < sqs.length; si++)
263    {
264  0 sgrps[sg].sg.deleteSequence(sqs[si], false);
265    }
266  5 sgrps[sg] = null;
267    }
268    }
269   
270    /**
271    * construct an alignmentView from a SeqCigarArray. Errors are thrown if the
272    * seqcigararray.isSeqCigarArray() flag is not set.
273    */
 
274  25 toggle public AlignmentView(CigarArray seqcigararray)
275    {
276  25 if (!seqcigararray.isSeqCigarArray())
277    {
278  0 throw new Error(
279    "Implementation Error - can only make an alignment view from a CigarArray of sequences.");
280    }
281    // contigs = seqcigararray.applyDeletions();
282  25 contigs = seqcigararray.getDeletedRegions();
283  25 sequences = seqcigararray.getSeqCigarArray();
284  25 width = seqcigararray.getWidth(); // visible width
285    }
286   
287    /**
288    * Create an alignmentView where the first column corresponds with the
289    * 'firstcol' column of some reference alignment
290    *
291    * @param sdata
292    * @param firstcol
293    */
 
294  24 toggle public AlignmentView(CigarArray sdata, int firstcol)
295    {
296  24 this(sdata);
297  24 firstCol = firstcol;
298    }
299   
 
300  3 toggle public void setSequences(SeqCigar[] sequences)
301    {
302  3 this.sequences = sequences;
303    }
304   
 
305  0 toggle public void setContigs(int[] contigs)
306    {
307  0 this.contigs = contigs;
308    }
309   
 
310  21 toggle public SeqCigar[] getSequences()
311    {
312  21 return sequences;
313    }
314   
315    /**
316    * @see CigarArray.getDeletedRegions
317    * @return int[] { vis_start, sym_start, length }
318    */
 
319  0 toggle public int[] getContigs()
320    {
321  0 return contigs;
322    }
323   
324    /**
325    * get the full alignment and a columnselection object marking the hidden
326    * regions
327    *
328    * @param gapCharacter
329    * char
330    * @return Object[] { SequenceI[], ColumnSelection}
331    */
 
332  3 toggle public Object[] getAlignmentAndHiddenColumns(char gapCharacter)
333    {
334  3 HiddenColumns hidden = new HiddenColumns();
335   
336  3 return new Object[] { SeqCigar.createAlignmentSequences(sequences,
337    gapCharacter, hidden, contigs),
338    hidden };
339    }
340   
341    /**
342    * return the visible alignment corresponding to this view. Sequences in this
343    * alignment are edited versions of the parent sequences - where hidden
344    * regions have been removed. NOTE: the sequence data in this alignment is not
345    * complete!
346    *
347    * @param c
348    * @return
349    */
 
350  2 toggle public AlignmentI getVisibleAlignment(char c)
351    {
352  2 SequenceI[] aln = getVisibleSeqs(c);
353   
354  2 AlignmentI vcal = new Alignment(aln);
355  2 addPrunedGroupsInOrder(vcal, -1, -1, true);
356  2 return vcal;
357    }
358   
359    /**
360    * add groups from view to the given alignment
361    *
362    * @param vcal
363    * @param gstart
364    * -1 or 0 to width-1
365    * @param gend
366    * -1 or gstart to width-1
367    * @param viscontigs
368    * - true if vcal is alignment of the visible regions of the view
369    * (e.g. as returned from getVisibleAlignment)
370    */
 
371  4 toggle private void addPrunedGroupsInOrder(AlignmentI vcal, int gstart, int gend,
372    boolean viscontigs)
373    {
374  4 boolean r = false;
375  4 if (gstart > -1 && gstart <= gend)
376    {
377  2 r = true;
378    }
379   
380  4 SequenceI[] aln = vcal.getSequencesArray();
381    {
382    /**
383    * prune any groups to the visible coordinates of the alignment.
384    */
385    {
386  4 int nvg = (scGroups != null) ? scGroups.size() : 0;
387  4 if (nvg > 0)
388    {
389  2 SequenceGroup[] nsg = new SequenceGroup[nvg];
390  12 for (int g = 0; g < nvg; g++)
391    {
392  10 SequenceGroup sg = scGroups.get(g).sg;
393  10 if (r)
394    {
395  10 if (sg.getStartRes() > gend || sg.getEndRes() < gstart)
396    {
397    // Skip this group
398  0 nsg[g] = null;
399  0 continue;
400    }
401    }
402   
403    // clone group properties
404  10 nsg[g] = new SequenceGroup(sg);
405   
406    // may need to shift/trim start and end ?
407  10 if (r && !viscontigs)
408    {
409    // Not fully tested code - routine not yet called with
410    // viscontigs==false
411  0 if (nsg[g].getStartRes() < gstart)
412    {
413  0 nsg[g].setStartRes(0);
414    }
415    else
416    {
417  0 nsg[g].setStartRes(nsg[g].getStartRes() - gstart);
418  0 nsg[g].setEndRes(nsg[g].getEndRes() - gstart);
419    }
420  0 if (nsg[g].getEndRes() > (gend - gstart))
421    {
422  0 nsg[g].setEndRes(gend - gstart);
423    }
424    }
425    }
426  2 if (viscontigs)
427    {
428    // prune groups to cover just the visible positions between
429    // gstart/gend.
430  2 if (contigs != null)
431    {
432  0 int p = 0;
433  0 ShiftList prune = new ShiftList();
434  0 if (r)
435    {
436    // adjust for start of alignment within visible window.
437  0 prune.addShift(gstart, -gstart); //
438    }
439  0 for (int h = 0; h < contigs.length; h += 3)
440    {
441    {
442  0 prune.addShift(p + contigs[h + 1],
443    contigs[h + 2] - contigs[h + 1]);
444    }
445  0 p = contigs[h + 1] + contigs[h + 2];
446    }
447  0 for (int g = 0; g < nsg.length; g++)
448    {
449  0 if (nsg[g] != null)
450    {
451  0 int s = nsg[g].getStartRes(), t = nsg[g].getEndRes();
452  0 int w = 1 + t - s;
453  0 if (r)
454    {
455  0 if (s < gstart)
456    {
457  0 s = gstart;
458    }
459  0 if (t > gend)
460    {
461  0 t = gend;
462    }
463    }
464  0 s = prune.shift(s);
465  0 t = prune.shift(t);
466  0 nsg[g].setStartRes(s);
467  0 nsg[g].setEndRes(t);
468    }
469    }
470    }
471    }
472   
473  68 for (int nsq = 0; nsq < aln.length; nsq++)
474    {
475  396 for (int g = 0; g < nvg; g++)
476    {
477  330 if (nsg[g] != null
478    && sequences[nsq].isMemberOf(scGroups.get(g)))
479    {
480  66 nsg[g].addSequence(aln[nsq], false);
481    }
482    }
483    }
484  12 for (int g = 0; g < nvg; g++)
485    {
486  10 if (nsg[g] != null && nsg[g].getSize() > 0)
487    {
488  10 vcal.addGroup(nsg[g]);
489    }
490  10 nsg[g] = null;
491    }
492    }
493    }
494    }
495    }
496   
497    /**
498    * generate sequence array corresponding to the visible parts of the
499    * alignment.
500    *
501    * @param c
502    * gap character to use to recreate the alignment
503    * @return
504    */
 
505  2 toggle private SequenceI[] getVisibleSeqs(char c)
506    {
507  2 SequenceI[] aln = new SequenceI[sequences.length];
508  5 for (int i = 0, j = sequences.length; i < j; i++)
509    {
510  3 aln[i] = sequences[i].getSeq(c);
511    // Remove hidden regions from sequence
512  3 aln[i].setSequence(getASequenceString(c, i));
513    }
514  2 return aln;
515    }
516   
517    /**
518    * creates new alignment objects for all contiguous visible segments
519    *
520    * @param c
521    * @param start
522    * @param end
523    * @param regionOfInterest
524    * specify which sequences to include (or null to include all
525    * sequences)
526    * @return AlignmentI[] - all alignments where each sequence is a subsequence
527    * constructed from visible contig regions of view
528    */
 
529  2 toggle public AlignmentI[] getVisibleContigAlignments(char c)
530    {
531  2 int nvc = 0;
532  2 int[] vcontigs = getVisibleContigs();
533  2 SequenceI[][] contigviews = getVisibleContigs(c);
534  2 AlignmentI[] vcals = new AlignmentI[contigviews.length];
535  4 for (nvc = 0; nvc < contigviews.length; nvc++)
536    {
537  2 vcals[nvc] = new Alignment(contigviews[nvc]);
538  2 if (scGroups != null && scGroups.size() > 0)
539    {
540  2 addPrunedGroupsInOrder(vcals[nvc], vcontigs[nvc * 2],
541    vcontigs[nvc * 2 + 1], true);
542    }
543    }
544  2 return vcals;
545    }
546   
547    /**
548    * build a string excluding hidden regions from a particular sequence in the
549    * view
550    *
551    * @param c
552    * @param n
553    * @return
554    */
 
555  24 toggle private String getASequenceString(char c, int n)
556    {
557  24 String sqn;
558  24 String fullseq = sequences[n].getSequenceString(c);
559  24 if (contigs != null)
560    {
561  0 sqn = "";
562  0 int p = 0;
563  0 for (int h = 0; h < contigs.length; h += 3)
564    {
565  0 sqn += fullseq.substring(p, contigs[h + 1]);
566  0 p = contigs[h + 1] + contigs[h + 2];
567    }
568  0 sqn += fullseq.substring(p);
569    }
570    else
571    {
572  24 sqn = fullseq;
573    }
574  24 return sqn;
575    }
576   
577    /**
578    * get an array of visible sequence strings for a view on an alignment using
579    * the given gap character uses getASequenceString
580    *
581    * @param c
582    * char
583    * @return String[]
584    */
 
585  5 toggle public String[] getSequenceStrings(char c)
586    {
587  5 String[] seqs = new String[sequences.length];
588  26 for (int n = 0; n < sequences.length; n++)
589    {
590  21 seqs[n] = getASequenceString(c, n);
591    }
592  5 return seqs;
593    }
594   
595    /**
596    *
597    * @return visible number of columns in alignment view
598    */
 
599  0 toggle public int getWidth()
600    {
601  0 return width;
602    }
603   
 
604  0 toggle protected void setWidth(int width)
605    {
606  0 this.width = width;
607    }
608   
609    /**
610    * get the contiguous subalignments in an alignment view.
611    *
612    * @param gapCharacter
613    * char
614    * @return SequenceI[][]
615    */
 
616  2 toggle public SequenceI[][] getVisibleContigs(char gapCharacter)
617    {
618  2 SequenceI[][] smsa;
619  2 int njobs = 1;
620  2 if (sequences == null || width <= 0)
621    {
622  0 return null;
623    }
624  2 if (contigs != null && contigs.length > 0)
625    {
626  0 int start = 0;
627  0 njobs = 0;
628  0 int fwidth = width;
629  0 for (int contig = 0; contig < contigs.length; contig += 3)
630    {
631  0 if ((contigs[contig + 1] - start) > 0)
632    {
633  0 njobs++;
634    }
635  0 fwidth += contigs[contig + 2]; // end up with full region width
636    // (including hidden regions)
637  0 start = contigs[contig + 1] + contigs[contig + 2];
638    }
639  0 if (start < fwidth)
640    {
641  0 njobs++;
642    }
643  0 smsa = new SequenceI[njobs][];
644  0 start = 0;
645  0 int j = 0;
646  0 for (int contig = 0; contig < contigs.length; contig += 3)
647    {
648  0 if (contigs[contig + 1] - start > 0)
649    {
650  0 SequenceI mseq[] = new SequenceI[sequences.length];
651  0 for (int s = 0; s < mseq.length; s++)
652    {
653  0 mseq[s] = sequences[s].getSeq(gapCharacter)
654    .getSubSequence(start, contigs[contig + 1]);
655    }
656  0 smsa[j] = mseq;
657  0 j++;
658    }
659  0 start = contigs[contig + 1] + contigs[contig + 2];
660    }
661  0 if (start < fwidth)
662    {
663  0 SequenceI mseq[] = new SequenceI[sequences.length];
664  0 for (int s = 0; s < mseq.length; s++)
665    {
666  0 mseq[s] = sequences[s].getSeq(gapCharacter).getSubSequence(start,
667    fwidth + 1);
668    }
669  0 smsa[j] = mseq;
670  0 j++;
671    }
672    }
673    else
674    {
675  2 smsa = new SequenceI[1][];
676  2 smsa[0] = new SequenceI[sequences.length];
677  68 for (int s = 0; s < sequences.length; s++)
678    {
679  66 smsa[0][s] = sequences[s].getSeq(gapCharacter);
680    }
681    }
682  2 return smsa;
683    }
684   
685    /**
686    * return full msa and hidden regions with visible blocks replaced with new
687    * sub alignments
688    *
689    * @param nvismsa
690    * SequenceI[][]
691    * @param orders
692    * AlignmentOrder[] corresponding to each SequenceI[] block.
693    * @return Object[]
694    */
 
695  0 toggle public Object[] getUpdatedView(SequenceI[][] nvismsa,
696    AlignmentOrder[] orders, char gapCharacter)
697    {
698  0 if (sequences == null || width <= 0)
699    {
700  0 throw new Error(MessageManager
701    .getString("error.empty_view_cannot_be_updated"));
702    }
703  0 if (nvismsa == null)
704    {
705  0 throw new Error(
706    "nvismsa==null. use getAlignmentAndColumnSelection() instead.");
707    }
708  0 if (contigs != null && contigs.length > 0)
709    {
710  0 SequenceI[] alignment = new SequenceI[sequences.length];
711    // ColumnSelection columnselection = new ColumnSelection();
712  0 HiddenColumns hidden = new HiddenColumns();
713  0 if (contigs != null && contigs.length > 0)
714    {
715  0 int start = 0;
716  0 int nwidth = 0;
717  0 int owidth = width;
718  0 int j = 0;
719  0 for (int contig = 0; contig < contigs.length; contig += 3)
720    {
721  0 owidth += contigs[contig + 2]; // recover final column width
722  0 if (contigs[contig + 1] - start > 0)
723    {
724  0 int swidth = 0; // subalignment width
725  0 if (nvismsa[j] != null)
726    {
727  0 SequenceI mseq[] = nvismsa[j];
728  0 AlignmentOrder order = (orders == null) ? null : orders[j];
729  0 j++;
730  0 if (mseq.length != sequences.length)
731    {
732  0 throw new Error(MessageManager.formatMessage(
733    "error.mismatch_between_number_of_sequences_in_block",
734    new String[]
735    { Integer.valueOf(j).toString(),
736    Integer.valueOf(mseq.length).toString(),
737    Integer.valueOf(sequences.length)
738    .toString() }));
739    }
740  0 swidth = mseq[0].getLength(); // JBPNote: could ensure padded
741    // here.
742  0 for (int s = 0; s < mseq.length; s++)
743    {
744  0 if (alignment[s] == null)
745    {
746  0 alignment[s] = mseq[s];
747    }
748    else
749    {
750  0 alignment[s]
751    .setSequence(alignment[s].getSequenceAsString()
752    + mseq[s].getSequenceAsString());
753  0 if (mseq[s].getStart() <= mseq[s].getEnd())
754    {
755  0 alignment[s].setEnd(mseq[s].getEnd());
756    }
757  0 if (order != null)
758    {
759  0 order.updateSequence(mseq[s], alignment[s]);
760    }
761    }
762    }
763    }
764    else
765    {
766    // recover original alignment block or place gaps
767  0 if (true)
768    {
769    // recover input data
770  0 for (int s = 0; s < sequences.length; s++)
771    {
772  0 SequenceI oseq = sequences[s].getSeq(gapCharacter)
773    .getSubSequence(start, contigs[contig + 1]);
774  0 if (swidth < oseq.getLength())
775    {
776  0 swidth = oseq.getLength();
777    }
778  0 if (alignment[s] == null)
779    {
780  0 alignment[s] = oseq;
781    }
782    else
783    {
784  0 alignment[s]
785    .setSequence(alignment[s].getSequenceAsString()
786    + oseq.getSequenceAsString());
787  0 if (oseq.getEnd() >= oseq.getStart())
788    {
789  0 alignment[s].setEnd(oseq.getEnd());
790    }
791    }
792    }
793   
794    }
795  0 j++;
796    }
797  0 nwidth += swidth;
798    }
799    // advance to begining of visible region
800  0 start = contigs[contig + 1] + contigs[contig + 2];
801    // add hidden segment to right of next region
802  0 for (int s = 0; s < sequences.length; s++)
803    {
804  0 SequenceI hseq = sequences[s].getSeq(gapCharacter)
805    .getSubSequence(contigs[contig + 1], start);
806  0 if (alignment[s] == null)
807    {
808  0 alignment[s] = hseq;
809    }
810    else
811    {
812  0 alignment[s].setSequence(alignment[s].getSequenceAsString()
813    + hseq.getSequenceAsString());
814  0 if (hseq.getEnd() >= hseq.getStart())
815    {
816  0 alignment[s].setEnd(hseq.getEnd());
817    }
818    }
819    }
820    // mark hidden segment as hidden in the new alignment
821  0 hidden.hideColumns(nwidth, nwidth + contigs[contig + 2] - 1);
822  0 nwidth += contigs[contig + 2];
823    }
824    // Do final segment - if it exists
825  0 if (j < nvismsa.length)
826    {
827  0 int swidth = 0;
828  0 if (nvismsa[j] != null)
829    {
830  0 SequenceI mseq[] = nvismsa[j];
831  0 AlignmentOrder order = (orders != null) ? orders[j] : null;
832  0 swidth = mseq[0].getLength();
833  0 for (int s = 0; s < mseq.length; s++)
834    {
835  0 if (alignment[s] == null)
836    {
837  0 alignment[s] = mseq[s];
838    }
839    else
840    {
841  0 alignment[s].setSequence(alignment[s].getSequenceAsString()
842    + mseq[s].getSequenceAsString());
843  0 if (mseq[s].getEnd() >= mseq[s].getStart())
844    {
845  0 alignment[s].setEnd(mseq[s].getEnd());
846    }
847  0 if (order != null)
848    {
849  0 order.updateSequence(mseq[s], alignment[s]);
850    }
851    }
852    }
853    }
854    else
855    {
856  0 if (start < owidth)
857    {
858    // recover input data or place gaps
859  0 if (true)
860    {
861    // recover input data
862  0 for (int s = 0; s < sequences.length; s++)
863    {
864  0 SequenceI oseq = sequences[s].getSeq(gapCharacter)
865    .getSubSequence(start, owidth + 1);
866  0 if (swidth < oseq.getLength())
867    {
868  0 swidth = oseq.getLength();
869    }
870  0 if (alignment[s] == null)
871    {
872  0 alignment[s] = oseq;
873    }
874    else
875    {
876  0 alignment[s]
877    .setSequence(alignment[s].getSequenceAsString()
878    + oseq.getSequenceAsString());
879  0 if (oseq.getEnd() >= oseq.getStart())
880    {
881  0 alignment[s].setEnd(oseq.getEnd());
882    }
883    }
884    }
885  0 nwidth += swidth;
886    }
887    else
888    {
889    // place gaps.
890  0 throw new Error(MessageManager
891    .getString("error.padding_not_yet_implemented"));
892    }
893    }
894    }
895    }
896    }
897  0 return new Object[] { alignment, hidden };
898    }
899    else
900    {
901  0 if (nvismsa.length != 1)
902    {
903  0 throw new Error(MessageManager.formatMessage(
904    "error.mismatch_between_visible_blocks_to_update_and_number_of_contigs_in_view",
905    new String[]
906    { Integer.valueOf(nvismsa.length).toString() }));
907    }
908  0 if (nvismsa[0] != null)
909    {
910  0 return new Object[] { nvismsa[0], new HiddenColumns() };
911    }
912    else
913    {
914  0 return getAlignmentAndHiddenColumns(gapCharacter);
915    }
916    }
917    }
918   
919    /**
920    * returns simple array of start end positions of visible range on alignment.
921    * vis_start and vis_end are inclusive - use
922    * SequenceI.getSubSequence(vis_start, vis_end+1) to recover visible sequence
923    * from underlying alignment.
924    *
925    * @return int[] { start_i, end_i } for 1<i<n visible regions.
926    */
 
927  25 toggle public int[] getVisibleContigs()
928    {
929  25 if (contigs != null && contigs.length > 0)
930    {
931  8 int start = 0;
932  8 int nvis = 0;
933  8 int fwidth = width;
934  22 for (int contig = 0; contig < contigs.length; contig += 3)
935    {
936  14 if ((contigs[contig + 1] - start) > 0)
937    {
938  7 nvis++;
939    }
940  14 fwidth += contigs[contig + 2]; // end up with full region width
941    // (including hidden regions)
942  14 start = contigs[contig + 1] + contigs[contig + 2];
943    }
944  8 if (start < fwidth)
945    {
946  3 nvis++;
947    }
948  8 int viscontigs[] = new int[nvis * 2];
949  8 nvis = 0;
950  8 start = 0;
951  22 for (int contig = 0; contig < contigs.length; contig += 3)
952    {
953  14 if ((contigs[contig + 1] - start) > 0)
954    {
955  7 viscontigs[nvis] = start;
956  7 viscontigs[nvis + 1] = contigs[contig + 1] - 1; // end is inclusive
957  7 nvis += 2;
958    }
959  14 start = contigs[contig + 1] + contigs[contig + 2];
960    }
961  8 if (start < fwidth)
962    {
963  3 viscontigs[nvis] = start;
964  3 viscontigs[nvis + 1] = fwidth - 1; // end is inclusive
965  3 nvis += 2;
966    }
967  8 return viscontigs;
968    }
969    else
970    {
971  17 return new int[] { 0, width - 1 };
972    }
973    }
974   
975    /**
976    *
977    * @return position of first visible column of AlignmentView within its
978    * parent's alignment reference frame
979    */
 
980  0 toggle public int getAlignmentOrigin()
981    {
982  0 return firstCol;
983    }
984   
985    /**
986    * compute a deletion map for the current view according to the given
987    * gap/match map
988    *
989    * @param gapMap
990    * (as returned from SequenceI.gapMap())
991    * @return int[] {intersection of visible regions with gapMap)
992    */
 
993  0 toggle public int[] getVisibleContigMapFor(int[] gapMap)
994    {
995  0 int[] delMap = null;
996  0 int[] viscontigs = getVisibleContigs();
997  0 int spos = 0;
998  0 int i = 0;
999  0 if (viscontigs != null)
1000    {
1001    // viscontigs maps from a subset of the gapMap to the gapMap, so it will
1002    // always be equal to or shorter than gapMap
1003  0 delMap = new int[gapMap.length];
1004  0 for (int contig = 0; contig < viscontigs.length; contig += 2)
1005    {
1006   
1007  0 while (spos < gapMap.length && gapMap[spos] < viscontigs[contig])
1008    {
1009  0 spos++;
1010    }
1011  0 while (spos < gapMap.length
1012    && gapMap[spos] <= viscontigs[contig + 1])
1013    {
1014  0 delMap[i++] = spos++;
1015    }
1016    }
1017  0 int tmap[] = new int[i];
1018  0 System.arraycopy(delMap, 0, tmap, 0, i);
1019  0 delMap = tmap;
1020    }
1021  0 return delMap;
1022    }
1023   
1024    /**
1025    * apply the getSeq(gc) method to each sequence cigar, and return the array of
1026    * edited sequences, optionally with hidden regions removed.
1027    *
1028    * @param gc
1029    * gap character to use for insertions
1030    * @param delete
1031    * remove hidden regions from sequences. Note: currently implemented
1032    * in a memory inefficient way - space needed is 2*result set for
1033    * deletion
1034    *
1035    * @return SequenceI[]
1036    */
 
1037  0 toggle public SequenceI[] getEditedSequences(char gc, boolean delete)
1038    {
1039  0 SeqCigar[] msf = getSequences();
1040  0 SequenceI[] aln = new SequenceI[msf.length];
1041  0 for (int i = 0, j = msf.length; i < j; i++)
1042    {
1043  0 aln[i] = msf[i].getSeq(gc);
1044    }
1045  0 if (delete)
1046    {
1047  0 String[] sqs = getSequenceStrings(gc);
1048  0 for (int i = 0; i < sqs.length; i++)
1049    {
1050  0 aln[i].setSequence(sqs[i]);
1051  0 sqs[i] = null;
1052    }
1053    }
1054  0 return aln;
1055    }
1056   
 
1057  0 toggle public static void summariseAlignmentView(AlignmentView view,
1058    PrintStream os)
1059    {
1060  0 os.print("View has " + view.sequences.length + " of which ");
1061  0 if (view.selected == null)
1062    {
1063  0 os.print("None");
1064    }
1065    else
1066    {
1067  0 os.print(" " + view.selected.size());
1068    }
1069  0 os.println(" are selected.");
1070  0 os.print("View is " + view.getWidth() + " columns wide");
1071  0 int viswid = 0;
1072  0 int[] contigs = view.getContigs();
1073  0 if (contigs != null)
1074    {
1075  0 viswid = view.width;
1076  0 for (int i = 0; i < contigs.length; i += 3)
1077    {
1078  0 viswid += contigs[i + 2];
1079    }
1080  0 os.println("with " + viswid + " visible columns spread over "
1081    + contigs.length / 3 + " regions.");
1082    }
1083    else
1084    {
1085  0 viswid = view.width;
1086  0 os.println(".");
1087    }
1088  0 if (view.scGroups != null)
1089    {
1090  0 os.println("There are " + view.scGroups.size()
1091    + " groups defined on the view.");
1092  0 for (int g = 0; g < view.scGroups.size(); g++)
1093    {
1094  0 ScGroup sgr = view.scGroups.get(g);
1095  0 os.println("Group " + g + ": Name = " + sgr.sg.getName()
1096    + " Contains " + sgr.seqs.size() + " Seqs.");
1097  0 os.println("This group runs from " + sgr.sg.getStartRes() + " to "
1098    + sgr.sg.getEndRes());
1099  0 for (int s = 0; s < sgr.seqs.size(); s++)
1100    {
1101    // JBPnote this should be a unit test for ScGroup
1102  0 if (!sgr.seqs.get(s).isMemberOf(sgr))
1103    {
1104  0 os.println("** WARNING: sequence " + sgr.seqs.get(s).toString()
1105    + " is not marked as member of group.");
1106    }
1107    }
1108    }
1109  0 AlignmentI visal = view.getVisibleAlignment('-');
1110  0 if (visal != null)
1111    {
1112  0 os.println("Vis. alignment is " + visal.getWidth()
1113    + " wide and has " + visal.getHeight() + " seqs.");
1114  0 if (visal.getGroups() != null && visal.getGroups().size() > 0)
1115    {
1116   
1117  0 int i = 1;
1118  0 for (SequenceGroup sg : visal.getGroups())
1119    {
1120  0 os.println("Group " + (i++) + " begins at column "
1121    + sg.getStartRes() + " and ends at " + sg.getEndRes());
1122    }
1123    }
1124    }
1125    }
1126    }
1127   
 
1128  0 toggle public static void testSelectionViews(AlignmentI alignment,
1129    HiddenColumns hidden, SequenceGroup selection)
1130    {
1131  0 jalview.bin.Console.outPrintln("Testing standard view creation:\n");
1132  0 AlignmentView view = null;
1133  0 try
1134    {
1135  0 jalview.bin.Console.outPrintln(
1136    "View with no hidden columns, no limit to selection, no groups to be collected:");
1137  0 view = new AlignmentView(alignment, hidden, selection, false, false,
1138    false);
1139  0 summariseAlignmentView(view, System.out);
1140   
1141    } catch (Exception e)
1142    {
1143  0 e.printStackTrace();
1144  0 jalview.bin.Console.errPrintln(
1145    "Failed to generate alignment with selection but no groups marked.");
1146    }
1147  0 try
1148    {
1149  0 jalview.bin.Console.outPrintln(
1150    "View with no hidden columns, no limit to selection, and all groups to be collected:");
1151  0 view = new AlignmentView(alignment, hidden, selection, false, false,
1152    true);
1153  0 summariseAlignmentView(view, System.out);
1154    } catch (Exception e)
1155    {
1156  0 e.printStackTrace();
1157  0 jalview.bin.Console.errPrintln(
1158    "Failed to generate alignment with selection marked but no groups marked.");
1159    }
1160  0 try
1161    {
1162  0 jalview.bin.Console.outPrintln(
1163    "View with no hidden columns, limited to selection and no groups to be collected:");
1164  0 view = new AlignmentView(alignment, hidden, selection, false, true,
1165    false);
1166  0 summariseAlignmentView(view, System.out);
1167    } catch (Exception e)
1168    {
1169  0 e.printStackTrace();
1170  0 jalview.bin.Console.errPrintln(
1171    "Failed to generate alignment with selection restricted but no groups marked.");
1172    }
1173  0 try
1174    {
1175  0 jalview.bin.Console.outPrintln(
1176    "View with no hidden columns, limited to selection, and all groups to be collected:");
1177  0 view = new AlignmentView(alignment, hidden, selection, false, true,
1178    true);
1179  0 summariseAlignmentView(view, System.out);
1180    } catch (Exception e)
1181    {
1182  0 e.printStackTrace();
1183  0 jalview.bin.Console.errPrintln(
1184    "Failed to generate alignment with selection restricted and groups marked.");
1185    }
1186  0 try
1187    {
1188  0 jalview.bin.Console.outPrintln(
1189    "View *with* hidden columns, no limit to selection, no groups to be collected:");
1190  0 view = new AlignmentView(alignment, hidden, selection, true, false,
1191    false);
1192  0 summariseAlignmentView(view, System.out);
1193    } catch (Exception e)
1194    {
1195  0 e.printStackTrace();
1196  0 jalview.bin.Console.errPrintln(
1197    "Failed to generate alignment with selection but no groups marked.");
1198    }
1199  0 try
1200    {
1201  0 jalview.bin.Console.outPrintln(
1202    "View *with* hidden columns, no limit to selection, and all groups to be collected:");
1203  0 view = new AlignmentView(alignment, hidden, selection, true, false,
1204    true);
1205  0 summariseAlignmentView(view, System.out);
1206    } catch (Exception e)
1207    {
1208  0 e.printStackTrace();
1209  0 jalview.bin.Console.errPrintln(
1210    "Failed to generate alignment with selection marked but no groups marked.");
1211    }
1212  0 try
1213    {
1214  0 jalview.bin.Console.outPrintln(
1215    "View *with* hidden columns, limited to selection and no groups to be collected:");
1216  0 view = new AlignmentView(alignment, hidden, selection, true, true,
1217    false);
1218  0 summariseAlignmentView(view, System.out);
1219    } catch (Exception e)
1220    {
1221  0 e.printStackTrace();
1222  0 jalview.bin.Console.errPrintln(
1223    "Failed to generate alignment with selection restricted but no groups marked.");
1224    }
1225  0 try
1226    {
1227  0 jalview.bin.Console.outPrintln(
1228    "View *with* hidden columns, limited to selection, and all groups to be collected:");
1229  0 view = new AlignmentView(alignment, hidden, selection, true, true,
1230    true);
1231  0 summariseAlignmentView(view, System.out);
1232    } catch (Exception e)
1233    {
1234  0 e.printStackTrace();
1235  0 jalview.bin.Console.errPrintln(
1236    "Failed to generate alignment with selection restricted and groups marked.");
1237    }
1238   
1239    }
1240    }