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