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