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