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