hack to completely disable calculation of consensus and conservation if autocalculate...
[jalview.git] / src / jalview / gui / AlignViewport.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3  * Copyright (C) 2008 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 /*
20  * Jalview - A Sequence Alignment Editor and Viewer
21  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
22  *
23  * This program is free software; you can redistribute it and/or
24  * modify it under the terms of the GNU General Public License
25  * as published by the Free Software Foundation; either version 2
26  * of the License, or (at your option) any later version.
27  *
28  * This program is distributed in the hope that it will be useful,
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  * GNU General Public License for more details.
32  *
33  * You should have received a copy of the GNU General Public License
34  * along with this program; if not, write to the Free Software
35  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
36  */
37 package jalview.gui;
38
39 import java.util.*;
40
41 import java.awt.*;
42
43 import jalview.analysis.*;
44
45 import jalview.bin.*;
46
47 import jalview.datamodel.*;
48
49 import jalview.schemes.*;
50 import jalview.structure.SelectionSource;
51 import jalview.structure.StructureSelectionManager;
52
53 /**
54  * DOCUMENT ME!
55  * 
56  * @author $author$
57  * @version $Revision$
58  */
59 public class AlignViewport implements SelectionSource
60 {
61   private static final int RIGHT_JUSTIFY = 1;
62
63   int startRes;
64
65   int endRes;
66
67   int startSeq;
68
69   int endSeq;
70
71   boolean showJVSuffix = true;
72
73   boolean showText = true;
74
75   boolean showColourText = false;
76
77   boolean showBoxes = true;
78
79   boolean wrapAlignment = false;
80
81   boolean renderGaps = true;
82
83   boolean showSequenceFeatures = false;
84
85   boolean showAnnotation = true;
86
87   boolean colourAppliesToAllGroups = true;
88
89   ColourSchemeI globalColourScheme = null;
90
91   boolean conservationColourSelected = false;
92
93   boolean abovePIDThreshold = false;
94
95   SequenceGroup selectionGroup;
96
97   int charHeight;
98
99   int charWidth;
100
101   boolean validCharWidth;
102
103   int wrappedWidth;
104
105   Font font;
106
107   boolean seqNameItalics;
108
109   AlignmentI alignment;
110
111   ColumnSelection colSel = new ColumnSelection();
112
113   int threshold;
114
115   int increment;
116
117   NJTree currentTree = null;
118
119   boolean scaleAboveWrapped = false;
120
121   boolean scaleLeftWrapped = true;
122
123   boolean scaleRightWrapped = true;
124
125   boolean hasHiddenColumns = false;
126
127   boolean hasHiddenRows = false;
128
129   boolean showHiddenMarkers = true;
130
131   boolean cursorMode = false;
132
133   // The following vector holds the features which are
134   // currently visible, in the correct order or rendering
135   Hashtable featuresDisplayed = null;
136
137   /** DOCUMENT ME!! */
138   public Hashtable[] hconsensus;
139
140   AlignmentAnnotation consensus;
141
142   AlignmentAnnotation conservation;
143
144   AlignmentAnnotation quality;
145
146   boolean autoCalculateConsensus = true;
147
148   /** DOCUMENT ME!! */
149   public int ConsPercGaps = 25; // JBPNote : This should be a scalable property!
150
151   // JBPNote Prolly only need this in the applet version.
152   private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(
153           this);
154
155   boolean ignoreGapsInConsensusCalculation = false;
156
157   boolean isDataset = false;
158
159   boolean antiAlias = false;
160
161   boolean padGaps = false;
162
163   Rectangle explodedPosition;
164
165   String viewName;
166
167   String sequenceSetID;
168
169   boolean gatherViewsHere = false;
170
171   Stack historyList = new Stack();
172
173   Stack redoList = new Stack();
174
175   Hashtable sequenceColours;
176
177   int thresholdTextColour = 0;
178
179   Color textColour = Color.black;
180
181   Color textColour2 = Color.white;
182
183   boolean rightAlignIds = false;
184
185   Hashtable hiddenRepSequences;
186
187   /**
188    * Creates a new AlignViewport object.
189    * 
190    * @param al alignment to view
191    */
192   public AlignViewport(AlignmentI al)
193   {
194     setAlignment(al);
195     init();
196   }
197   /**
198    * Create a new AlignViewport object with a specific sequence set ID
199    * @param al
200    * @param seqsetid (may be null - but potential for ambiguous constructor exception)
201    */
202   public AlignViewport(AlignmentI al, String seqsetid)
203   {
204     this(al,seqsetid,null);
205   }
206   public AlignViewport(AlignmentI al, String seqsetid, String viewid)
207   {
208     sequenceSetID = seqsetid;
209     viewId = viewid;
210     // TODO remove these once 2.4.VAMSAS release finished
211     if (Cache.log!=null && Cache.log.isDebugEnabled() && seqsetid!=null) { Cache.log.debug("Setting viewport's sequence set id : "+sequenceSetID); }
212     if (Cache.log!=null && Cache.log.isDebugEnabled() && viewId!=null) { Cache.log.debug("Setting viewport's view id : "+viewId); }
213     setAlignment(al);
214     init();
215   }
216
217   /**
218    * Create a new AlignViewport with hidden regions
219    * 
220    * @param al
221    *                AlignmentI
222    * @param hiddenColumns
223    *                ColumnSelection
224    */
225   public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns)
226   {
227     setAlignment(al);
228     if (hiddenColumns != null)
229     {
230       this.colSel = hiddenColumns;
231       if (hiddenColumns.getHiddenColumns() != null)
232       {
233         hasHiddenColumns = true;
234       }
235     }
236     init();
237   }
238   /**
239    * New viewport with hidden columns and an existing sequence set id
240    * @param al
241    * @param hiddenColumns
242    * @param seqsetid (may be null)
243    */
244   public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns, String seqsetid)
245   {
246     this(al,hiddenColumns,seqsetid,null);
247   }
248   /**
249    * New viewport with hidden columns and an existing sequence set id and viewid
250    * @param al
251    * @param hiddenColumns
252    * @param seqsetid (may be null)
253    * @param viewid (may be null)
254    */
255   public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns, String seqsetid, String viewid)
256   {
257     sequenceSetID = seqsetid;
258     viewId = viewid;
259     // TODO remove these once 2.4.VAMSAS release finished
260     if (Cache.log!=null && Cache.log.isDebugEnabled() && seqsetid!=null) { Cache.log.debug("Setting viewport's sequence set id : "+sequenceSetID); }
261     if (Cache.log!=null && Cache.log.isDebugEnabled() && viewId!=null) { Cache.log.debug("Setting viewport's view id : "+viewId); }
262     setAlignment(al);
263     if (hiddenColumns != null)
264     {
265       this.colSel = hiddenColumns;
266       if (hiddenColumns.getHiddenColumns() != null)
267       {
268         hasHiddenColumns = true;
269       }
270     }
271     init();
272   }
273
274   void init()
275   {
276     this.startRes = 0;
277     this.endRes = alignment.getWidth() - 1;
278     this.startSeq = 0;
279     this.endSeq = alignment.getHeight() - 1;
280
281     antiAlias = Cache.getDefault("ANTI_ALIAS", false);
282
283     showJVSuffix = Cache.getDefault("SHOW_JVSUFFIX", true);
284     showAnnotation = Cache.getDefault("SHOW_ANNOTATIONS", true);
285
286     rightAlignIds = Cache.getDefault("RIGHT_ALIGN_IDS", false);
287     centreColumnLabels = Cache.getDefault("CENTRE_COLUMN_LABELS", false);
288     autoCalculateConsensus = Cache.getDefault("AUTO_CALC_CONSENSUS", true);
289
290     padGaps = Cache.getDefault("PAD_GAPS", true);
291     shownpfeats = Cache.getDefault("SHOW_NPFEATS_TOOLTIP",true);
292     showdbrefs = Cache.getDefault("SHOW_DBREFS_TOOLTIP",true);
293     
294     String fontName = Cache.getDefault("FONT_NAME", "SansSerif");
295     String fontStyle = Cache.getDefault("FONT_STYLE", Font.PLAIN + "");
296     String fontSize = Cache.getDefault("FONT_SIZE", "10");
297
298     seqNameItalics = Cache.getDefault("ID_ITALICS", true);
299
300     int style = 0;
301
302     if (fontStyle.equals("bold"))
303     {
304       style = 1;
305     }
306     else if (fontStyle.equals("italic"))
307     {
308       style = 2;
309     }
310
311     setFont(new Font(fontName, style, Integer.parseInt(fontSize)));
312
313     alignment
314             .setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0));
315
316     // We must set conservation and consensus before setting colour,
317     // as Blosum and Clustal require this to be done
318     if (hconsensus == null && !isDataset)
319     {
320       if (!alignment.isNucleotide())
321       {
322         conservation = new AlignmentAnnotation("Conservation",
323                 "Conservation of total alignment less than " + ConsPercGaps
324                         + "% gaps", new Annotation[1], 0f, 11f,
325                 AlignmentAnnotation.BAR_GRAPH);
326         conservation.hasText = true;
327         conservation.autoCalculated = true;
328
329         if (Cache.getDefault("SHOW_CONSERVATION", true))
330         {
331           alignment.addAnnotation(conservation);
332         }
333
334         if (Cache.getDefault("SHOW_QUALITY", true))
335         {
336           quality = new AlignmentAnnotation("Quality",
337                   "Alignment Quality based on Blosum62 scores",
338                   new Annotation[1], 0f, 11f, AlignmentAnnotation.BAR_GRAPH);
339           quality.hasText = true;
340           quality.autoCalculated = true;
341
342           alignment.addAnnotation(quality);
343         }
344       }
345       // TODO: add menu option action that nulls or creates consensus object depending on if the user wants to see the annotation or not in a specific alignment
346       consensus = new AlignmentAnnotation("Consensus", "PID",
347               new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
348       consensus.hasText = true;
349       consensus.autoCalculated = true;
350
351       if (Cache.getDefault("SHOW_IDENTITY", true))
352       {
353         alignment.addAnnotation(consensus);
354       }
355     }
356
357     if (jalview.bin.Cache.getProperty("DEFAULT_COLOUR") != null)
358     {
359       globalColourScheme = ColourSchemeProperty.getColour(alignment,
360               jalview.bin.Cache.getProperty("DEFAULT_COLOUR"));
361
362       if (globalColourScheme instanceof UserColourScheme)
363       {
364         globalColourScheme = UserDefinedColours.loadDefaultColours();
365         ((UserColourScheme) globalColourScheme).setThreshold(0,
366                 getIgnoreGapsConsensus());
367       }
368
369       if (globalColourScheme != null)
370       {
371         globalColourScheme.setConsensus(hconsensus);
372       }
373     }
374
375     wrapAlignment = jalview.bin.Cache.getDefault("WRAP_ALIGNMENT", false);
376   }
377
378   /**
379    * DOCUMENT ME!
380    * 
381    * @param b
382    *                DOCUMENT ME!
383    */
384   public void setShowSequenceFeatures(boolean b)
385   {
386     showSequenceFeatures = b;
387   }
388
389   public boolean getShowSequenceFeatures()
390   {
391     return showSequenceFeatures;
392   }
393
394   class ConservationThread extends Thread
395   {
396     AlignmentPanel ap;
397
398     public ConservationThread(AlignmentPanel ap)
399     {
400       this.ap = ap;
401     }
402
403     public void run()
404     {
405       try
406       {
407         updatingConservation = true;
408
409         while (UPDATING_CONSERVATION)
410         {
411           try
412           {
413             if (ap != null)
414             {
415               ap.paintAlignment(false);
416             }
417             Thread.sleep(200);
418           } catch (Exception ex)
419           {
420             ex.printStackTrace();
421           }
422         }
423
424         UPDATING_CONSERVATION = true;
425
426         int alWidth = alignment.getWidth();
427         if (alWidth < 0)
428         {
429           return;
430         }
431
432         Conservation cons = new jalview.analysis.Conservation("All",
433                 jalview.schemes.ResidueProperties.propHash, 3, alignment
434                         .getSequences(), 0, alWidth - 1);
435
436         cons.calculate();
437         cons.verdict(false, ConsPercGaps);
438
439         if (quality != null)
440         {
441           cons.findQuality();
442         }
443
444         char[] sequence = cons.getConsSequence().getSequence();
445         float minR;
446         float minG;
447         float minB;
448         float maxR;
449         float maxG;
450         float maxB;
451         minR = 0.3f;
452         minG = 0.0f;
453         minB = 0f;
454         maxR = 1.0f - minR;
455         maxG = 0.9f - minG;
456         maxB = 0f - minB; // scalable range for colouring both Conservation and
457                           // Quality
458
459         float min = 0f;
460         float max = 11f;
461         float qmin = 0f;
462         float qmax = 0f;
463
464         char c;
465
466         conservation.annotations = new Annotation[alWidth];
467
468         if (quality != null)
469         {
470           quality.graphMax = cons.qualityRange[1].floatValue();
471           quality.annotations = new Annotation[alWidth];
472           qmin = cons.qualityRange[0].floatValue();
473           qmax = cons.qualityRange[1].floatValue();
474         }
475
476         for (int i = 0; i < alWidth; i++)
477         {
478           float value = 0;
479
480           c = sequence[i];
481
482           if (Character.isDigit(c))
483           {
484             value = (int) (c - '0');
485           }
486           else if (c == '*')
487           {
488             value = 11;
489           }
490           else if (c == '+')
491           {
492             value = 10;
493           }
494
495           float vprop = value - min;
496           vprop /= max;
497           conservation.annotations[i] = new Annotation(String.valueOf(c),
498                   String.valueOf(value), ' ', value, new Color(minR
499                           + (maxR * vprop), minG + (maxG * vprop), minB
500                           + (maxB * vprop)));
501
502           // Quality calc
503           if (quality != null)
504           {
505             value = ((Double) cons.quality.get(i)).floatValue();
506             vprop = value - qmin;
507             vprop /= qmax;
508             quality.annotations[i] = new Annotation(" ", String
509                     .valueOf(value), ' ', value, new Color(minR
510                     + (maxR * vprop), minG + (maxG * vprop), minB
511                     + (maxB * vprop)));
512           }
513         }
514       } catch (OutOfMemoryError error)
515       {
516         new OOMWarning("calculating conservation", error);
517
518         conservation = null;
519         quality = null;
520
521       }
522
523       UPDATING_CONSERVATION = false;
524       updatingConservation = false;
525
526       if (ap != null)
527       {
528         ap.paintAlignment(true);
529       }
530
531     }
532   }
533
534   ConservationThread conservationThread;
535
536   ConsensusThread consensusThread;
537
538   boolean consUpdateNeeded = false;
539
540   static boolean UPDATING_CONSENSUS = false;
541
542   static boolean UPDATING_CONSERVATION = false;
543
544   boolean updatingConsensus = false;
545
546   boolean updatingConservation = false;
547
548   /**
549    * centre columnar annotation labels in displayed alignment annotation TODO:
550    * add to jalviewXML and annotation display settings
551    */
552   boolean centreColumnLabels = false;
553
554   private boolean showdbrefs;
555
556   private boolean shownpfeats;
557
558   /**
559    * trigger update of conservation annotation
560    */
561   public void updateConservation(final AlignmentPanel ap)
562   {
563     // see note in mantis : issue number 8585
564     if (alignment.isNucleotide() || conservation == null || !autoCalculateConsensus)
565     {
566       return;
567     }
568
569     conservationThread = new ConservationThread(ap);
570     conservationThread.start();
571   }
572
573   /**
574    * trigger update of consensus annotation
575    */
576   public void updateConsensus(final AlignmentPanel ap)
577   {
578     // see note in mantis : issue number 8585
579     if (consensus == null || !autoCalculateConsensus)
580     {
581       return;
582     }
583     consensusThread = new ConsensusThread(ap);
584     consensusThread.start();
585   }
586
587   class ConsensusThread extends Thread
588   {
589     AlignmentPanel ap;
590
591     public ConsensusThread(AlignmentPanel ap)
592     {
593       this.ap = ap;
594     }
595
596     public void run()
597     {
598       updatingConsensus = true;
599       while (UPDATING_CONSENSUS)
600       {
601         try
602         {
603           if (ap != null)
604           {
605             ap.paintAlignment(false);
606           }
607
608           Thread.sleep(200);
609         } catch (Exception ex)
610         {
611           ex.printStackTrace();
612         }
613       }
614
615       UPDATING_CONSENSUS = true;
616
617       try
618       {
619         int aWidth = (alignment != null) ? alignment.getWidth() : 0; // null
620                                                                       // pointer
621                                                                       // possibility
622                                                                       // here.
623         if (aWidth < 0)
624         {
625           return;
626         }
627
628         consensus.annotations = null;
629         consensus.annotations = new Annotation[aWidth];
630
631         hconsensus = new Hashtable[aWidth];
632         AAFrequency.calculate(alignment.getSequencesArray(), 0, alignment
633                 .getWidth(), hconsensus);
634
635         for (int i = 0; i < aWidth; i++)
636         {
637           float value = 0;
638           if (ignoreGapsInConsensusCalculation)
639           {
640             value = ((Float) hconsensus[i].get(AAFrequency.PID_NOGAPS))
641                     .floatValue();
642           }
643           else
644           {
645             value = ((Float) hconsensus[i].get(AAFrequency.PID_GAPS))
646                     .floatValue();
647           }
648
649           String maxRes = hconsensus[i].get(AAFrequency.MAXRESIDUE)
650                   .toString();
651           String mouseOver = hconsensus[i].get(AAFrequency.MAXRESIDUE)
652                   + " ";
653
654           if (maxRes.length() > 1)
655           {
656             mouseOver = "[" + maxRes + "] ";
657             maxRes = "+";
658           }
659
660           mouseOver += ((int) value + "%");
661           consensus.annotations[i] = new Annotation(maxRes, mouseOver, ' ',
662                   value);
663         }
664
665         if (globalColourScheme != null)
666         {
667           globalColourScheme.setConsensus(hconsensus);
668         }
669
670       } catch (OutOfMemoryError error)
671       {
672         alignment.deleteAnnotation(consensus);
673
674         consensus = null;
675         hconsensus = null;
676         new OOMWarning("calculating consensus", error);
677       }
678       UPDATING_CONSENSUS = false;
679       updatingConsensus = false;
680
681       if (ap != null)
682       {
683         ap.paintAlignment(true);
684       }
685     }
686   }
687
688   /**
689    * get the consensus sequence as displayed under the PID consensus annotation
690    * row.
691    * 
692    * @return consensus sequence as a new sequence object
693    */
694   public SequenceI getConsensusSeq()
695   {
696     if (consensus == null)
697     {
698       updateConsensus(null);
699     }
700     if (consensus == null)
701     {
702       return null;
703     }
704     StringBuffer seqs = new StringBuffer();
705     for (int i = 0; i < consensus.annotations.length; i++)
706     {
707       if (consensus.annotations[i] != null)
708       {
709         if (consensus.annotations[i].description.charAt(0) == '[')
710         {
711           seqs.append(consensus.annotations[i].description.charAt(1));
712         }
713         else
714         {
715           seqs.append(consensus.annotations[i].displayCharacter);
716         }
717       }
718     }
719
720     SequenceI sq = new Sequence("Consensus", seqs.toString());
721     sq.setDescription("Percentage Identity Consensus "
722             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
723     return sq;
724   }
725
726   /**
727    * DOCUMENT ME!
728    * 
729    * @return DOCUMENT ME!
730    */
731   public SequenceGroup getSelectionGroup()
732   {
733     return selectionGroup;
734   }
735
736   /**
737    * DOCUMENT ME!
738    * 
739    * @param sg
740    *                DOCUMENT ME!
741    */
742   public void setSelectionGroup(SequenceGroup sg)
743   {
744     selectionGroup = sg;    
745   }
746
747   /**
748    * DOCUMENT ME!
749    * 
750    * @return DOCUMENT ME!
751    */
752   public boolean getConservationSelected()
753   {
754     return conservationColourSelected;
755   }
756
757   /**
758    * DOCUMENT ME!
759    * 
760    * @param b
761    *                DOCUMENT ME!
762    */
763   public void setConservationSelected(boolean b)
764   {
765     conservationColourSelected = b;
766   }
767
768   /**
769    * DOCUMENT ME!
770    * 
771    * @return DOCUMENT ME!
772    */
773   public boolean getAbovePIDThreshold()
774   {
775     return abovePIDThreshold;
776   }
777
778   /**
779    * DOCUMENT ME!
780    * 
781    * @param b
782    *                DOCUMENT ME!
783    */
784   public void setAbovePIDThreshold(boolean b)
785   {
786     abovePIDThreshold = b;
787   }
788
789   /**
790    * DOCUMENT ME!
791    * 
792    * @return DOCUMENT ME!
793    */
794   public int getStartRes()
795   {
796     return startRes;
797   }
798
799   /**
800    * DOCUMENT ME!
801    * 
802    * @return DOCUMENT ME!
803    */
804   public int getEndRes()
805   {
806     return endRes;
807   }
808
809   /**
810    * DOCUMENT ME!
811    * 
812    * @return DOCUMENT ME!
813    */
814   public int getStartSeq()
815   {
816     return startSeq;
817   }
818
819   /**
820    * DOCUMENT ME!
821    * 
822    * @param cs
823    *                DOCUMENT ME!
824    */
825   public void setGlobalColourScheme(ColourSchemeI cs)
826   {
827     globalColourScheme = cs;
828   }
829
830   /**
831    * DOCUMENT ME!
832    * 
833    * @return DOCUMENT ME!
834    */
835   public ColourSchemeI getGlobalColourScheme()
836   {
837     return globalColourScheme;
838   }
839
840   /**
841    * DOCUMENT ME!
842    * 
843    * @param res
844    *                DOCUMENT ME!
845    */
846   public void setStartRes(int res)
847   {
848     this.startRes = res;
849   }
850
851   /**
852    * DOCUMENT ME!
853    * 
854    * @param seq
855    *                DOCUMENT ME!
856    */
857   public void setStartSeq(int seq)
858   {
859     this.startSeq = seq;
860   }
861
862   /**
863    * DOCUMENT ME!
864    * 
865    * @param res
866    *                DOCUMENT ME!
867    */
868   public void setEndRes(int res)
869   {
870     if (res > (alignment.getWidth() - 1))
871     {
872       // log.System.out.println(" Corrected res from " + res + " to maximum " +
873       // (alignment.getWidth()-1));
874       res = alignment.getWidth() - 1;
875     }
876
877     if (res < 0)
878     {
879       res = 0;
880     }
881
882     this.endRes = res;
883   }
884
885   /**
886    * DOCUMENT ME!
887    * 
888    * @param seq
889    *                DOCUMENT ME!
890    */
891   public void setEndSeq(int seq)
892   {
893     if (seq > alignment.getHeight())
894     {
895       seq = alignment.getHeight();
896     }
897
898     if (seq < 0)
899     {
900       seq = 0;
901     }
902
903     this.endSeq = seq;
904   }
905
906   /**
907    * DOCUMENT ME!
908    * 
909    * @return DOCUMENT ME!
910    */
911   public int getEndSeq()
912   {
913     return endSeq;
914   }
915
916   /**
917    * DOCUMENT ME!
918    * 
919    * @param f
920    *                DOCUMENT ME!
921    */
922   public void setFont(Font f)
923   {
924     font = f;
925
926     Container c = new Container();
927
928     java.awt.FontMetrics fm = c.getFontMetrics(font);
929     setCharHeight(fm.getHeight());
930     setCharWidth(fm.charWidth('M'));
931     validCharWidth = true;
932   }
933
934   /**
935    * DOCUMENT ME!
936    * 
937    * @return DOCUMENT ME!
938    */
939   public Font getFont()
940   {
941     return font;
942   }
943
944   /**
945    * DOCUMENT ME!
946    * 
947    * @param w
948    *                DOCUMENT ME!
949    */
950   public void setCharWidth(int w)
951   {
952     this.charWidth = w;
953   }
954
955   /**
956    * DOCUMENT ME!
957    * 
958    * @return DOCUMENT ME!
959    */
960   public int getCharWidth()
961   {
962     return charWidth;
963   }
964
965   /**
966    * DOCUMENT ME!
967    * 
968    * @param h
969    *                DOCUMENT ME!
970    */
971   public void setCharHeight(int h)
972   {
973     this.charHeight = h;
974   }
975
976   /**
977    * DOCUMENT ME!
978    * 
979    * @return DOCUMENT ME!
980    */
981   public int getCharHeight()
982   {
983     return charHeight;
984   }
985
986   /**
987    * DOCUMENT ME!
988    * 
989    * @param w
990    *                DOCUMENT ME!
991    */
992   public void setWrappedWidth(int w)
993   {
994     this.wrappedWidth = w;
995   }
996
997   /**
998    * DOCUMENT ME!
999    * 
1000    * @return DOCUMENT ME!
1001    */
1002   public int getWrappedWidth()
1003   {
1004     return wrappedWidth;
1005   }
1006
1007   /**
1008    * DOCUMENT ME!
1009    * 
1010    * @return DOCUMENT ME!
1011    */
1012   public AlignmentI getAlignment()
1013   {
1014     return alignment;
1015   }
1016
1017   /**
1018    * DOCUMENT ME!
1019    * 
1020    * @param align
1021    *                DOCUMENT ME!
1022    */
1023   public void setAlignment(AlignmentI align)
1024   {
1025     if (alignment != null && alignment.getCodonFrames() != null)
1026     {
1027       StructureSelectionManager.getStructureSelectionManager()
1028               .removeMappings(alignment.getCodonFrames());
1029     }
1030     this.alignment = align;
1031     if (alignment.getCodonFrames() != null)
1032     {
1033       StructureSelectionManager.getStructureSelectionManager().addMappings(
1034               alignment.getCodonFrames());
1035     }
1036   }
1037
1038   /**
1039    * DOCUMENT ME!
1040    * 
1041    * @param state
1042    *                DOCUMENT ME!
1043    */
1044   public void setWrapAlignment(boolean state)
1045   {
1046     wrapAlignment = state;
1047   }
1048
1049   /**
1050    * DOCUMENT ME!
1051    * 
1052    * @param state
1053    *                DOCUMENT ME!
1054    */
1055   public void setShowText(boolean state)
1056   {
1057     showText = state;
1058   }
1059
1060   /**
1061    * DOCUMENT ME!
1062    * 
1063    * @param state
1064    *                DOCUMENT ME!
1065    */
1066   public void setRenderGaps(boolean state)
1067   {
1068     renderGaps = state;
1069   }
1070
1071   /**
1072    * DOCUMENT ME!
1073    * 
1074    * @return DOCUMENT ME!
1075    */
1076   public boolean getColourText()
1077   {
1078     return showColourText;
1079   }
1080
1081   /**
1082    * DOCUMENT ME!
1083    * 
1084    * @param state
1085    *                DOCUMENT ME!
1086    */
1087   public void setColourText(boolean state)
1088   {
1089     showColourText = state;
1090   }
1091
1092   /**
1093    * DOCUMENT ME!
1094    * 
1095    * @param state
1096    *                DOCUMENT ME!
1097    */
1098   public void setShowBoxes(boolean state)
1099   {
1100     showBoxes = state;
1101   }
1102
1103   /**
1104    * DOCUMENT ME!
1105    * 
1106    * @return DOCUMENT ME!
1107    */
1108   public boolean getWrapAlignment()
1109   {
1110     return wrapAlignment;
1111   }
1112
1113   /**
1114    * DOCUMENT ME!
1115    * 
1116    * @return DOCUMENT ME!
1117    */
1118   public boolean getShowText()
1119   {
1120     return showText;
1121   }
1122
1123   /**
1124    * DOCUMENT ME!
1125    * 
1126    * @return DOCUMENT ME!
1127    */
1128   public boolean getShowBoxes()
1129   {
1130     return showBoxes;
1131   }
1132
1133   /**
1134    * DOCUMENT ME!
1135    * 
1136    * @return DOCUMENT ME!
1137    */
1138   public char getGapCharacter()
1139   {
1140     return getAlignment().getGapCharacter();
1141   }
1142
1143   /**
1144    * DOCUMENT ME!
1145    * 
1146    * @param gap
1147    *                DOCUMENT ME!
1148    */
1149   public void setGapCharacter(char gap)
1150   {
1151     if (getAlignment() != null)
1152     {
1153       getAlignment().setGapCharacter(gap);
1154     }
1155   }
1156
1157   /**
1158    * DOCUMENT ME!
1159    * 
1160    * @param thresh
1161    *                DOCUMENT ME!
1162    */
1163   public void setThreshold(int thresh)
1164   {
1165     threshold = thresh;
1166   }
1167
1168   /**
1169    * DOCUMENT ME!
1170    * 
1171    * @return DOCUMENT ME!
1172    */
1173   public int getThreshold()
1174   {
1175     return threshold;
1176   }
1177
1178   /**
1179    * DOCUMENT ME!
1180    * 
1181    * @param inc
1182    *                DOCUMENT ME!
1183    */
1184   public void setIncrement(int inc)
1185   {
1186     increment = inc;
1187   }
1188
1189   /**
1190    * DOCUMENT ME!
1191    * 
1192    * @return DOCUMENT ME!
1193    */
1194   public int getIncrement()
1195   {
1196     return increment;
1197   }
1198
1199   /**
1200    * DOCUMENT ME!
1201    * 
1202    * @return DOCUMENT ME!
1203    */
1204   public ColumnSelection getColumnSelection()
1205   {
1206     return colSel;
1207   }
1208
1209   /**
1210    * DOCUMENT ME!
1211    * 
1212    * @param tree
1213    *                DOCUMENT ME!
1214    */
1215   public void setCurrentTree(NJTree tree)
1216   {
1217     currentTree = tree;
1218   }
1219
1220   /**
1221    * DOCUMENT ME!
1222    * 
1223    * @return DOCUMENT ME!
1224    */
1225   public NJTree getCurrentTree()
1226   {
1227     return currentTree;
1228   }
1229
1230   /**
1231    * DOCUMENT ME!
1232    * 
1233    * @param b
1234    *                DOCUMENT ME!
1235    */
1236   public void setColourAppliesToAllGroups(boolean b)
1237   {
1238     colourAppliesToAllGroups = b;
1239   }
1240
1241   /**
1242    * DOCUMENT ME!
1243    * 
1244    * @return DOCUMENT ME!
1245    */
1246   public boolean getColourAppliesToAllGroups()
1247   {
1248     return colourAppliesToAllGroups;
1249   }
1250
1251   /**
1252    * DOCUMENT ME!
1253    * 
1254    * @return DOCUMENT ME!
1255    */
1256   public boolean getShowJVSuffix()
1257   {
1258     return showJVSuffix;
1259   }
1260
1261   /**
1262    * DOCUMENT ME!
1263    * 
1264    * @param b
1265    *                DOCUMENT ME!
1266    */
1267   public void setShowJVSuffix(boolean b)
1268   {
1269     showJVSuffix = b;
1270   }
1271
1272   /**
1273    * DOCUMENT ME!
1274    * 
1275    * @return DOCUMENT ME!
1276    */
1277   public boolean getShowAnnotation()
1278   {
1279     return showAnnotation;
1280   }
1281
1282   /**
1283    * DOCUMENT ME!
1284    * 
1285    * @param b
1286    *                DOCUMENT ME!
1287    */
1288   public void setShowAnnotation(boolean b)
1289   {
1290     showAnnotation = b;
1291   }
1292
1293   /**
1294    * DOCUMENT ME!
1295    * 
1296    * @return DOCUMENT ME!
1297    */
1298   public boolean getScaleAboveWrapped()
1299   {
1300     return scaleAboveWrapped;
1301   }
1302
1303   /**
1304    * DOCUMENT ME!
1305    * 
1306    * @return DOCUMENT ME!
1307    */
1308   public boolean getScaleLeftWrapped()
1309   {
1310     return scaleLeftWrapped;
1311   }
1312
1313   /**
1314    * DOCUMENT ME!
1315    * 
1316    * @return DOCUMENT ME!
1317    */
1318   public boolean getScaleRightWrapped()
1319   {
1320     return scaleRightWrapped;
1321   }
1322
1323   /**
1324    * DOCUMENT ME!
1325    * 
1326    * @param b
1327    *                DOCUMENT ME!
1328    */
1329   public void setScaleAboveWrapped(boolean b)
1330   {
1331     scaleAboveWrapped = b;
1332   }
1333
1334   /**
1335    * DOCUMENT ME!
1336    * 
1337    * @param b
1338    *                DOCUMENT ME!
1339    */
1340   public void setScaleLeftWrapped(boolean b)
1341   {
1342     scaleLeftWrapped = b;
1343   }
1344
1345   /**
1346    * DOCUMENT ME!
1347    * 
1348    * @param b
1349    *                DOCUMENT ME!
1350    */
1351   public void setScaleRightWrapped(boolean b)
1352   {
1353     scaleRightWrapped = b;
1354   }
1355
1356   /**
1357    * Property change listener for changes in alignment
1358    * 
1359    * @param listener
1360    *                DOCUMENT ME!
1361    */
1362   public void addPropertyChangeListener(
1363           java.beans.PropertyChangeListener listener)
1364   {
1365     changeSupport.addPropertyChangeListener(listener);
1366   }
1367
1368   /**
1369    * DOCUMENT ME!
1370    * 
1371    * @param listener
1372    *                DOCUMENT ME!
1373    */
1374   public void removePropertyChangeListener(
1375           java.beans.PropertyChangeListener listener)
1376   {
1377     changeSupport.removePropertyChangeListener(listener);
1378   }
1379
1380   /**
1381    * Property change listener for changes in alignment
1382    * 
1383    * @param prop
1384    *                DOCUMENT ME!
1385    * @param oldvalue
1386    *                DOCUMENT ME!
1387    * @param newvalue
1388    *                DOCUMENT ME!
1389    */
1390   public void firePropertyChange(String prop, Object oldvalue,
1391           Object newvalue)
1392   {
1393     changeSupport.firePropertyChange(prop, oldvalue, newvalue);
1394   }
1395
1396   public void setIgnoreGapsConsensus(boolean b, AlignmentPanel ap)
1397   {
1398     ignoreGapsInConsensusCalculation = b;
1399     updateConsensus(ap);
1400     if (globalColourScheme != null)
1401     {
1402       globalColourScheme.setThreshold(globalColourScheme.getThreshold(),
1403               ignoreGapsInConsensusCalculation);
1404     }
1405   }
1406
1407   public boolean getIgnoreGapsConsensus()
1408   {
1409     return ignoreGapsInConsensusCalculation;
1410   }
1411
1412   public void setDataset(boolean b)
1413   {
1414     isDataset = b;
1415   }
1416
1417   public boolean isDataset()
1418   {
1419     return isDataset;
1420   }
1421
1422   public void hideSelectedColumns()
1423   {
1424     if (colSel.size() < 1)
1425     {
1426       return;
1427     }
1428
1429     colSel.hideSelectedColumns();
1430     setSelectionGroup(null);
1431
1432     hasHiddenColumns = true;
1433   }
1434
1435   public void hideColumns(int start, int end)
1436   {
1437     if (start == end)
1438     {
1439       colSel.hideColumns(start);
1440     }
1441     else
1442     {
1443       colSel.hideColumns(start, end);
1444     }
1445
1446     hasHiddenColumns = true;
1447   }
1448
1449   public void hideRepSequences(SequenceI repSequence, SequenceGroup sg)
1450   {
1451     int sSize = sg.getSize();
1452     if (sSize < 2)
1453     {
1454       return;
1455     }
1456
1457     if (hiddenRepSequences == null)
1458     {
1459       hiddenRepSequences = new Hashtable();
1460     }
1461
1462     hiddenRepSequences.put(repSequence, sg);
1463
1464     // Hide all sequences except the repSequence
1465     SequenceI[] seqs = new SequenceI[sSize - 1];
1466     int index = 0;
1467     for (int i = 0; i < sSize; i++)
1468     {
1469       if (sg.getSequenceAt(i) != repSequence)
1470       {
1471         if (index == sSize - 1)
1472         {
1473           return;
1474         }
1475
1476         seqs[index++] = sg.getSequenceAt(i);
1477       }
1478     }
1479     sg.setSeqrep(repSequence);
1480     sg.setHidereps(true);
1481     hideSequence(seqs);
1482
1483   }
1484
1485   public void hideAllSelectedSeqs()
1486   {
1487     if (selectionGroup == null || selectionGroup.getSize() < 1)
1488     {
1489       return;
1490     }
1491
1492     SequenceI[] seqs = selectionGroup.getSequencesInOrder(alignment);
1493
1494     hideSequence(seqs);
1495
1496     setSelectionGroup(null);
1497   }
1498
1499   public void hideSequence(SequenceI[] seq)
1500   {
1501     if (seq != null)
1502     {
1503       for (int i = 0; i < seq.length; i++)
1504       {
1505         alignment.getHiddenSequences().hideSequence(seq[i]);
1506       }
1507       hasHiddenRows = true;
1508       firePropertyChange("alignment", null, alignment.getSequences());
1509     }
1510   }
1511
1512   public void showSequence(int index)
1513   {
1514     Vector tmp = alignment.getHiddenSequences().showSequence(index,
1515             hiddenRepSequences);
1516     if (tmp.size() > 0)
1517     {
1518       if (selectionGroup == null)
1519       {
1520         selectionGroup = new SequenceGroup();
1521         selectionGroup.setEndRes(alignment.getWidth() - 1);
1522       }
1523
1524       for (int t = 0; t < tmp.size(); t++)
1525       {
1526         selectionGroup.addSequence((SequenceI) tmp.elementAt(t), false);
1527       }
1528       firePropertyChange("alignment", null, alignment.getSequences());
1529       sendSelection();
1530     }
1531
1532     if (alignment.getHiddenSequences().getSize() < 1)
1533     {
1534       hasHiddenRows = false;
1535     }
1536   }
1537
1538   public void showColumn(int col)
1539   {
1540     colSel.revealHiddenColumns(col);
1541     if (colSel.getHiddenColumns() == null)
1542     {
1543       hasHiddenColumns = false;
1544     }
1545   }
1546
1547   public void showAllHiddenColumns()
1548   {
1549     colSel.revealAllHiddenColumns();
1550     hasHiddenColumns = false;
1551   }
1552
1553   public void showAllHiddenSeqs()
1554   {
1555     if (alignment.getHiddenSequences().getSize() > 0)
1556     {
1557       if (selectionGroup == null)
1558       {
1559         selectionGroup = new SequenceGroup();
1560         selectionGroup.setEndRes(alignment.getWidth() - 1);
1561       }
1562       Vector tmp = alignment.getHiddenSequences().showAll(
1563               hiddenRepSequences);
1564       for (int t = 0; t < tmp.size(); t++)
1565       {
1566         selectionGroup.addSequence((SequenceI) tmp.elementAt(t), false);
1567       }
1568       firePropertyChange("alignment", null, alignment.getSequences());
1569       sendSelection();
1570       hasHiddenRows = false;
1571       hiddenRepSequences = null;
1572     }
1573   }
1574
1575   public void invertColumnSelection()
1576   {
1577     colSel.invertColumnSelection(0, alignment.getWidth());
1578   }
1579
1580   public int adjustForHiddenSeqs(int alignmentIndex)
1581   {
1582     return alignment.getHiddenSequences().adjustForHiddenSeqs(
1583             alignmentIndex);
1584   }
1585
1586   /**
1587    * This method returns an array of new SequenceI objects derived from the
1588    * whole alignment or just the current selection with start and end points
1589    * adjusted
1590    * 
1591    * @note if you need references to the actual SequenceI objects in the
1592    *       alignment or currently selected then use getSequenceSelection()
1593    * @return selection as new sequenceI objects
1594    */
1595   public SequenceI[] getSelectionAsNewSequence()
1596   {
1597     SequenceI[] sequences;
1598
1599     if (selectionGroup == null)
1600     {
1601       sequences = alignment.getSequencesArray();
1602       AlignmentAnnotation[] annots = alignment.getAlignmentAnnotation();
1603       for (int i = 0; i < sequences.length; i++)
1604       {
1605         sequences[i] = new Sequence(sequences[i], annots); // construct new
1606                                                             // sequence with
1607                                                             // subset of visible
1608                                                             // annotation
1609       }
1610     }
1611     else
1612     {
1613       sequences = selectionGroup.getSelectionAsNewSequences(alignment);
1614     }
1615
1616     return sequences;
1617   }
1618
1619   /**
1620    * get the currently selected sequence objects or all the sequences in the
1621    * alignment.
1622    * 
1623    * @return array of references to sequence objects
1624    */
1625   public SequenceI[] getSequenceSelection()
1626   {
1627     SequenceI[] sequences;
1628     if (selectionGroup == null)
1629     {
1630       sequences = alignment.getSequencesArray();
1631     }
1632     else
1633     {
1634       sequences = selectionGroup.getSequencesInOrder(alignment);
1635     }
1636     return sequences;
1637   }
1638
1639   /**
1640    * This method returns the visible alignment as text, as seen on the GUI, ie
1641    * if columns are hidden they will not be returned in the result. Use this for
1642    * calculating trees, PCA, redundancy etc on views which contain hidden
1643    * columns.
1644    * 
1645    * @return String[]
1646    */
1647   public jalview.datamodel.CigarArray getViewAsCigars(
1648           boolean selectedRegionOnly)
1649   {
1650     CigarArray selection = null;
1651     SequenceI[] seqs = null;
1652     int i, iSize;
1653     int start = 0, end = 0;
1654     if (selectedRegionOnly && selectionGroup != null)
1655     {
1656       iSize = selectionGroup.getSize();
1657       seqs = selectionGroup.getSequencesInOrder(alignment);
1658       start = selectionGroup.getStartRes();
1659       end = selectionGroup.getEndRes(); // inclusive for start and end in
1660                                         // SeqCigar constructor
1661     }
1662     else
1663     {
1664       iSize = alignment.getHeight();
1665       seqs = alignment.getSequencesArray();
1666       end = alignment.getWidth() - 1;
1667     }
1668     SeqCigar[] selseqs = new SeqCigar[iSize];
1669     for (i = 0; i < iSize; i++)
1670     {
1671       selseqs[i] = new SeqCigar(seqs[i], start, end);
1672     }
1673     selection = new CigarArray(selseqs);
1674     // now construct the CigarArray operations
1675     if (hasHiddenColumns)
1676     {
1677       Vector regions = colSel.getHiddenColumns();
1678       int[] region;
1679       int hideStart, hideEnd;
1680       int last = start;
1681       for (int j = 0; last < end & j < regions.size(); j++)
1682       {
1683         region = (int[]) regions.elementAt(j);
1684         hideStart = region[0];
1685         hideEnd = region[1];
1686         // edit hidden regions to selection range
1687         if (hideStart < last)
1688         {
1689           if (hideEnd > last)
1690           {
1691             hideStart = last;
1692           }
1693           else
1694           {
1695             continue;
1696           }
1697         }
1698
1699         if (hideStart > end)
1700         {
1701           break;
1702         }
1703
1704         if (hideEnd > end)
1705         {
1706           hideEnd = end;
1707         }
1708
1709         if (hideStart > hideEnd)
1710         {
1711           break;
1712         }
1713         /**
1714          * form operations...
1715          */
1716         if (last < hideStart)
1717         {
1718           selection.addOperation(CigarArray.M, hideStart - last);
1719         }
1720         selection.addOperation(CigarArray.D, 1 + hideEnd - hideStart);
1721         last = hideEnd + 1;
1722       }
1723       // Final match if necessary.
1724       if (last < end)
1725       {
1726         selection.addOperation(CigarArray.M, end - last + 1);
1727       }
1728     }
1729     else
1730     {
1731       selection.addOperation(CigarArray.M, end - start + 1);
1732     }
1733     return selection;
1734   }
1735
1736   /**
1737    * return a compact representation of the current alignment selection to pass
1738    * to an analysis function
1739    * 
1740    * @param selectedOnly
1741    *                boolean true to just return the selected view
1742    * @return AlignmentView
1743    */
1744   jalview.datamodel.AlignmentView getAlignmentView(boolean selectedOnly)
1745   {
1746     // JBPNote:
1747     // this is here because the AlignmentView constructor modifies the
1748     // CigarArray
1749     // object. Refactoring of Cigar and alignment view representation should
1750     // be done to remove redundancy.
1751     CigarArray aligview = getViewAsCigars(selectedOnly);
1752     if (aligview != null)
1753     {
1754       return new AlignmentView(aligview,
1755               (selectedOnly && selectionGroup != null) ? selectionGroup
1756                       .getStartRes() : 0);
1757     }
1758     return null;
1759   }
1760
1761   /**
1762    * This method returns the visible alignment as text, as seen on the GUI, ie
1763    * if columns are hidden they will not be returned in the result. Use this for
1764    * calculating trees, PCA, redundancy etc on views which contain hidden
1765    * columns.
1766    * 
1767    * @return String[]
1768    */
1769   public String[] getViewAsString(boolean selectedRegionOnly)
1770   {
1771     String[] selection = null;
1772     SequenceI[] seqs = null;
1773     int i, iSize;
1774     int start = 0, end = 0;
1775     if (selectedRegionOnly && selectionGroup != null)
1776     {
1777       iSize = selectionGroup.getSize();
1778       seqs = selectionGroup.getSequencesInOrder(alignment);
1779       start = selectionGroup.getStartRes();
1780       end = selectionGroup.getEndRes() + 1;
1781     }
1782     else
1783     {
1784       iSize = alignment.getHeight();
1785       seqs = alignment.getSequencesArray();
1786       end = alignment.getWidth();
1787     }
1788
1789     selection = new String[iSize];
1790     if (hasHiddenColumns)
1791     {
1792       selection = colSel.getVisibleSequenceStrings(start, end, seqs);
1793     }
1794     else
1795     {
1796       for (i = 0; i < iSize; i++)
1797       {
1798         selection[i] = seqs[i].getSequenceAsString(start, end);
1799       }
1800
1801     }
1802     return selection;
1803   }
1804
1805   public int[][] getVisibleRegionBoundaries(int min, int max)
1806   {
1807     Vector regions = new Vector();
1808     int start = min;
1809     int end = max;
1810
1811     do
1812     {
1813       if (hasHiddenColumns)
1814       {
1815         if (start == 0)
1816         {
1817           start = colSel.adjustForHiddenColumns(start);
1818         }
1819
1820         end = colSel.getHiddenBoundaryRight(start);
1821         if (start == end)
1822         {
1823           end = max;
1824         }
1825         if (end > max)
1826         {
1827           end = max;
1828         }
1829       }
1830
1831       regions.addElement(new int[]
1832       { start, end });
1833
1834       if (hasHiddenColumns)
1835       {
1836         start = colSel.adjustForHiddenColumns(end);
1837         start = colSel.getHiddenBoundaryLeft(start) + 1;
1838       }
1839     } while (end < max);
1840
1841     int[][] startEnd = new int[regions.size()][2];
1842
1843     regions.copyInto(startEnd);
1844
1845     return startEnd;
1846
1847   }
1848
1849   public boolean getShowHiddenMarkers()
1850   {
1851     return showHiddenMarkers;
1852   }
1853
1854   public void setShowHiddenMarkers(boolean show)
1855   {
1856     showHiddenMarkers = show;
1857   }
1858
1859   public String getSequenceSetId()
1860   {
1861     if (sequenceSetID == null)
1862     {
1863       sequenceSetID = alignment.hashCode() + "";
1864     }
1865
1866     return sequenceSetID;
1867   }
1868   /**
1869    * unique viewId for synchronizing state with stored Jalview Project 
1870    * 
1871    */
1872   private String viewId=null;
1873
1874   
1875   public String getViewId()
1876   {
1877     if (viewId==null)
1878     {
1879       viewId = this.getSequenceSetId()+"."+this.hashCode()+"";
1880     }
1881     return viewId;
1882   }
1883   
1884   public void alignmentChanged(AlignmentPanel ap)
1885   {
1886     if (padGaps)
1887     {
1888       alignment.padGaps();
1889     }
1890     if (hconsensus != null && autoCalculateConsensus)
1891     {
1892       updateConservation(ap);
1893     }
1894     if (autoCalculateConsensus)
1895     {
1896       updateConsensus(ap);
1897     }
1898
1899     // Reset endRes of groups if beyond alignment width
1900     int alWidth = alignment.getWidth();
1901     Vector groups = alignment.getGroups();
1902     if (groups != null)
1903     {
1904       for (int i = 0; i < groups.size(); i++)
1905       {
1906         SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
1907         if (sg.getEndRes() > alWidth)
1908         {
1909           sg.setEndRes(alWidth - 1);
1910         }
1911       }
1912     }
1913
1914     if (selectionGroup != null && selectionGroup.getEndRes() > alWidth)
1915     {
1916       selectionGroup.setEndRes(alWidth - 1);
1917     }
1918
1919     resetAllColourSchemes();
1920
1921     // alignment.adjustSequenceAnnotations();
1922   }
1923
1924   void resetAllColourSchemes()
1925   {
1926     ColourSchemeI cs = globalColourScheme;
1927     if (cs != null)
1928     {
1929       if (cs instanceof ClustalxColourScheme)
1930       {
1931         ((ClustalxColourScheme) cs).resetClustalX(alignment.getSequences(),
1932                 alignment.getWidth());
1933       }
1934
1935       cs.setConsensus(hconsensus);
1936       if (cs.conservationApplied())
1937       {
1938         Alignment al = (Alignment) alignment;
1939         Conservation c = new Conservation("All",
1940                 ResidueProperties.propHash, 3, al.getSequences(), 0, al
1941                         .getWidth() - 1);
1942         c.calculate();
1943         c.verdict(false, ConsPercGaps);
1944
1945         cs.setConservation(c);
1946       }
1947     }
1948
1949     int s, sSize = alignment.getGroups().size();
1950     for (s = 0; s < sSize; s++)
1951     {
1952       SequenceGroup sg = (SequenceGroup) alignment.getGroups().elementAt(s);
1953       if (sg.cs != null && sg.cs instanceof ClustalxColourScheme)
1954       {
1955         ((ClustalxColourScheme) sg.cs).resetClustalX(sg
1956                 .getSequences(hiddenRepSequences), sg.getWidth());
1957       }
1958       sg.recalcConservation();
1959     }
1960   }
1961
1962   public Color getSequenceColour(SequenceI seq)
1963   {
1964     if (sequenceColours == null || !sequenceColours.containsKey(seq))
1965     {
1966       return Color.white;
1967     }
1968     else
1969     {
1970       return (Color) sequenceColours.get(seq);
1971     }
1972   }
1973
1974   public void setSequenceColour(SequenceI seq, Color col)
1975   {
1976     if (sequenceColours == null)
1977     {
1978       sequenceColours = new Hashtable();
1979     }
1980
1981     if (col == null)
1982     {
1983       sequenceColours.remove(seq);
1984     }
1985     else
1986     {
1987       sequenceColours.put(seq, col);
1988     }
1989   }
1990
1991   /**
1992    * returns the visible column regions of the alignment
1993    * 
1994    * @param selectedRegionOnly
1995    *                true to just return the contigs intersecting with the
1996    *                selected area
1997    * @return
1998    */
1999   public int[] getViewAsVisibleContigs(boolean selectedRegionOnly)
2000   {
2001     int[] viscontigs = null;
2002     int start = 0, end = 0;
2003     if (selectedRegionOnly && selectionGroup != null)
2004     {
2005       start = selectionGroup.getStartRes();
2006       end = selectionGroup.getEndRes() + 1;
2007     }
2008     else
2009     {
2010       end = alignment.getWidth();
2011     }
2012     viscontigs = colSel.getVisibleContigs(start, end);
2013     return viscontigs;
2014   }
2015
2016   /**
2017    * get hash of undo and redo list for the alignment
2018    * 
2019    * @return long[] { historyList.hashCode, redoList.hashCode };
2020    */
2021   public long[] getUndoRedoHash()
2022   {
2023     if (historyList == null || redoList == null)
2024       return new long[]
2025       { -1, -1 };
2026     return new long[]
2027     { historyList.hashCode(), this.redoList.hashCode() };
2028   }
2029
2030   /**
2031    * test if a particular set of hashcodes are different to the hashcodes for
2032    * the undo and redo list.
2033    * 
2034    * @param undoredo
2035    *                the stored set of hashcodes as returned by getUndoRedoHash
2036    * @return true if the hashcodes differ (ie the alignment has been edited) or
2037    *         the stored hashcode array differs in size
2038    */
2039   public boolean isUndoRedoHashModified(long[] undoredo)
2040   {
2041     if (undoredo == null)
2042     {
2043       return true;
2044     }
2045     long[] cstate = getUndoRedoHash();
2046     if (cstate.length != undoredo.length)
2047     {
2048       return true;
2049     }
2050
2051     for (int i = 0; i < cstate.length; i++)
2052     {
2053       if (cstate[i] != undoredo[i])
2054       {
2055         return true;
2056       }
2057     }
2058     return false;
2059   }
2060
2061   public boolean getCentreColumnLabels()
2062   {
2063     return centreColumnLabels;
2064   }
2065
2066   public void setCentreColumnLabels(boolean centrecolumnlabels)
2067   {
2068     centreColumnLabels = centrecolumnlabels;
2069   }
2070
2071   public void updateSequenceIdColours()
2072   {
2073     Vector groups = alignment.getGroups();
2074     if (sequenceColours == null)
2075     {
2076       sequenceColours = new Hashtable();
2077     }
2078     for (int ig = 0, igSize = groups.size(); ig < igSize; ig++)
2079     {
2080       SequenceGroup sg = (SequenceGroup) groups.elementAt(ig);
2081       if (sg.idColour != null)
2082       {
2083         Vector sqs = sg.getSequences(hiddenRepSequences);
2084         for (int s = 0, sSize = sqs.size(); s < sSize; s++)
2085         {
2086           sequenceColours.put(sqs.elementAt(s), sg.idColour);
2087         }
2088       }
2089     }
2090   }
2091
2092   /**
2093    *  enable or disable the display of Database Cross References in the sequence ID tooltip
2094    */ 
2095   public void setShowDbRefs(boolean show)
2096   {
2097     showdbrefs=show;
2098   }
2099
2100   /**
2101    * 
2102    * @return true if Database References are to be displayed on tooltips.
2103    */
2104   public boolean isShowDbRefs()
2105   {
2106     return showdbrefs;
2107   }
2108
2109   /**
2110    * 
2111    * @return true if Non-positional features are to be displayed on tooltips.
2112    */
2113   public boolean isShowNpFeats()
2114   {
2115     return shownpfeats;
2116   }
2117   /**
2118    * enable or disable the display of Non-Positional sequence features in the sequence ID tooltip 
2119    * @param show 
2120    */
2121   public void setShowNpFeats(boolean show)
2122   {
2123     shownpfeats=show;
2124   }
2125   /**
2126    * 
2127    * @return true if view has hidden rows
2128    */
2129   public boolean hasHiddenRows()
2130   {
2131     return hasHiddenRows;
2132   }
2133   /**
2134    * 
2135    * @return true if view has hidden columns
2136    */
2137   public boolean hasHiddenColumns()
2138   {
2139     return hasHiddenColumns;
2140   }
2141   /**
2142    * when set, view will scroll to show the highlighted position
2143    */
2144   public boolean followHighlight=true;
2145   /**
2146    * @return true if view should scroll to show the highlighted region of a sequence
2147    * @return
2148    */
2149   public boolean getFollowHighlight() {
2150     return followHighlight;
2151   }
2152   public boolean followSelection=true;
2153   /**
2154    * @return true if view selection should always follow the selections broadcast by other selection sources
2155    */
2156   public boolean getFollowSelection() {
2157     return followSelection;
2158   }
2159   private long sgrouphash=-1,colselhash=-1;
2160
2161   boolean showSeqFeaturesHeight;
2162   /**
2163    * checks current SelectionGroup against record of last hash value, and updates record.
2164    * @return true if SelectionGroup changed since last call
2165    */
2166   boolean isSelectionGroupChanged() {
2167     int hc=(selectionGroup==null) ? -1 : selectionGroup.hashCode();
2168     if (hc!=sgrouphash)
2169     {
2170       sgrouphash = hc;
2171       return true;
2172     }
2173     return false;
2174   }
2175   /**
2176    * checks current colsel against record of last hash value, and updates record.
2177    * @return true if colsel changed since last call
2178    */
2179   boolean isColSelChanged() {
2180     int hc=(colSel==null) ? -1 : colSel.hashCode();
2181     if (hc!=colselhash)
2182     {
2183       colselhash = hc;
2184       return true;
2185     }
2186     return false;
2187   }
2188   public void sendSelection()
2189   {
2190     jalview.structure.StructureSelectionManager.getStructureSelectionManager().sendSelection(new SequenceGroup(getSelectionGroup()), new ColumnSelection(getColumnSelection()), this);
2191   }
2192   public void setShowSequenceFeaturesHeight(boolean selected)
2193   {
2194     showSeqFeaturesHeight = selected; 
2195   }
2196   public boolean getShowSequenceFeaturesHeight()
2197   {
2198     return showSeqFeaturesHeight; 
2199   }
2200
2201 }