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