Multiple Views
[jalview.git] / src / jalview / gui / 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 package jalview.gui;
20
21 import jalview.analysis.*;
22
23 import jalview.bin.*;
24
25 import jalview.datamodel.*;
26
27 import jalview.schemes.*;
28
29 import java.awt.*;
30
31 import java.util.*;
32
33
34 /**
35  * DOCUMENT ME!
36  *
37  * @author $author$
38  * @version $Revision$
39  */
40 public class AlignViewport
41 {
42     int startRes;
43     int endRes;
44     int startSeq;
45     int endSeq;
46     boolean showJVSuffix = true;
47     boolean showText = true;
48     boolean showColourText = false;
49     boolean showBoxes = true;
50     boolean wrapAlignment = false;
51     boolean renderGaps = true;
52     boolean showSequenceFeatures = false;
53     boolean showAnnotation = true;
54     boolean showConservation = true;
55     boolean showQuality = true;
56     boolean showIdentity = true;
57     boolean colourAppliesToAllGroups = true;
58     ColourSchemeI globalColourScheme = null;
59     boolean conservationColourSelected = false;
60     boolean abovePIDThreshold = false;
61     SequenceGroup selectionGroup;
62     int charHeight;
63     int charWidth;
64     boolean validCharWidth;
65     int wrappedWidth;
66     Font font;
67     AlignmentI alignment;
68     ColumnSelection colSel = new ColumnSelection();
69     int threshold;
70     int increment;
71     NJTree currentTree = null;
72     boolean scaleAboveWrapped = false;
73     boolean scaleLeftWrapped = true;
74     boolean scaleRightWrapped = true;
75     boolean hasHiddenColumns = false;
76     boolean hasHiddenRows = false;
77     boolean showHiddenMarkers = true;
78
79     boolean cursorMode = false;
80
81     // The following vector holds the features which are
82     // currently visible, in the correct order or rendering
83     Hashtable featuresDisplayed = null;
84
85
86     /** DOCUMENT ME!! */
87     public Vector vconsensus;
88     AlignmentAnnotation consensus;
89     AlignmentAnnotation conservation;
90     AlignmentAnnotation quality;
91     boolean autoCalculateConsensus = true;
92
93     /** DOCUMENT ME!! */
94     public int ConsPercGaps = 25; // JBPNote : This should be a scalable property!
95
96     // JBPNote Prolly only need this in the applet version.
97     private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(this);
98
99     boolean ignoreGapsInConsensusCalculation = false;
100
101     boolean isDataset = false;
102
103     boolean antiAlias = false;
104
105     boolean padGaps = false;
106
107     Rectangle explodedPosition;
108
109     String viewName;
110
111     String sequenceSetID;
112
113     boolean gatherViewsHere = false;
114
115
116     public AlignViewport(AlignmentI al, boolean dataset)
117     {
118       isDataset = dataset;
119       setAlignment(al);
120       init();
121     }
122     /**
123      * Creates a new AlignViewport object.
124      *
125      * @param al DOCUMENT ME!
126      */
127     public AlignViewport(AlignmentI al)
128     {
129         setAlignment(al);
130         init();
131     }
132     /**
133      * Create a new AlignViewport with hidden regions
134      * @param al AlignmentI
135      * @param hiddenColumns ColumnSelection
136      */
137     public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns) {
138       setAlignment(al);
139       if (hiddenColumns!=null) {
140         this.colSel = hiddenColumns;
141         if (hiddenColumns.getHiddenColumns() != null)
142           hasHiddenColumns = true;
143       }
144       init();
145     }
146
147     void init()
148     {
149         this.startRes = 0;
150         this.endRes = alignment.getWidth() - 1;
151         this.startSeq = 0;
152         this.endSeq = alignment.getHeight() - 1;
153
154       antiAlias = Cache.getDefault("ANTI_ALIAS", false);
155
156       showJVSuffix = Cache.getDefault("SHOW_JVSUFFIX", true);
157       showAnnotation = Cache.getDefault("SHOW_ANNOTATIONS", true);
158       showConservation = Cache.getDefault("SHOW_CONSERVATION", true);
159
160       showQuality = Cache.getDefault("SHOW_QUALITY", true);
161       showIdentity = Cache.getDefault("SHOW_IDENTITY", true);
162
163       autoCalculateConsensus = Cache.getDefault("AUTO_CALC_CONSENSUS", true);
164
165       padGaps = Cache.getDefault("PAD_GAPS", false);
166
167        String fontName = Cache.getDefault("FONT_NAME", "SansSerif");
168        String fontStyle = Cache.getDefault("FONT_STYLE", Font.PLAIN + "") ;
169        String fontSize = Cache.getDefault("FONT_SIZE", "10");
170
171        int style = 0;
172
173        if (fontStyle.equals("bold"))
174        {
175          style = 1;
176        }
177        else if (fontStyle.equals("italic"))
178        {
179          style = 2;
180        }
181
182        setFont(new Font(fontName, style, Integer.parseInt(fontSize)));
183
184
185        alignment.setGapCharacter( Cache.getDefault("GAP_SYMBOL", "-").charAt(0) );
186
187
188         // We must set conservation and consensus before setting colour,
189         // as Blosum and Clustal require this to be done
190         if(vconsensus==null && !isDataset)
191         {
192           updateConservation();
193           updateConsensus();
194         }
195
196         if (jalview.bin.Cache.getProperty("DEFAULT_COLOUR") != null)
197         {
198           globalColourScheme = ColourSchemeProperty.getColour(alignment,
199               jalview.bin.Cache.getProperty("DEFAULT_COLOUR"));
200
201             if (globalColourScheme instanceof UserColourScheme)
202             {
203                 globalColourScheme = UserDefinedColours.loadDefaultColours();
204                 ((UserColourScheme)globalColourScheme).setThreshold(0, getIgnoreGapsConsensus());
205             }
206
207             if (globalColourScheme != null)
208             {
209                 globalColourScheme.setConsensus(vconsensus);
210             }
211         }
212     }
213
214
215
216     /**
217      * DOCUMENT ME!
218      *
219      * @param b DOCUMENT ME!
220      */
221     public void setShowSequenceFeatures(boolean b)
222     {
223         showSequenceFeatures = b;
224     }
225
226     public boolean getShowSequenceFeatures()
227     {
228       return showSequenceFeatures;
229     }
230
231     /**
232      * DOCUMENT ME!
233      */
234     public void updateConservation()
235     {
236       if(alignment.isNucleotide())
237           return;
238
239       try{
240         Conservation cons = new jalview.analysis.Conservation("All",
241             jalview.schemes.ResidueProperties.propHash, 3,
242             alignment.getSequences(), 0, alignment.getWidth() - 1);
243         cons.calculate();
244         cons.verdict(false, ConsPercGaps);
245         cons.findQuality();
246
247         int alWidth = alignment.getWidth();
248         Annotation[] annotations = new Annotation[alWidth];
249         Annotation[] qannotations = new Annotation[alWidth];
250         String sequence = cons.getConsSequence().getSequence();
251         float minR;
252         float minG;
253         float minB;
254         float maxR;
255         float maxG;
256         float maxB;
257         minR = 0.3f;
258         minG = 0.0f;
259         minB = 0f;
260         maxR = 1.0f - minR;
261         maxG = 0.9f - minG;
262         maxB = 0f - minB; // scalable range for colouring both Conservation and Quality
263
264         float min = 0f;
265         float max = 11f;
266         float qmin = cons.qualityRange[0].floatValue();
267         float qmax = cons.qualityRange[1].floatValue();
268
269         for (int i = 0; i < alWidth; i++)
270         {
271           float value = 0;
272
273           try
274           {
275             value = Integer.parseInt(sequence.charAt(i) + "");
276           }
277           catch (Exception ex)
278           {
279             if (sequence.charAt(i) == '*')
280             {
281               value = 11;
282             }
283
284             if (sequence.charAt(i) == '+')
285             {
286               value = 10;
287             }
288           }
289
290           float vprop = value - min;
291           vprop /= max;
292           annotations[i] = new Annotation(sequence.charAt(i) + "",
293                                           String.valueOf(value), ' ', value,
294                                           new Color(minR + (maxR * vprop),
295               minG + (maxG * vprop),
296               minB + (maxB * vprop)));
297
298           // Quality calc
299           value = ( (Double) cons.quality.get(i)).floatValue();
300           vprop = value - qmin;
301           vprop /= qmax;
302           qannotations[i] = new Annotation(" ", String.valueOf(value), ' ',
303                                            value,
304                                            new Color(minR + (maxR * vprop),
305               minG + (maxG * vprop),
306               minB + (maxB * vprop)));
307         }
308
309         if (conservation == null)
310         {
311           conservation = new AlignmentAnnotation("Conservation",
312                                                  "Conservation of total alignment less than " +
313                                                  ConsPercGaps + "% gaps",
314                                                  annotations, 0f, // cons.qualityRange[0].floatValue(),
315                                                  11f, // cons.qualityRange[1].floatValue()
316                                                  AlignmentAnnotation.BAR_GRAPH);
317
318           if (showConservation)
319           {
320             alignment.addAnnotation(conservation);
321           }
322
323           quality = new AlignmentAnnotation("Quality",
324                                             "Alignment Quality based on Blosum62 scores",
325                                             qannotations,
326                                             cons.qualityRange[0].floatValue(),
327                                             cons.qualityRange[1].floatValue(),
328                                             AlignmentAnnotation.BAR_GRAPH);
329
330           if (showQuality)
331           {
332             alignment.addAnnotation(quality);
333           }
334         }
335         else
336         {
337           conservation.annotations = annotations;
338           quality.annotations = qannotations;
339           quality.graphMax = cons.qualityRange[1].floatValue();
340         }
341       }
342       catch (OutOfMemoryError error)
343       {
344         javax.swing.SwingUtilities.invokeLater(new Runnable()
345         {
346           public void run()
347           {
348             javax.swing.JOptionPane.showInternalMessageDialog(Desktop.desktop,
349                 "Out of memory calculating conservation!!"
350                 +
351                 "\nSee help files for increasing Java Virtual Machine memory."
352                 , "Out of memory",
353                 javax.swing.JOptionPane.WARNING_MESSAGE);
354           }
355         });
356
357         System.out.println("Conservation calculation: " + error);
358         System.gc();
359
360       }
361     }
362
363     /**
364      * DOCUMENT ME!
365      */
366     public void updateConsensus()
367     {
368       try{
369         Annotation[] annotations = new Annotation[alignment.getWidth()];
370
371         // this routine prevents vconsensus becoming a new object each time
372         // consenus is calculated. Important for speed of Blosum62
373         // and PID colouring of alignment
374         if (vconsensus == null)
375         {
376           vconsensus = alignment.getAAFrequency();
377         }
378         else
379         {
380           Vector temp = alignment.getAAFrequency();
381           vconsensus.clear();
382
383           Enumeration e = temp.elements();
384
385           while (e.hasMoreElements())
386           {
387             vconsensus.add(e.nextElement());
388           }
389         }
390
391         Hashtable hash = null;
392
393         for (int i = 0; i < alignment.getWidth(); i++)
394         {
395           hash = (Hashtable) vconsensus.elementAt(i);
396
397           float value = 0;
398           if (ignoreGapsInConsensusCalculation)
399             value = ( (Float) hash.get("pid_nogaps")).floatValue();
400           else
401             value = ( (Float) hash.get("pid_gaps")).floatValue();
402
403           String maxRes = hash.get("maxResidue").toString();
404           String mouseOver = hash.get("maxResidue") + " ";
405
406           if (maxRes.length() > 1)
407           {
408             mouseOver = "[" + maxRes + "] ";
409             maxRes = "+";
410           }
411
412           mouseOver += ( (int) value + "%");
413           annotations[i] = new Annotation(maxRes, mouseOver, ' ', value);
414         }
415
416         if (consensus == null)
417         {
418           consensus = new AlignmentAnnotation("Consensus", "PID",
419                                               annotations, 0f, 100f,AlignmentAnnotation.BAR_GRAPH);
420
421           if (showIdentity)
422           {
423             alignment.addAnnotation(consensus);
424           }
425         }
426         else
427         {
428           consensus.annotations = annotations;
429         }
430
431         if (globalColourScheme != null)
432           globalColourScheme.setConsensus(vconsensus);
433
434       }catch(OutOfMemoryError error)
435       {
436         javax.swing.SwingUtilities.invokeLater(new Runnable()
437         {
438           public void run()
439           {
440             javax.swing.JOptionPane.showInternalMessageDialog(Desktop.desktop,
441                 "Out of memory calculating consensus!!"
442                 +
443                 "\nSee help files for increasing Java Virtual Machine memory."
444                 , "Out of memory",
445                 javax.swing.JOptionPane.WARNING_MESSAGE);
446           }
447         });
448
449
450         System.out.println("Consensus calculation: " + error);
451         System.gc();
452       }
453
454     }
455     /**
456      * get the consensus sequence as displayed under the PID consensus annotation row.
457      * @return consensus sequence as a new sequence object
458      */
459     public SequenceI getConsensusSeq() {
460       if (consensus==null)
461         updateConsensus();
462       if (consensus==null)
463         return null;
464       StringBuffer seqs=new StringBuffer();
465       for (int i=0; i<consensus.annotations.length; i++) {
466         if (consensus.annotations[i]!=null) {
467           if (consensus.annotations[i].description.charAt(0) == '[')
468             seqs.append(consensus.annotations[i].description.charAt(1));
469           else
470             seqs.append(consensus.annotations[i].displayCharacter);
471         }
472       }
473       SequenceI sq = new Sequence("Consensus", seqs.toString());
474       sq.setDescription("Percentage Identity Consensus "+((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
475       return sq;
476     }
477     /**
478      * DOCUMENT ME!
479      *
480      * @return DOCUMENT ME!
481      */
482     public SequenceGroup getSelectionGroup()
483     {
484         return selectionGroup;
485     }
486
487     /**
488      * DOCUMENT ME!
489      *
490      * @param sg DOCUMENT ME!
491      */
492     public void setSelectionGroup(SequenceGroup sg)
493     {
494         selectionGroup = sg;
495     }
496
497     /**
498      * DOCUMENT ME!
499      *
500      * @return DOCUMENT ME!
501      */
502     public boolean getConservationSelected()
503     {
504         return conservationColourSelected;
505     }
506
507     /**
508      * DOCUMENT ME!
509      *
510      * @param b DOCUMENT ME!
511      */
512     public void setConservationSelected(boolean b)
513     {
514         conservationColourSelected = b;
515     }
516
517     /**
518      * DOCUMENT ME!
519      *
520      * @return DOCUMENT ME!
521      */
522     public boolean getAbovePIDThreshold()
523     {
524         return abovePIDThreshold;
525     }
526
527     /**
528      * DOCUMENT ME!
529      *
530      * @param b DOCUMENT ME!
531      */
532     public void setAbovePIDThreshold(boolean b)
533     {
534         abovePIDThreshold = b;
535     }
536
537     /**
538      * DOCUMENT ME!
539      *
540      * @return DOCUMENT ME!
541      */
542     public int getStartRes()
543     {
544         return startRes;
545     }
546
547     /**
548      * DOCUMENT ME!
549      *
550      * @return DOCUMENT ME!
551      */
552     public int getEndRes()
553     {
554         return endRes;
555     }
556
557     /**
558      * DOCUMENT ME!
559      *
560      * @return DOCUMENT ME!
561      */
562     public int getStartSeq()
563     {
564         return startSeq;
565     }
566
567     /**
568      * DOCUMENT ME!
569      *
570      * @param cs DOCUMENT ME!
571      */
572     public void setGlobalColourScheme(ColourSchemeI cs)
573     {
574         globalColourScheme = cs;
575     }
576
577     /**
578      * DOCUMENT ME!
579      *
580      * @return DOCUMENT ME!
581      */
582     public ColourSchemeI getGlobalColourScheme()
583     {
584         return globalColourScheme;
585     }
586
587     /**
588      * DOCUMENT ME!
589      *
590      * @param res DOCUMENT ME!
591      */
592     public void setStartRes(int res)
593     {
594         this.startRes = res;
595     }
596
597     /**
598      * DOCUMENT ME!
599      *
600      * @param seq DOCUMENT ME!
601      */
602     public void setStartSeq(int seq)
603     {
604         this.startSeq = seq;
605     }
606
607     /**
608      * DOCUMENT ME!
609      *
610      * @param res DOCUMENT ME!
611      */
612     public void setEndRes(int res)
613     {
614         if (res > (alignment.getWidth() - 1))
615         {
616             // log.System.out.println(" Corrected res from " + res + " to maximum " + (alignment.getWidth()-1));
617             res = alignment.getWidth() - 1;
618         }
619
620         if (res < 0)
621         {
622             res = 0;
623         }
624
625         this.endRes = res;
626     }
627
628     /**
629      * DOCUMENT ME!
630      *
631      * @param seq DOCUMENT ME!
632      */
633     public void setEndSeq(int seq)
634     {
635         if (seq > alignment.getHeight())
636         {
637             seq = alignment.getHeight();
638         }
639
640         if (seq < 0)
641         {
642             seq = 0;
643         }
644
645         this.endSeq = seq;
646     }
647
648     /**
649      * DOCUMENT ME!
650      *
651      * @return DOCUMENT ME!
652      */
653     public int getEndSeq()
654     {
655         return endSeq;
656     }
657
658     /**
659      * DOCUMENT ME!
660      *
661      * @param f DOCUMENT ME!
662      */
663     public void setFont(Font f)
664     {
665         font = f;
666
667         Container c = new Container();
668
669         java.awt.FontMetrics fm = c.getFontMetrics(font);
670         setCharHeight(fm.getHeight());
671         setCharWidth(fm.charWidth('M'));
672         validCharWidth = true;
673     }
674
675     /**
676      * DOCUMENT ME!
677      *
678      * @return DOCUMENT ME!
679      */
680     public Font getFont()
681     {
682         return font;
683     }
684
685     /**
686      * DOCUMENT ME!
687      *
688      * @param w DOCUMENT ME!
689      */
690     public void setCharWidth(int w)
691     {
692         this.charWidth = w;
693     }
694
695     /**
696      * DOCUMENT ME!
697      *
698      * @return DOCUMENT ME!
699      */
700     public int getCharWidth()
701     {
702         return charWidth;
703     }
704
705     /**
706      * DOCUMENT ME!
707      *
708      * @param h DOCUMENT ME!
709      */
710     public void setCharHeight(int h)
711     {
712         this.charHeight = h;
713     }
714
715     /**
716      * DOCUMENT ME!
717      *
718      * @return DOCUMENT ME!
719      */
720     public int getCharHeight()
721     {
722         return charHeight;
723     }
724
725     /**
726      * DOCUMENT ME!
727      *
728      * @param w DOCUMENT ME!
729      */
730     public void setWrappedWidth(int w)
731     {
732         this.wrappedWidth = w;
733     }
734
735     /**
736      * DOCUMENT ME!
737      *
738      * @return DOCUMENT ME!
739      */
740     public int getWrappedWidth()
741     {
742         return wrappedWidth;
743     }
744
745
746     /**
747      * DOCUMENT ME!
748      *
749      * @return DOCUMENT ME!
750      */
751     public AlignmentI getAlignment()
752     {
753         return alignment;
754     }
755
756     /**
757      * DOCUMENT ME!
758      *
759      * @param align DOCUMENT ME!
760      */
761     public void setAlignment(AlignmentI align)
762     {
763         this.alignment = align;
764     }
765
766     /**
767      * DOCUMENT ME!
768      *
769      * @param state DOCUMENT ME!
770      */
771     public void setWrapAlignment(boolean state)
772     {
773         wrapAlignment = state;
774     }
775
776     /**
777      * DOCUMENT ME!
778      *
779      * @param state DOCUMENT ME!
780      */
781     public void setShowText(boolean state)
782     {
783         showText = state;
784     }
785
786     /**
787      * DOCUMENT ME!
788      *
789      * @param state DOCUMENT ME!
790      */
791     public void setRenderGaps(boolean state)
792     {
793         renderGaps = state;
794     }
795
796     /**
797      * DOCUMENT ME!
798      *
799      * @return DOCUMENT ME!
800      */
801     public boolean getColourText()
802     {
803         return showColourText;
804     }
805
806     /**
807      * DOCUMENT ME!
808      *
809      * @param state DOCUMENT ME!
810      */
811     public void setColourText(boolean state)
812     {
813         showColourText = state;
814     }
815
816     /**
817      * DOCUMENT ME!
818      *
819      * @param state DOCUMENT ME!
820      */
821     public void setShowBoxes(boolean state)
822     {
823         showBoxes = state;
824     }
825
826     /**
827      * DOCUMENT ME!
828      *
829      * @return DOCUMENT ME!
830      */
831     public boolean getWrapAlignment()
832     {
833         return wrapAlignment;
834     }
835
836     /**
837      * DOCUMENT ME!
838      *
839      * @return DOCUMENT ME!
840      */
841     public boolean getShowText()
842     {
843         return showText;
844     }
845
846     /**
847      * DOCUMENT ME!
848      *
849      * @return DOCUMENT ME!
850      */
851     public boolean getShowBoxes()
852     {
853         return showBoxes;
854     }
855
856     /**
857      * DOCUMENT ME!
858      *
859      * @return DOCUMENT ME!
860      */
861     public char getGapCharacter()
862     {
863         return getAlignment().getGapCharacter();
864     }
865
866     /**
867      * DOCUMENT ME!
868      *
869      * @param gap DOCUMENT ME!
870      */
871     public void setGapCharacter(char gap)
872     {
873         if (getAlignment() != null)
874         {
875             getAlignment().setGapCharacter(gap);
876         }
877     }
878
879     /**
880      * DOCUMENT ME!
881      *
882      * @param thresh DOCUMENT ME!
883      */
884     public void setThreshold(int thresh)
885     {
886         threshold = thresh;
887     }
888
889     /**
890      * DOCUMENT ME!
891      *
892      * @return DOCUMENT ME!
893      */
894     public int getThreshold()
895     {
896         return threshold;
897     }
898
899     /**
900      * DOCUMENT ME!
901      *
902      * @param inc DOCUMENT ME!
903      */
904     public void setIncrement(int inc)
905     {
906         increment = inc;
907     }
908
909     /**
910      * DOCUMENT ME!
911      *
912      * @return DOCUMENT ME!
913      */
914     public int getIncrement()
915     {
916         return increment;
917     }
918
919
920     /**
921      * DOCUMENT ME!
922      *
923      * @return DOCUMENT ME!
924      */
925     public ColumnSelection getColumnSelection()
926     {
927         return colSel;
928     }
929
930
931     /**
932      * DOCUMENT ME!
933      *
934      * @param tree DOCUMENT ME!
935      */
936     public void setCurrentTree(NJTree tree)
937     {
938         currentTree = tree;
939     }
940
941     /**
942      * DOCUMENT ME!
943      *
944      * @return DOCUMENT ME!
945      */
946     public NJTree getCurrentTree()
947     {
948         return currentTree;
949     }
950
951     /**
952      * DOCUMENT ME!
953      *
954      * @param b DOCUMENT ME!
955      */
956     public void setColourAppliesToAllGroups(boolean b)
957     {
958         colourAppliesToAllGroups = b;
959     }
960
961     /**
962      * DOCUMENT ME!
963      *
964      * @return DOCUMENT ME!
965      */
966     public boolean getColourAppliesToAllGroups()
967     {
968         return colourAppliesToAllGroups;
969     }
970
971     /**
972      * DOCUMENT ME!
973      *
974      * @return DOCUMENT ME!
975      */
976     public boolean getShowJVSuffix()
977     {
978         return showJVSuffix;
979     }
980
981     /**
982      * DOCUMENT ME!
983      *
984      * @param b DOCUMENT ME!
985      */
986     public void setShowJVSuffix(boolean b)
987     {
988         showJVSuffix = b;
989     }
990
991
992     /**
993      * DOCUMENT ME!
994      *
995      * @return DOCUMENT ME!
996      */
997     public boolean getShowAnnotation()
998     {
999         return showAnnotation;
1000     }
1001
1002     /**
1003      * DOCUMENT ME!
1004      *
1005      * @param b DOCUMENT ME!
1006      */
1007     public void setShowAnnotation(boolean b)
1008     {
1009         showAnnotation = b;
1010     }
1011
1012     /**
1013      * DOCUMENT ME!
1014      *
1015      * @return DOCUMENT ME!
1016      */
1017     public boolean getScaleAboveWrapped()
1018     {
1019         return scaleAboveWrapped;
1020     }
1021
1022     /**
1023      * DOCUMENT ME!
1024      *
1025      * @return DOCUMENT ME!
1026      */
1027     public boolean getScaleLeftWrapped()
1028     {
1029         return scaleLeftWrapped;
1030     }
1031
1032     /**
1033      * DOCUMENT ME!
1034      *
1035      * @return DOCUMENT ME!
1036      */
1037     public boolean getScaleRightWrapped()
1038     {
1039         return scaleRightWrapped;
1040     }
1041
1042     /**
1043      * DOCUMENT ME!
1044      *
1045      * @param b DOCUMENT ME!
1046      */
1047     public void setScaleAboveWrapped(boolean b)
1048     {
1049         scaleAboveWrapped = b;
1050     }
1051
1052     /**
1053      * DOCUMENT ME!
1054      *
1055      * @param b DOCUMENT ME!
1056      */
1057     public void setScaleLeftWrapped(boolean b)
1058     {
1059         scaleLeftWrapped = b;
1060     }
1061
1062     /**
1063      * DOCUMENT ME!
1064      *
1065      * @param b DOCUMENT ME!
1066      */
1067     public void setScaleRightWrapped(boolean b)
1068     {
1069         scaleRightWrapped = b;
1070     }
1071
1072     /**
1073      * Property change listener for changes in alignment
1074      *
1075      * @param listener DOCUMENT ME!
1076      */
1077     public void addPropertyChangeListener(
1078         java.beans.PropertyChangeListener listener)
1079     {
1080         changeSupport.addPropertyChangeListener(listener);
1081     }
1082
1083     /**
1084      * DOCUMENT ME!
1085      *
1086      * @param listener DOCUMENT ME!
1087      */
1088     public void removePropertyChangeListener(
1089         java.beans.PropertyChangeListener listener)
1090     {
1091         changeSupport.removePropertyChangeListener(listener);
1092     }
1093
1094     /**
1095      * Property change listener for changes in alignment
1096      *
1097      * @param prop DOCUMENT ME!
1098      * @param oldvalue DOCUMENT ME!
1099      * @param newvalue DOCUMENT ME!
1100      */
1101     public void firePropertyChange(String prop, Object oldvalue, Object newvalue)
1102     {
1103         changeSupport.firePropertyChange(prop, oldvalue, newvalue);
1104     }
1105
1106     public void setIgnoreGapsConsensus(boolean b)
1107     {
1108       ignoreGapsInConsensusCalculation = b;
1109       updateConsensus();
1110       if(globalColourScheme!=null)
1111       {
1112         globalColourScheme.setThreshold(globalColourScheme.getThreshold(), ignoreGapsInConsensusCalculation);
1113       }
1114     }
1115
1116     public boolean getIgnoreGapsConsensus()
1117     {
1118      return ignoreGapsInConsensusCalculation;
1119     }
1120
1121     public void setDataset(boolean b)
1122     {
1123       isDataset = b;
1124     }
1125
1126     public boolean isDataset()
1127     {
1128       return isDataset;
1129     }
1130
1131
1132     public void hideSelectedColumns()
1133     {
1134       if (colSel.size() < 1)
1135         return;
1136
1137       colSel.hideSelectedColumns();
1138       setSelectionGroup(null);
1139
1140       hasHiddenColumns = true;
1141     }
1142
1143
1144     public void hideColumns(int start, int end)
1145     {
1146       if(start==end)
1147         colSel.hideColumns(start);
1148       else
1149         colSel.hideColumns(start, end);
1150
1151       hasHiddenColumns = true;
1152     }
1153
1154     public void hideAllSelectedSeqs()
1155     {
1156       if (selectionGroup == null)
1157         return;
1158
1159       SequenceI[] seqs = selectionGroup.getSequencesInOrder(alignment);
1160
1161       hideSequence(seqs);
1162
1163       setSelectionGroup(null);
1164     }
1165
1166     public void hideSequence(SequenceI [] seq)
1167     {
1168       if(seq!=null)
1169       {
1170         for (int i = 0; i < seq.length; i++)
1171           alignment.getHiddenSequences().hideSequence(seq[i]);
1172
1173         hasHiddenRows = true;
1174         firePropertyChange("alignment", null, alignment.getSequences());
1175       }
1176     }
1177
1178     public void showSequence(int index)
1179     {
1180       Vector tmp = alignment.getHiddenSequences().showSequence(index);
1181       if(tmp.size()>0)
1182       {
1183         if(selectionGroup==null)
1184         {
1185           selectionGroup = new SequenceGroup();
1186           selectionGroup.setEndRes(alignment.getWidth()-1);
1187         }
1188
1189         for (int t = 0; t < tmp.size(); t++)
1190         {
1191           selectionGroup.addSequence(
1192               (SequenceI) tmp.elementAt(t), false
1193               );
1194         }
1195         firePropertyChange("alignment", null, alignment.getSequences());
1196       }
1197
1198       if(alignment.getHiddenSequences().getSize()<1)
1199         hasHiddenRows = false;
1200     }
1201
1202     public void showColumn(int col)
1203     {
1204       colSel.revealHiddenColumns(col);
1205       if(colSel.getHiddenColumns()==null)
1206         hasHiddenColumns = false;
1207     }
1208
1209     public void showAllHiddenColumns()
1210     {
1211       colSel.revealAllHiddenColumns();
1212       hasHiddenColumns = false;
1213     }
1214
1215     public void showAllHiddenSeqs()
1216     {
1217       if(alignment.getHiddenSequences().getSize()>0)
1218       {
1219         if(selectionGroup==null)
1220         {
1221           selectionGroup = new SequenceGroup();
1222           selectionGroup.setEndRes(alignment.getWidth()-1);
1223         }
1224         Vector tmp = alignment.getHiddenSequences().showAll();
1225         for(int t=0; t<tmp.size(); t++)
1226         {
1227           selectionGroup.addSequence(
1228               (SequenceI)tmp.elementAt(t), false
1229               );
1230         }
1231         firePropertyChange("alignment", null, alignment.getSequences());
1232         hasHiddenRows = false;
1233       }
1234     }
1235
1236     public void invertColumnSelection()
1237     {
1238       int column;
1239       for(int i=0; i<alignment.getWidth(); i++)
1240       {
1241         column = i;
1242
1243         if(colSel.contains(column))
1244           colSel.removeElement(column);
1245         else
1246           colSel.addElement(column);
1247
1248       }
1249
1250     }
1251
1252     public int adjustForHiddenSeqs(int alignmentIndex)
1253     {
1254       return alignment.getHiddenSequences().adjustForHiddenSeqs(alignmentIndex);
1255     }
1256
1257     /**
1258      * This method returns the a new SequenceI [] with
1259      * the selection sequence and start and end points adjusted
1260      * @return String[]
1261      */
1262     public SequenceI[] getSelectionAsNewSequence()
1263     {
1264       SequenceI[] sequences;
1265
1266       if (selectionGroup == null)
1267         sequences = alignment.getSequencesArray();
1268       else
1269         sequences = selectionGroup.getSelectionAsNewSequences(alignment);
1270
1271       return sequences;
1272     }
1273
1274     /**
1275      * This method returns the visible alignment as text, as
1276      * seen on the GUI, ie if columns are hidden they will not
1277      * be returned in the result.
1278      * Use this for calculating trees, PCA, redundancy etc on views
1279      * which contain hidden columns.
1280      * @return String[]
1281      */
1282     public jalview.datamodel.CigarArray getViewAsCigars(boolean selectedRegionOnly)
1283     {
1284       CigarArray selection=null;
1285       SequenceI [] seqs= null;
1286       int i, iSize;
1287       int start = 0, end = 0;
1288       if(selectedRegionOnly && selectionGroup!=null)
1289       {
1290         iSize = selectionGroup.getSize(false);
1291         seqs = selectionGroup.getSequencesInOrder(alignment);
1292         start = selectionGroup.getStartRes();
1293         end = selectionGroup.getEndRes(); // inclusive for start and end in SeqCigar constructor
1294       }
1295       else
1296       {
1297         iSize = alignment.getHeight();
1298         seqs = alignment.getSequencesArray();
1299         end = alignment.getWidth()-1;
1300       }
1301       SeqCigar[] selseqs = new SeqCigar[iSize];
1302       for(i=0; i<iSize; i++)
1303       {
1304         selseqs[i] = new SeqCigar(seqs[i], start, end);
1305       }
1306       selection=new CigarArray(selseqs);
1307       // now construct the CigarArray operations
1308       if (hasHiddenColumns) {
1309         Vector regions = colSel.getHiddenColumns();
1310         int [] region;
1311         int hideStart, hideEnd;
1312         int last=start;
1313         for (int j = 0; last<end & j < regions.size(); j++)
1314         {
1315           region = (int[]) regions.elementAt(j);
1316           hideStart = region[0];
1317           hideEnd = region[1];
1318           // edit hidden regions to selection range
1319           if(hideStart<last) {
1320             if (hideEnd > last)
1321             {
1322               hideStart = last;
1323             } else
1324               continue;
1325           }
1326
1327           if (hideStart>end)
1328             break;
1329
1330           if (hideEnd>end)
1331             hideEnd=end;
1332
1333           if (hideStart>hideEnd)
1334             break;
1335           /**
1336            * form operations...
1337            */
1338           if (last<hideStart)
1339             selection.addOperation(CigarArray.M, hideStart-last);
1340           selection.addOperation(CigarArray.D, 1+hideEnd-hideStart);
1341           last = hideEnd+1;
1342         }
1343         // Final match if necessary.
1344         if (last<end)
1345           selection.addOperation(CigarArray.M, end-last+1);
1346       } else {
1347         selection.addOperation(CigarArray.M, end-start+1);
1348       }
1349       return selection;
1350     }
1351     /**
1352      * return a compact representation of the current alignment selection to
1353      * pass to an analysis function
1354      * @param selectedOnly boolean true to just return the selected view
1355      * @return AlignmentView
1356      */
1357     jalview.datamodel.AlignmentView getAlignmentView(boolean selectedOnly) {
1358       // JBPNote:
1359       // this is here because the AlignmentView constructor modifies the CigarArray
1360       // object. Refactoring of Cigar and alignment view representation should
1361       // be done to remove redundancy.
1362       CigarArray aligview = getViewAsCigars(selectedOnly);
1363       if (aligview!=null)
1364         return new AlignmentView(aligview);
1365       return null;
1366     }
1367     /**
1368      * This method returns the visible alignment as text, as
1369      * seen on the GUI, ie if columns are hidden they will not
1370      * be returned in the result.
1371      * Use this for calculating trees, PCA, redundancy etc on views
1372      * which contain hidden columns.
1373      * @return String[]
1374      */
1375     public String [] getViewAsString(boolean selectedRegionOnly)
1376     {
1377       String [] selection = null;
1378       SequenceI [] seqs= null;
1379       int i, iSize;
1380       int start = 0, end = 0;
1381       if(selectedRegionOnly && selectionGroup!=null)
1382       {
1383         iSize = selectionGroup.getSize(false);
1384         seqs = selectionGroup.getSequencesInOrder(alignment);
1385         start = selectionGroup.getStartRes();
1386         end = selectionGroup.getEndRes()+1;
1387       }
1388       else
1389       {
1390         iSize = alignment.getHeight();
1391         seqs = alignment.getSequencesArray();
1392         end = alignment.getWidth();
1393       }
1394
1395       selection = new String[iSize];
1396       if (hasHiddenColumns) {
1397         selection = colSel.getVisibleSequenceStrings(start, end, seqs);
1398       } else {
1399         for(i=0; i<iSize; i++)
1400         {
1401           selection[i] = seqs[i].getSequence(start, end);
1402         }
1403
1404       }
1405       return selection;
1406     }
1407
1408     public boolean getShowHiddenMarkers()
1409     {
1410       return showHiddenMarkers;
1411     }
1412
1413     public void setShowHiddenMarkers(boolean show)
1414     {
1415       showHiddenMarkers = show;
1416     }
1417
1418     public String getSequenceSetId()
1419     {
1420       if(sequenceSetID==null)
1421         sequenceSetID =  alignment.hashCode()+"";
1422
1423       return sequenceSetID;
1424     }
1425
1426 }