eb832f2f68a8b3c2c58dd8c415176c10bec59906
[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
54   boolean colourAppliesToAllGroups = true;
55   ColourSchemeI globalColourScheme = null;
56   boolean conservationColourSelected = false;
57   boolean abovePIDThreshold = false;
58
59   SequenceGroup selectionGroup;
60
61   int charHeight;
62   int charWidth;
63   int wrappedWidth;
64
65   Font font = new Font("SansSerif", Font.PLAIN, 10);
66   boolean validCharWidth = true;
67   AlignmentI alignment;
68
69   ColumnSelection colSel = new ColumnSelection();
70
71   int threshold;
72   int increment;
73
74   NJTree currentTree = null;
75
76   boolean scaleAboveWrapped = true;
77   boolean scaleLeftWrapped = true;
78   boolean scaleRightWrapped = true;
79
80   // The following vector holds the features which are
81  // currently visible, in the correct order or rendering
82   Hashtable featuresDisplayed;
83
84   boolean hasHiddenColumns = false;
85   boolean hasHiddenRows = false;
86   boolean showHiddenMarkers = true;
87
88
89   public Vector vconsensus;
90   AlignmentAnnotation consensus;
91   AlignmentAnnotation conservation;
92   AlignmentAnnotation quality;
93
94   boolean autocalculateConsensus = true;
95
96   public int ConsPercGaps = 25; // JBPNote : This should be a scalable property!
97
98   private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(this);
99
100   boolean ignoreGapsInConsensusCalculation = false;
101
102   jalview.bin.JalviewLite applet;
103
104   boolean MAC = false;
105
106   public AlignViewport(AlignmentI al, JalviewLite applet)
107   {
108     this.applet = applet;
109     setAlignment(al);
110     this.startRes = 0;
111     this.endRes = al.getWidth() - 1;
112     this.startSeq = 0;
113     this.endSeq = al.getHeight() - 1;
114     setFont(font);
115
116     if(System.getProperty("os.name").startsWith("Mac"))
117       MAC = true;
118
119     if (applet != null)
120     {
121       String param = applet.getParameter("showFullId");
122       if (param != null)
123       {
124         showJVSuffix = Boolean.valueOf(param).booleanValue();
125       }
126
127       param = applet.getParameter("showAnnotation");
128       if (param != null)
129       {
130         showAnnotation = Boolean.valueOf(param).booleanValue();
131       }
132
133       param = applet.getParameter("showConservation");
134       if (param != null)
135       {
136         showConservation = Boolean.valueOf(param).booleanValue();
137       }
138
139       param = applet.getParameter("showQuality");
140       if (param != null)
141       {
142         showQuality = Boolean.valueOf(param).booleanValue();
143       }
144
145       param = applet.getParameter("showConsensus");
146       if (param != null)
147       {
148         showConsensus = Boolean.valueOf(param).booleanValue();
149       }
150     }
151     // We must set conservation and consensus before setting colour,
152     // as Blosum and Clustal require this to be done
153     updateConservation();
154     updateConsensus();
155
156
157     if (applet != null)
158     {
159       String colour = applet.getParameter("defaultColour");
160
161       if(colour == null)
162       {
163         colour = applet.getParameter("userDefinedColour");
164         if(colour !=null)
165           colour = "User Defined";
166       }
167
168       if(colour != null)
169       {
170         globalColourScheme = ColourSchemeProperty.getColour(alignment, colour);
171         if (globalColourScheme != null)
172         {
173           globalColourScheme.setConsensus(vconsensus);
174         }
175       }
176
177       if(applet.getParameter("userDefinedColour")!=null)
178       {
179         ((UserColourScheme)globalColourScheme).parseAppletParameter(
180             applet.getParameter("userDefinedColour"));
181       }
182
183
184     }
185   }
186
187   public void showSequenceFeatures(boolean b)
188   {
189     showSequenceFeatures = b;
190   }
191
192   public boolean getShowSequenceFeatures()
193   {
194     return showSequenceFeatures;
195   }
196
197
198   public void updateConservation()
199   {
200     if(alignment.isNucleotide())
201           return;
202
203     Conservation cons = new jalview.analysis.Conservation("All",
204         jalview.schemes.ResidueProperties.propHash, 3,
205         alignment.getSequences(), 0,
206         alignment.getWidth() - 1);
207     cons.calculate();
208     cons.verdict(false, ConsPercGaps);
209     cons.findQuality();
210     int alWidth = alignment.getWidth();
211     Annotation[] annotations = new Annotation[alWidth];
212     Annotation[] qannotations = new Annotation[alWidth];
213     String sequence = cons.getConsSequence().getSequence();
214     float minR, minG, minB, maxR, maxG, maxB;
215     minR = 0.3f;
216     minG = 0.0f;
217     minB = 0f;
218     maxR = 1.0f - minR;
219     maxG = 0.9f - minG;
220     maxB = 0f - minB; // scalable range for colouring both Conservation and Quality
221     float min = 0f;
222     float max = 11f;
223     float qmin = cons.qualityRange[0].floatValue();
224     float qmax = cons.qualityRange[1].floatValue();
225
226     for (int i = 0; i < alWidth; i++)
227     {
228       float value = 0;
229       try
230       {
231         value = Integer.parseInt(sequence.charAt(i) + "");
232       }
233       catch (Exception ex)
234       {
235         if (sequence.charAt(i) == '*')
236         {
237           value = 11;
238         }
239         if (sequence.charAt(i) == '+')
240         {
241           value = 10;
242         }
243       }
244       float vprop = value - min;
245       vprop /= max;
246
247       annotations[i] = new Annotation(sequence.charAt(i) + "",
248                                       "", ' ', value,
249                                       new Color(minR + maxR * vprop,
250                                                 minG + maxG * vprop,
251                                                 minB + maxB * vprop));
252       // Quality calc
253       value = ( (Double) cons.quality.elementAt(i)).floatValue();
254       vprop = value - qmin;
255       vprop /= qmax;
256       qannotations[i] = new Annotation(" ",
257                                        String.valueOf(value), ' ', value,
258                                        new
259                                        Color(minR + maxR * vprop,
260                                              minG + maxG * vprop,
261                                              minB + maxB * vprop));
262     }
263
264     if (conservation == null)
265     {
266       conservation = new AlignmentAnnotation("Conservation",
267                                              "Conservation of total alignment less than " +
268                                              ConsPercGaps + "% gaps",
269                                              annotations,
270                                              0f, // cons.qualityRange[0].floatValue(),
271                                              11f, // cons.qualityRange[1].floatValue()
272                                              AlignmentAnnotation.BAR_GRAPH);
273       if (showConservation)
274       {
275         alignment.addAnnotation(conservation);
276       }
277       quality = new AlignmentAnnotation("Quality",
278                                         "Alignment Quality based on Blosum62 scores",
279                                         qannotations,
280                                         cons.qualityRange[0].floatValue(),
281                                         cons.qualityRange[1].floatValue(),
282                                         AlignmentAnnotation.BAR_GRAPH);
283       if (showQuality)
284       {
285         alignment.addAnnotation(quality);
286       }
287     }
288     else
289     {
290       conservation.annotations = annotations;
291       quality.annotations = qannotations;
292       quality.graphMax = cons.qualityRange[1].floatValue();
293     }
294
295   }
296
297   public void updateConsensus()
298   {
299     Annotation[] annotations = new Annotation[alignment.getWidth()];
300
301     // this routine prevents vconsensus becoming a new object each time
302     // consenus is calculated. Important for speed of Blosum62
303     // and PID colouring of alignment
304     if (vconsensus == null)
305     {
306       vconsensus = alignment.getAAFrequency();
307     }
308     else
309     {
310       Vector temp = alignment.getAAFrequency();
311       vconsensus.removeAllElements();
312       Enumeration e = temp.elements();
313       while (e.hasMoreElements())
314       {
315         vconsensus.addElement(e.nextElement());
316       }
317     }
318     Hashtable hash = null;
319     for (int i = 0; i < alignment.getWidth(); i++)
320     {
321       hash = (Hashtable) vconsensus.elementAt(i);
322       float value = 0;
323       if(ignoreGapsInConsensusCalculation)
324         value = ((Float)hash.get("pid_nogaps")).floatValue();
325       else
326         value = ((Float)hash.get("pid_gaps")).floatValue();
327
328       String maxRes = hash.get("maxResidue").toString();
329       String mouseOver = hash.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(vconsensus);
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
498   public Font getFont()
499   {
500     return font;
501   }
502
503   public int getCharWidth()
504   {
505     return charWidth;
506   }
507
508   public void setCharHeight(int h)
509   {
510     this.charHeight = h;
511   }
512
513   public int getCharHeight()
514   {
515     return charHeight;
516   }
517
518   public void setWrappedWidth(int w)
519   {
520     this.wrappedWidth = w;
521   }
522
523   public int getwrappedWidth()
524   {
525     return wrappedWidth;
526   }
527
528   public AlignmentI getAlignment()
529   {
530     return alignment;
531   }
532
533   public void setAlignment(AlignmentI align)
534   {
535     this.alignment = align;
536   }
537
538   public void setWrapAlignment(boolean state)
539   {
540     wrapAlignment = state;
541   }
542
543   public void setShowText(boolean state)
544   {
545     showText = state;
546   }
547
548   public void setRenderGaps(boolean state)
549   {
550     renderGaps = state;
551   }
552
553   public boolean getColourText()
554   {
555     return showColourText;
556   }
557
558   public void setColourText(boolean state)
559   {
560     showColourText = state;
561   }
562
563   public void setShowBoxes(boolean state)
564   {
565     showBoxes = state;
566   }
567
568   public boolean getWrapAlignment()
569   {
570     return wrapAlignment;
571   }
572
573   public boolean getShowText()
574   {
575     return showText;
576   }
577
578   public boolean getShowBoxes()
579   {
580     return showBoxes;
581   }
582
583   public char getGapCharacter()
584   {
585     return getAlignment().getGapCharacter();
586   }
587
588   public void setGapCharacter(char gap)
589   {
590     if (getAlignment() != null)
591     {
592       getAlignment().setGapCharacter(gap);
593     }
594   }
595
596   public void setThreshold(int thresh)
597   {
598     threshold = thresh;
599   }
600
601   public int getThreshold()
602   {
603     return threshold;
604   }
605
606   public void setIncrement(int inc)
607   {
608     increment = inc;
609   }
610
611   public int getIncrement()
612   {
613     return increment;
614   }
615
616   public void setHiddenColumns(ColumnSelection colsel)
617   {
618     this.colSel = colsel;
619     if(colSel.getHiddenColumns()!=null)
620       hasHiddenColumns = true;
621   }
622
623   public ColumnSelection getColumnSelection()
624   {
625     return colSel;
626   }
627
628   public void resetSeqLimits(int height)
629   {
630     setEndSeq(height / getCharHeight());
631   }
632
633   public void setCurrentTree(NJTree tree)
634   {
635     currentTree = tree;
636   }
637
638   public NJTree getCurrentTree()
639   {
640     return currentTree;
641   }
642
643   public void setColourAppliesToAllGroups(boolean b)
644   {
645     colourAppliesToAllGroups = b;
646   }
647
648   public boolean getColourAppliesToAllGroups()
649   {
650     return colourAppliesToAllGroups;
651   }
652
653   public boolean getShowJVSuffix()
654   {
655     return showJVSuffix;
656   }
657
658   public void setShowJVSuffix(boolean b)
659   {
660     showJVSuffix = b;
661   }
662
663   public boolean getShowAnnotation()
664   {
665     return showAnnotation;
666   }
667
668   public void setShowAnnotation(boolean b)
669   {
670     showAnnotation = b;
671   }
672
673   public boolean getScaleAboveWrapped()
674   {
675     return scaleAboveWrapped;
676   }
677
678   public boolean getScaleLeftWrapped()
679   {
680     return scaleLeftWrapped;
681   }
682
683   public boolean getScaleRightWrapped()
684   {
685     return scaleRightWrapped;
686   }
687
688   public void setScaleAboveWrapped(boolean b)
689   {
690     scaleAboveWrapped = b;
691   }
692
693   public void setScaleLeftWrapped(boolean b)
694   {
695     scaleLeftWrapped = b;
696   }
697
698   public void setScaleRightWrapped(boolean b)
699   {
700     scaleRightWrapped = b;
701   }
702
703   public void setIgnoreGapsConsensus(boolean b)
704   {
705     ignoreGapsInConsensusCalculation = b;
706     updateConsensus();
707     if (globalColourScheme!=null)
708     {
709       globalColourScheme.setThreshold(globalColourScheme.getThreshold(),
710           ignoreGapsInConsensusCalculation);
711
712     }
713   }
714
715   /**
716    * Property change listener for changes in alignment
717    *
718    * @param listener DOCUMENT ME!
719    */
720   public void addPropertyChangeListener(
721       java.beans.PropertyChangeListener listener)
722   {
723       changeSupport.addPropertyChangeListener(listener);
724   }
725
726   /**
727    * DOCUMENT ME!
728    *
729    * @param listener DOCUMENT ME!
730    */
731   public void removePropertyChangeListener(
732       java.beans.PropertyChangeListener listener)
733   {
734       changeSupport.removePropertyChangeListener(listener);
735   }
736
737   /**
738    * Property change listener for changes in alignment
739    *
740    * @param prop DOCUMENT ME!
741    * @param oldvalue DOCUMENT ME!
742    * @param newvalue DOCUMENT ME!
743    */
744   public void firePropertyChange(String prop, Object oldvalue, Object newvalue)
745   {
746       changeSupport.firePropertyChange(prop, oldvalue, newvalue);
747   }
748
749
750
751   public boolean getIgnoreGapsConsensus()
752   {
753     return ignoreGapsInConsensusCalculation;
754   }
755   public void hideSelectedColumns()
756   {
757     if (colSel.size() < 1)
758       return;
759
760     colSel.hideSelectedColumns();
761     setSelectionGroup(null);
762
763     hasHiddenColumns = true;
764   }
765
766   public void invertColumnSelection()
767   {
768     int column;
769     for (int i = 0; i < alignment.getWidth(); i++)
770     {
771       column = i;
772
773       if (colSel.contains(column))
774         colSel.removeElement(column);
775       else
776         colSel.addElement(column);
777
778     }
779   }
780
781
782   public void hideColumns(int start, int end)
783   {
784     if(start==end)
785       colSel.hideColumns(start);
786     else
787       colSel.hideColumns(start, end);
788
789     hasHiddenColumns = true;
790   }
791
792   public void hideSequence(SequenceI seq)
793   {
794     if(seq!=null)
795     {
796       alignment.getHiddenSequences().hideSequence(seq);
797       hasHiddenRows = true;
798       firePropertyChange("alignment", null, alignment.getSequences());
799     }
800   }
801
802   public void hideAllSelectedSeqs()
803   {
804     if (selectionGroup == null)
805       return;
806
807     SequenceI[] seqs = selectionGroup.getSequencesInOrder(alignment);
808
809     for (int i = 0; i < seqs.length; i++)
810     {
811       alignment.getHiddenSequences().hideSequence(seqs[i]);
812     }
813     firePropertyChange("alignment", null, alignment.getSequences());
814     hasHiddenRows = true;
815     setSelectionGroup(null);
816   }
817
818   public void showColumn(int col)
819   {
820     colSel.revealHiddenColumns(col);
821     if(colSel.getHiddenColumns()==null)
822       hasHiddenColumns = false;
823   }
824
825   public void showAllHiddenColumns()
826   {
827     colSel.revealAllHiddenColumns();
828     hasHiddenColumns = false;
829   }
830
831   public void showAllHiddenSeqs()
832   {
833     if(alignment.getHiddenSequences().getSize()>0)
834     {
835       if(selectionGroup==null)
836       {
837         selectionGroup = new SequenceGroup();
838         selectionGroup.setEndRes(alignment.getWidth()-1);
839       }
840       Vector tmp = alignment.getHiddenSequences().showAll();
841       for(int t=0; t<tmp.size(); t++)
842       {
843         selectionGroup.addSequence(
844             (SequenceI)tmp.elementAt(t), false
845             );
846       }
847       firePropertyChange("alignment", null, alignment.getSequences());
848       hasHiddenRows = false;
849     }
850   }
851
852   public int adjustForHiddenSeqs(int alignmentIndex)
853   {
854     return alignment.getHiddenSequences().adjustForHiddenSeqs(alignmentIndex);
855   }
856
857   /**
858    * This method returns the a new SequenceI [] with
859    * the selection sequence and start and end points adjusted
860    * @return String[]
861    */
862   public SequenceI[] getSelectionAsNewSequence()
863   {
864     SequenceI[] sequences;
865
866     if (selectionGroup == null)
867       sequences = alignment.getSequencesArray();
868     else
869       sequences = selectionGroup.getSelectionAsNewSequences(alignment);
870
871     return sequences;
872   }
873
874   /**
875    * This method returns the visible alignment as text, as
876    * seen on the GUI, ie if columns are hidden they will not
877    * be returned in the result.
878    * Use this for calculating trees, PCA, redundancy etc on views
879    * which contain hidden columns.
880    * @return String[]
881    */
882   public jalview.datamodel.CigarArray getViewAsCigars(boolean selectedRegionOnly)
883   {
884     CigarArray selection=null;
885     SequenceI [] seqs= null;
886     int i, iSize;
887     int start = 0, end = 0;
888     if(selectedRegionOnly && selectionGroup!=null)
889     {
890       iSize = selectionGroup.getSize(false);
891       seqs = selectionGroup.getSequencesInOrder(alignment);
892       start = selectionGroup.getStartRes();
893       end = selectionGroup.getEndRes(); // inclusive for start and end in SeqCigar constructor
894     }
895     else
896     {
897       iSize = alignment.getHeight();
898       seqs = alignment.getSequencesArray();
899       end = alignment.getWidth()-1;
900     }
901     SeqCigar[] selseqs = new SeqCigar[iSize];
902     for(i=0; i<iSize; i++)
903     {
904       selseqs[i] = new SeqCigar(seqs[i], start, end);
905     }
906     selection=new CigarArray(selseqs);
907     // now construct the CigarArray operations
908     if (hasHiddenColumns) {
909       Vector regions = colSel.getHiddenColumns();
910       int [] region;
911       int hideStart, hideEnd;
912       int last=start;
913       for (int j = 0; last<end & j < regions.size(); j++)
914       {
915         region = (int[]) regions.elementAt(j);
916         hideStart = region[0];
917         hideEnd = region[1];
918         // edit hidden regions to selection range
919         if(hideStart<last) {
920           if (hideEnd > last)
921           {
922             hideStart = last;
923           } else
924             continue;
925         }
926
927         if (hideStart>end)
928           break;
929
930         if (hideEnd>end)
931           hideEnd=end;
932
933         if (hideStart>hideEnd)
934           break;
935         /**
936          * form operations...
937          */
938         if (last<hideStart)
939           selection.addOperation(CigarArray.M, hideStart-last);
940         selection.addOperation(CigarArray.D, 1+hideEnd-hideStart);
941         last = hideEnd+1;
942       }
943       // Final match if necessary.
944       if (last<end)
945         selection.addOperation(CigarArray.M, end-last);
946     } else {
947       selection.addOperation(CigarArray.M, end-start);
948     }
949     return selection;
950   }
951   /**
952    * return a compact representation of the current alignment selection to
953    * pass to an analysis function
954    * @param selectedOnly boolean true to just return the selected view
955    * @return AlignmentView
956    */
957   jalview.datamodel.AlignmentView getAlignmentView(boolean selectedOnly) {
958     // JBPNote:
959     // this is here because the AlignmentView constructor modifies the CigarArray
960     // object. Refactoring of Cigar and alignment view representation should
961     // be done to remove redundancy.
962     CigarArray aligview = getViewAsCigars(selectedOnly);
963     if (aligview!=null)
964       return new AlignmentView(aligview);
965     return null;
966   }
967   /**
968    * This method returns the visible alignment as text, as
969    * seen on the GUI, ie if columns are hidden they will not
970    * be returned in the result.
971    * Use this for calculating trees, PCA, redundancy etc on views
972    * which contain hidden columns.
973    * @return String[]
974    */
975   public String [] getViewAsString(boolean selectedRegionOnly)
976   {
977     String [] selection = null;
978     SequenceI [] seqs= null;
979     int i, iSize;
980     int start = 0, end = 0;
981     if(selectedRegionOnly && selectionGroup!=null)
982     {
983       iSize = selectionGroup.getSize(false);
984       seqs = selectionGroup.getSequencesInOrder(alignment);
985       start = selectionGroup.getStartRes();
986       end = selectionGroup.getEndRes()+1;
987     }
988     else
989     {
990       iSize = alignment.getHeight();
991       seqs = alignment.getSequencesArray();
992       end = alignment.getWidth();
993     }
994
995     selection = new String[iSize];
996
997
998     for(i=0; i<iSize; i++)
999     {
1000       if (hasHiddenColumns)
1001       {
1002            StringBuffer visibleSeq = new StringBuffer();
1003            Vector regions = colSel.getHiddenColumns();
1004
1005            int blockStart = start, blockEnd=end;
1006            int [] region;
1007            int hideStart, hideEnd;
1008
1009            for (int j = 0; j < regions.size(); j++)
1010            {
1011              region = (int[]) regions.elementAt(j);
1012              hideStart = region[0];
1013              hideEnd = region[1];
1014
1015              if(hideStart < start)
1016              {
1017                continue;
1018              }
1019
1020              blockStart = Math.min(blockStart, hideEnd+1);
1021              blockEnd = Math.min(blockEnd, hideStart);
1022
1023              if(blockStart>blockEnd)
1024              {
1025                 break;
1026              }
1027
1028
1029              visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
1030
1031              blockStart = hideEnd+1;
1032              blockEnd = end;
1033            }
1034
1035            if(end>blockStart)
1036              visibleSeq.append(seqs[i].getSequence(blockStart, end));
1037
1038            selection[i] = visibleSeq.toString();
1039       }
1040       else
1041       {
1042         selection[i] = seqs[i].getSequence(start, end);
1043       }
1044     }
1045
1046     return selection;
1047   }
1048
1049   public boolean getShowHiddenMarkers()
1050   {
1051     return showHiddenMarkers;
1052   }
1053
1054   public void setShowHiddenMarkers(boolean show)
1055   {
1056     showHiddenMarkers = show;
1057   }
1058
1059
1060 }