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