set firstColumn property for an alignmentView object.
[jalview.git] / src / jalview / appletgui / AlignViewport.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19
20 package jalview.appletgui;
21
22 import java.util.*;
23
24 import java.awt.*;
25
26 import jalview.analysis.*;
27 import jalview.bin.*;
28 import jalview.datamodel.*;
29 import jalview.schemes.*;
30
31 public class AlignViewport
32 {
33   int startRes;
34   int endRes;
35
36   int startSeq;
37   int endSeq;
38
39
40   boolean cursorMode = false;
41
42   boolean showJVSuffix = true;
43   boolean showText = true;
44   boolean showColourText = false;
45   boolean showBoxes = true;
46   boolean wrapAlignment = false;
47   boolean renderGaps = true;
48   boolean showSequenceFeatures = false;
49   boolean showAnnotation = true;
50   boolean showConservation = true;
51   boolean showQuality = true;
52   boolean showConsensus = true;
53   boolean upperCasebold = false;
54
55   boolean colourAppliesToAllGroups = true;
56   ColourSchemeI globalColourScheme = null;
57   boolean conservationColourSelected = false;
58   boolean abovePIDThreshold = false;
59
60   SequenceGroup selectionGroup;
61
62   int charHeight;
63   int charWidth;
64   int wrappedWidth;
65
66   Font font = new Font("SansSerif", Font.PLAIN, 10);
67   boolean validCharWidth = true;
68   AlignmentI alignment;
69
70   ColumnSelection colSel = new ColumnSelection();
71
72   int threshold;
73   int increment;
74
75   NJTree currentTree = null;
76
77   boolean scaleAboveWrapped = true;
78   boolean scaleLeftWrapped = true;
79   boolean scaleRightWrapped = true;
80
81   // The following vector holds the features which are
82  // currently visible, in the correct order or rendering
83   public Hashtable featuresDisplayed;
84
85   boolean hasHiddenColumns = false;
86   boolean hasHiddenRows = false;
87   boolean showHiddenMarkers = true;
88
89
90   public Hashtable [] hconsensus;
91   AlignmentAnnotation consensus;
92   AlignmentAnnotation conservation;
93   AlignmentAnnotation quality;
94
95   boolean autocalculateConsensus = true;
96
97   public int ConsPercGaps = 25; // JBPNote : This should be a scalable property!
98
99   private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(this);
100
101   boolean ignoreGapsInConsensusCalculation = false;
102
103   jalview.bin.JalviewLite applet;
104
105   boolean MAC = false;
106
107   public AlignViewport(AlignmentI al, JalviewLite applet)
108   {
109     this.applet = applet;
110     setAlignment(al);
111     this.startRes = 0;
112     this.endRes = al.getWidth() - 1;
113     this.startSeq = 0;
114     this.endSeq = al.getHeight() - 1;
115     setFont(font);
116
117     if(System.getProperty("os.name").startsWith("Mac"))
118       MAC = true;
119
120     if (applet != null)
121     {
122       String param = applet.getParameter("showFullId");
123       if (param != null)
124       {
125         showJVSuffix = Boolean.valueOf(param).booleanValue();
126       }
127
128       param = applet.getParameter("showAnnotation");
129       if (param != null)
130       {
131         showAnnotation = Boolean.valueOf(param).booleanValue();
132       }
133
134       param = applet.getParameter("showConservation");
135       if (param != null)
136       {
137         showConservation = Boolean.valueOf(param).booleanValue();
138       }
139
140       param = applet.getParameter("showQuality");
141       if (param != null)
142       {
143         showQuality = Boolean.valueOf(param).booleanValue();
144       }
145
146       param = applet.getParameter("showConsensus");
147       if (param != null)
148       {
149         showConsensus = Boolean.valueOf(param).booleanValue();
150       }
151
152       param = applet.getParameter("upperCase");
153       if (param != null)
154       {
155         if(param.equalsIgnoreCase("bold"))
156           upperCasebold = true;
157       }
158
159     }
160     // We must set conservation and consensus before setting colour,
161     // as Blosum and Clustal require this to be done
162     updateConservation();
163     updateConsensus();
164
165
166     if (applet != null)
167     {
168       String colour = applet.getParameter("defaultColour");
169
170       if(colour == null)
171       {
172         colour = applet.getParameter("userDefinedColour");
173         if(colour !=null)
174           colour = "User Defined";
175       }
176
177       if(colour != null)
178       {
179         globalColourScheme = ColourSchemeProperty.getColour(alignment, colour);
180         if (globalColourScheme != null)
181         {
182           globalColourScheme.setConsensus(hconsensus);
183         }
184       }
185
186       if(applet.getParameter("userDefinedColour")!=null)
187       {
188         ((UserColourScheme)globalColourScheme).parseAppletParameter(
189             applet.getParameter("userDefinedColour"));
190       }
191
192
193     }
194   }
195
196   public void showSequenceFeatures(boolean b)
197   {
198     showSequenceFeatures = b;
199   }
200
201   public boolean getShowSequenceFeatures()
202   {
203     return showSequenceFeatures;
204   }
205
206
207   public void updateConservation()
208   {
209     if(alignment.isNucleotide())
210           return;
211
212     Conservation cons = new jalview.analysis.Conservation("All",
213         jalview.schemes.ResidueProperties.propHash, 3,
214         alignment.getSequences(), 0,
215         alignment.getWidth() - 1);
216     cons.calculate();
217     cons.verdict(false, ConsPercGaps);
218     cons.findQuality();
219     int alWidth = alignment.getWidth();
220     Annotation[] annotations = new Annotation[alWidth];
221     Annotation[] qannotations = new Annotation[alWidth];
222     String sequence = cons.getConsSequence().getSequence();
223     float minR, minG, minB, maxR, maxG, maxB;
224     minR = 0.3f;
225     minG = 0.0f;
226     minB = 0f;
227     maxR = 1.0f - minR;
228     maxG = 0.9f - minG;
229     maxB = 0f - minB; // scalable range for colouring both Conservation and Quality
230     float min = 0f;
231     float max = 11f;
232     float qmin = cons.qualityRange[0].floatValue();
233     float qmax = cons.qualityRange[1].floatValue();
234
235     for (int i = 0; i < alWidth; i++)
236     {
237       float value = 0;
238       try
239       {
240         value = Integer.parseInt(sequence.charAt(i) + "");
241       }
242       catch (Exception ex)
243       {
244         if (sequence.charAt(i) == '*')
245         {
246           value = 11;
247         }
248         if (sequence.charAt(i) == '+')
249         {
250           value = 10;
251         }
252       }
253       float vprop = value - min;
254       vprop /= max;
255
256       annotations[i] = new Annotation(sequence.charAt(i) + "",
257                                       "", ' ', value,
258                                       new Color(minR + maxR * vprop,
259                                                 minG + maxG * vprop,
260                                                 minB + maxB * vprop));
261       // Quality calc
262       value = ( (Double) cons.quality.elementAt(i)).floatValue();
263       vprop = value - qmin;
264       vprop /= qmax;
265       qannotations[i] = new Annotation(" ",
266                                        String.valueOf(value), ' ', value,
267                                        new
268                                        Color(minR + maxR * vprop,
269                                              minG + maxG * vprop,
270                                              minB + maxB * vprop));
271     }
272
273     if (conservation == null)
274     {
275       conservation = new AlignmentAnnotation("Conservation",
276                                              "Conservation of total alignment less than " +
277                                              ConsPercGaps + "% gaps",
278                                              annotations,
279                                              0f, // cons.qualityRange[0].floatValue(),
280                                              11f, // cons.qualityRange[1].floatValue()
281                                              AlignmentAnnotation.BAR_GRAPH);
282       if (showConservation)
283       {
284         alignment.addAnnotation(conservation);
285       }
286       quality = new AlignmentAnnotation("Quality",
287                                         "Alignment Quality based on Blosum62 scores",
288                                         qannotations,
289                                         cons.qualityRange[0].floatValue(),
290                                         cons.qualityRange[1].floatValue(),
291                                         AlignmentAnnotation.BAR_GRAPH);
292       if (showQuality)
293       {
294         alignment.addAnnotation(quality);
295       }
296     }
297     else
298     {
299       conservation.annotations = annotations;
300       quality.annotations = qannotations;
301       quality.graphMax = cons.qualityRange[1].floatValue();
302     }
303
304   }
305
306   public void updateConsensus()
307   {
308     // this routine prevents vconsensus becoming a new object each time
309     // consenus is calculated. Important for speed of Blosum62
310     // and PID colouring of alignment
311     int aWidth = alignment.getWidth();
312
313     Annotation[] annotations = new Annotation[aWidth];
314
315     hconsensus = new Hashtable[aWidth];
316     AAFrequency.calculate(alignment.getSequencesArray(),
317                           0, aWidth,
318                           hconsensus);
319
320     for (int i = 0; i < aWidth; i++)
321     {
322       float value = 0;
323       if(ignoreGapsInConsensusCalculation)
324         value = ((Float)hconsensus[i].get("pid_nogaps")).floatValue();
325       else
326         value = ((Float)hconsensus[i].get("pid_gaps")).floatValue();
327
328       String maxRes = hconsensus[i].get("maxResidue").toString();
329       String mouseOver = hconsensus[i].get("maxResidue") + " ";
330       if (maxRes.length() > 1)
331       {
332         mouseOver = "[" + maxRes + "] ";
333         maxRes = "+";
334       }
335
336
337       mouseOver += (int) value + "%";
338       annotations[i] = new Annotation(maxRes, mouseOver, ' ', value);
339
340     }
341
342     if (consensus == null)
343     {
344       consensus = new AlignmentAnnotation("Consensus",
345                                           "PID", annotations, 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
346       if (showConsensus)
347       {
348         alignment.addAnnotation(consensus);
349       }
350     }
351     else
352     {
353       consensus.annotations = annotations;
354     }
355
356     if(globalColourScheme!=null)
357           globalColourScheme.setConsensus(hconsensus);
358
359   }
360   /**
361    * get the consensus sequence as displayed under the PID consensus annotation row.
362    * @return consensus sequence as a new sequence object
363    */
364   /**
365    * get the consensus sequence as displayed under the PID consensus annotation row.
366    * @return consensus sequence as a new sequence object
367    */
368   public SequenceI getConsensusSeq() {
369     if (consensus==null)
370       updateConsensus();
371     if (consensus==null)
372       return null;
373     StringBuffer seqs=new StringBuffer();
374     for (int i=0; i<consensus.annotations.length; i++) {
375       if (consensus.annotations[i]!=null) {
376         if (consensus.annotations[i].description.charAt(0) == '[')
377           seqs.append(consensus.annotations[i].description.charAt(1));
378         else
379           seqs.append(consensus.annotations[i].displayCharacter);
380       }
381     }
382     SequenceI sq = new Sequence("Consensus", seqs.toString());
383     sq.setDescription("Percentage Identity Consensus "+((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
384     return sq;
385   }
386   public SequenceGroup getSelectionGroup()
387   {
388     return selectionGroup;
389   }
390
391   public void setSelectionGroup(SequenceGroup sg)
392   {
393     selectionGroup = sg;
394   }
395
396   public boolean getConservationSelected()
397   {
398     return conservationColourSelected;
399   }
400
401   public void setConservationSelected(boolean b)
402   {
403     conservationColourSelected = b;
404   }
405
406   public boolean getAbovePIDThreshold()
407   {
408     return abovePIDThreshold;
409   }
410
411   public void setAbovePIDThreshold(boolean b)
412   {
413     abovePIDThreshold = b;
414   }
415
416   public int getStartRes()
417   {
418     return startRes;
419   }
420
421   public int getEndRes()
422   {
423     return endRes;
424   }
425
426   public int getStartSeq()
427   {
428     return startSeq;
429   }
430
431   public void setGlobalColourScheme(ColourSchemeI cs)
432   {
433     globalColourScheme = cs;
434   }
435
436   public ColourSchemeI getGlobalColourScheme()
437   {
438     return globalColourScheme;
439   }
440
441   public void setStartRes(int res)
442   {
443     this.startRes = res;
444   }
445
446   public void setStartSeq(int seq)
447   {
448     this.startSeq = seq;
449   }
450
451   public void setEndRes(int res)
452   {
453     if (res > alignment.getWidth() - 1)
454     {
455       // log.System.out.println(" Corrected res from " + res + " to maximum " + (alignment.getWidth()-1));
456       res = alignment.getWidth() - 1;
457     }
458     if (res < 0)
459     {
460       res = 0;
461     }
462     this.endRes = res;
463   }
464
465   public void setEndSeq(int seq)
466   {
467     if (seq > alignment.getHeight())
468     {
469       seq = alignment.getHeight();
470     }
471     if (seq < 0)
472     {
473       seq = 0;
474     }
475     this.endSeq = seq;
476   }
477
478   public int getEndSeq()
479   {
480     return endSeq;
481   }
482
483   java.awt.Frame nullFrame;
484   public void setFont(Font f)
485   {
486     font = f;
487     if(nullFrame == null)
488     {
489       nullFrame = new java.awt.Frame();
490       nullFrame.addNotify();
491     }
492
493     java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
494     setCharHeight(fm.getHeight());
495     charWidth = fm.charWidth('M');
496
497     if(upperCasebold)
498     {
499       Font f2 = new Font(f.getName(), Font.BOLD, f.getSize());
500       fm = nullFrame.getGraphics().getFontMetrics(f2);
501       charWidth = fm.stringWidth("MMMMMMMMMMM") / 10;
502     }
503   }
504
505   public Font getFont()
506   {
507     return font;
508   }
509
510   public int getCharWidth()
511   {
512     return charWidth;
513   }
514
515   public void setCharHeight(int h)
516   {
517     this.charHeight = h;
518   }
519
520   public int getCharHeight()
521   {
522     return charHeight;
523   }
524
525   public void setWrappedWidth(int w)
526   {
527     this.wrappedWidth = w;
528   }
529
530   public int getwrappedWidth()
531   {
532     return wrappedWidth;
533   }
534
535   public AlignmentI getAlignment()
536   {
537     return alignment;
538   }
539
540   public void setAlignment(AlignmentI align)
541   {
542     this.alignment = align;
543   }
544
545   public void setWrapAlignment(boolean state)
546   {
547     wrapAlignment = state;
548   }
549
550   public void setShowText(boolean state)
551   {
552     showText = state;
553   }
554
555   public void setRenderGaps(boolean state)
556   {
557     renderGaps = state;
558   }
559
560   public boolean getColourText()
561   {
562     return showColourText;
563   }
564
565   public void setColourText(boolean state)
566   {
567     showColourText = state;
568   }
569
570   public void setShowBoxes(boolean state)
571   {
572     showBoxes = state;
573   }
574
575   public boolean getWrapAlignment()
576   {
577     return wrapAlignment;
578   }
579
580   public boolean getShowText()
581   {
582     return showText;
583   }
584
585   public boolean getShowBoxes()
586   {
587     return showBoxes;
588   }
589
590   public char getGapCharacter()
591   {
592     return getAlignment().getGapCharacter();
593   }
594
595   public void setGapCharacter(char gap)
596   {
597     if (getAlignment() != null)
598     {
599       getAlignment().setGapCharacter(gap);
600     }
601   }
602
603   public void setThreshold(int thresh)
604   {
605     threshold = thresh;
606   }
607
608   public int getThreshold()
609   {
610     return threshold;
611   }
612
613   public void setIncrement(int inc)
614   {
615     increment = inc;
616   }
617
618   public int getIncrement()
619   {
620     return increment;
621   }
622
623   public void setHiddenColumns(ColumnSelection colsel)
624   {
625     this.colSel = colsel;
626     if(colSel.getHiddenColumns()!=null)
627       hasHiddenColumns = true;
628   }
629
630   public ColumnSelection getColumnSelection()
631   {
632     return colSel;
633   }
634
635   public void resetSeqLimits(int height)
636   {
637     setEndSeq(height / getCharHeight());
638   }
639
640   public void setCurrentTree(NJTree tree)
641   {
642     currentTree = tree;
643   }
644
645   public NJTree getCurrentTree()
646   {
647     return currentTree;
648   }
649
650   public void setColourAppliesToAllGroups(boolean b)
651   {
652     colourAppliesToAllGroups = b;
653   }
654
655   public boolean getColourAppliesToAllGroups()
656   {
657     return colourAppliesToAllGroups;
658   }
659
660   public boolean getShowJVSuffix()
661   {
662     return showJVSuffix;
663   }
664
665   public void setShowJVSuffix(boolean b)
666   {
667     showJVSuffix = b;
668   }
669
670   public boolean getShowAnnotation()
671   {
672     return showAnnotation;
673   }
674
675   public void setShowAnnotation(boolean b)
676   {
677     showAnnotation = b;
678   }
679
680   public boolean getScaleAboveWrapped()
681   {
682     return scaleAboveWrapped;
683   }
684
685   public boolean getScaleLeftWrapped()
686   {
687     return scaleLeftWrapped;
688   }
689
690   public boolean getScaleRightWrapped()
691   {
692     return scaleRightWrapped;
693   }
694
695   public void setScaleAboveWrapped(boolean b)
696   {
697     scaleAboveWrapped = b;
698   }
699
700   public void setScaleLeftWrapped(boolean b)
701   {
702     scaleLeftWrapped = b;
703   }
704
705   public void setScaleRightWrapped(boolean b)
706   {
707     scaleRightWrapped = b;
708   }
709
710   public void setIgnoreGapsConsensus(boolean b)
711   {
712     ignoreGapsInConsensusCalculation = b;
713     updateConsensus();
714     if (globalColourScheme!=null)
715     {
716       globalColourScheme.setThreshold(globalColourScheme.getThreshold(),
717           ignoreGapsInConsensusCalculation);
718
719     }
720   }
721
722   /**
723    * Property change listener for changes in alignment
724    *
725    * @param listener DOCUMENT ME!
726    */
727   public void addPropertyChangeListener(
728       java.beans.PropertyChangeListener listener)
729   {
730       changeSupport.addPropertyChangeListener(listener);
731   }
732
733   /**
734    * DOCUMENT ME!
735    *
736    * @param listener DOCUMENT ME!
737    */
738   public void removePropertyChangeListener(
739       java.beans.PropertyChangeListener listener)
740   {
741       changeSupport.removePropertyChangeListener(listener);
742   }
743
744   /**
745    * Property change listener for changes in alignment
746    *
747    * @param prop DOCUMENT ME!
748    * @param oldvalue DOCUMENT ME!
749    * @param newvalue DOCUMENT ME!
750    */
751   public void firePropertyChange(String prop, Object oldvalue, Object newvalue)
752   {
753       changeSupport.firePropertyChange(prop, oldvalue, newvalue);
754   }
755
756
757
758   public boolean getIgnoreGapsConsensus()
759   {
760     return ignoreGapsInConsensusCalculation;
761   }
762   public void hideSelectedColumns()
763   {
764     if (colSel.size() < 1)
765       return;
766
767     colSel.hideSelectedColumns();
768     setSelectionGroup(null);
769
770     hasHiddenColumns = true;
771   }
772
773   public void invertColumnSelection()
774   {
775     int column;
776     for (int i = 0; i < alignment.getWidth(); i++)
777     {
778       column = i;
779
780       if (colSel.contains(column))
781         colSel.removeElement(column);
782       else
783         colSel.addElement(column);
784
785     }
786   }
787
788
789   public void hideColumns(int start, int end)
790   {
791     if(start==end)
792       colSel.hideColumns(start);
793     else
794       colSel.hideColumns(start, end);
795
796     hasHiddenColumns = true;
797   }
798
799   public void hideAllSelectedSeqs()
800   {
801     if (selectionGroup == null)
802       return;
803
804     SequenceI[] seqs = selectionGroup.getSequencesInOrder(alignment);
805
806     hideSequence(seqs);
807
808     setSelectionGroup(null);
809   }
810
811   public void hideSequence(SequenceI [] seq)
812   {
813     if(seq!=null)
814     {
815       for (int i = 0; i < seq.length; i++)
816         alignment.getHiddenSequences().hideSequence(seq[i]);
817
818       hasHiddenRows = true;
819       firePropertyChange("alignment", null, alignment.getSequences());
820     }
821   }
822
823   public void showColumn(int col)
824   {
825     colSel.revealHiddenColumns(col);
826     if(colSel.getHiddenColumns()==null)
827       hasHiddenColumns = false;
828   }
829
830   public void showAllHiddenColumns()
831   {
832     colSel.revealAllHiddenColumns();
833     hasHiddenColumns = false;
834   }
835
836   public void showAllHiddenSeqs()
837   {
838     if(alignment.getHiddenSequences().getSize()>0)
839     {
840       if(selectionGroup==null)
841       {
842         selectionGroup = new SequenceGroup();
843         selectionGroup.setEndRes(alignment.getWidth()-1);
844       }
845       Vector tmp = alignment.getHiddenSequences().showAll();
846       for(int t=0; t<tmp.size(); t++)
847       {
848         selectionGroup.addSequence(
849             (SequenceI)tmp.elementAt(t), false
850             );
851       }
852       firePropertyChange("alignment", null, alignment.getSequences());
853       hasHiddenRows = false;
854     }
855   }
856
857   public int adjustForHiddenSeqs(int alignmentIndex)
858   {
859     return alignment.getHiddenSequences().adjustForHiddenSeqs(alignmentIndex);
860   }
861
862   /**
863    * This method returns the a new SequenceI [] with
864    * the selection sequence and start and end points adjusted
865    * @return String[]
866    */
867   public SequenceI[] getSelectionAsNewSequence()
868   {
869     SequenceI[] sequences;
870
871     if (selectionGroup == null)
872       sequences = alignment.getSequencesArray();
873     else
874       sequences = selectionGroup.getSelectionAsNewSequences(alignment);
875
876     return sequences;
877   }
878
879   /**
880    * This method returns the visible alignment as text, as
881    * seen on the GUI, ie if columns are hidden they will not
882    * be returned in the result.
883    * Use this for calculating trees, PCA, redundancy etc on views
884    * which contain hidden columns.
885    * @return String[]
886    */
887   public jalview.datamodel.CigarArray getViewAsCigars(boolean selectedRegionOnly)
888   {
889     CigarArray selection=null;
890     SequenceI [] seqs= null;
891     int i, iSize;
892     int start = 0, end = 0;
893     if(selectedRegionOnly && selectionGroup!=null)
894     {
895       iSize = selectionGroup.getSize(false);
896       seqs = selectionGroup.getSequencesInOrder(alignment);
897       start = selectionGroup.getStartRes();
898       end = selectionGroup.getEndRes(); // inclusive for start and end in SeqCigar constructor
899     }
900     else
901     {
902       iSize = alignment.getHeight();
903       seqs = alignment.getSequencesArray();
904       end = alignment.getWidth()-1;
905     }
906     SeqCigar[] selseqs = new SeqCigar[iSize];
907     for(i=0; i<iSize; i++)
908     {
909       selseqs[i] = new SeqCigar(seqs[i], start, end);
910     }
911     selection=new CigarArray(selseqs);
912     // now construct the CigarArray operations
913     if (hasHiddenColumns) {
914       Vector regions = colSel.getHiddenColumns();
915       int [] region;
916       int hideStart, hideEnd;
917       int last=start;
918       for (int j = 0; last<end & j < regions.size(); j++)
919       {
920         region = (int[]) regions.elementAt(j);
921         hideStart = region[0];
922         hideEnd = region[1];
923         // edit hidden regions to selection range
924         if(hideStart<last) {
925           if (hideEnd > last)
926           {
927             hideStart = last;
928           } else
929             continue;
930         }
931
932         if (hideStart>end)
933           break;
934
935         if (hideEnd>end)
936           hideEnd=end;
937
938         if (hideStart>hideEnd)
939           break;
940         /**
941          * form operations...
942          */
943         if (last<hideStart)
944           selection.addOperation(CigarArray.M, hideStart-last);
945         selection.addOperation(CigarArray.D, 1+hideEnd-hideStart);
946         last = hideEnd+1;
947       }
948       // Final match if necessary.
949       if (last<end)
950         selection.addOperation(CigarArray.M, end-last+1);
951     } else {
952       selection.addOperation(CigarArray.M, end-start+1);
953     }
954     return selection;
955   }
956   /**
957    * return a compact representation of the current alignment selection to
958    * pass to an analysis function
959    * @param selectedOnly boolean true to just return the selected view
960    * @return AlignmentView
961    */
962   jalview.datamodel.AlignmentView getAlignmentView(boolean selectedOnly) {
963     // JBPNote:
964     // this is here because the AlignmentView constructor modifies the CigarArray
965     // object. Refactoring of Cigar and alignment view representation should
966     // be done to remove redundancy.
967     CigarArray aligview = getViewAsCigars(selectedOnly);
968     if (aligview!=null) {
969       return new AlignmentView(aligview, 
970           (selectedOnly && selectionGroup!=null) ? selectionGroup.getStartRes() : 0);
971     }
972     return null;
973   }
974   /**
975    * This method returns the visible alignment as text, as
976    * seen on the GUI, ie if columns are hidden they will not
977    * be returned in the result.
978    * Use this for calculating trees, PCA, redundancy etc on views
979    * which contain hidden columns.
980    * @return String[]
981    */
982   public String [] getViewAsString(boolean selectedRegionOnly)
983   {
984     String [] selection = null;
985     SequenceI [] seqs= null;
986     int i, iSize;
987     int start = 0, end = 0;
988     if(selectedRegionOnly && selectionGroup!=null)
989     {
990       iSize = selectionGroup.getSize(false);
991       seqs = selectionGroup.getSequencesInOrder(alignment);
992       start = selectionGroup.getStartRes();
993       end = selectionGroup.getEndRes()+1;
994     }
995     else
996     {
997       iSize = alignment.getHeight();
998       seqs = alignment.getSequencesArray();
999       end = alignment.getWidth();
1000     }
1001
1002     selection = new String[iSize];
1003
1004
1005     for(i=0; i<iSize; i++)
1006     {
1007       if (hasHiddenColumns)
1008       {
1009            StringBuffer visibleSeq = new StringBuffer();
1010            Vector regions = colSel.getHiddenColumns();
1011
1012            int blockStart = start, blockEnd=end;
1013            int [] region;
1014            int hideStart, hideEnd;
1015
1016            for (int j = 0; j < regions.size(); j++)
1017            {
1018              region = (int[]) regions.elementAt(j);
1019              hideStart = region[0];
1020              hideEnd = region[1];
1021
1022              if(hideStart < start)
1023              {
1024                continue;
1025              }
1026
1027              blockStart = Math.min(blockStart, hideEnd+1);
1028              blockEnd = Math.min(blockEnd, hideStart);
1029
1030              if(blockStart>blockEnd)
1031              {
1032                 break;
1033              }
1034
1035
1036              visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
1037
1038              blockStart = hideEnd+1;
1039              blockEnd = end;
1040            }
1041
1042            if(end>blockStart)
1043              visibleSeq.append(seqs[i].getSequence(blockStart, end));
1044
1045            selection[i] = visibleSeq.toString();
1046       }
1047       else
1048       {
1049         selection[i] = seqs[i].getSequence(start, end);
1050       }
1051     }
1052
1053     return selection;
1054   }
1055
1056   public boolean getShowHiddenMarkers()
1057   {
1058     return showHiddenMarkers;
1059   }
1060
1061   public void setShowHiddenMarkers(boolean show)
1062   {
1063     showHiddenMarkers = show;
1064   }
1065
1066
1067 }