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