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