d94fa5d12ed47403b711e023643845f31c690078
[jalview.git] / src / jalview / viewmodel / AlignmentViewport.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.viewmodel;
22
23 import jalview.analysis.Conservation;
24 import jalview.api.AlignCalcManagerI;
25 import jalview.api.AlignViewportI;
26 import jalview.api.AlignmentViewPanel;
27 import jalview.api.FeaturesDisplayedI;
28 import jalview.api.ViewStyleI;
29 import jalview.datamodel.AlignmentAnnotation;
30 import jalview.datamodel.AlignmentI;
31 import jalview.datamodel.AlignmentView;
32 import jalview.datamodel.Annotation;
33 import jalview.datamodel.ColumnSelection;
34 import jalview.datamodel.Sequence;
35 import jalview.datamodel.SequenceCollectionI;
36 import jalview.datamodel.SequenceGroup;
37 import jalview.datamodel.SequenceI;
38 import jalview.schemes.Blosum62ColourScheme;
39 import jalview.schemes.ColourSchemeI;
40 import jalview.schemes.PIDColourScheme;
41 import jalview.schemes.ResidueProperties;
42 import jalview.viewmodel.styles.ViewStyle;
43 import jalview.workers.AlignCalcManager;
44 import jalview.workers.ConsensusThread;
45 import jalview.workers.StrucConsensusThread;
46
47 import java.awt.Color;
48 import java.util.ArrayList;
49 import java.util.BitSet;
50 import java.util.Hashtable;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.Vector;
54
55 /**
56  * base class holding visualization and analysis attributes and common logic for
57  * an active alignment view displayed in the GUI
58  * 
59  * @author jimp
60  * 
61  */
62 public abstract class AlignmentViewport implements AlignViewportI,
63         ViewStyleI
64 {
65   protected ViewStyleI viewStyle = new ViewStyle();
66   
67   /**
68    * @param upperCasebold
69    * @see jalview.api.ViewStyleI#setUpperCasebold(boolean)
70    */
71   public void setUpperCasebold(boolean upperCasebold)
72   {
73     viewStyle.setUpperCasebold(upperCasebold);
74   }
75
76   /**
77    * @return
78    * @see jalview.api.ViewStyleI#isUpperCasebold()
79    */
80   public boolean isUpperCasebold()
81   {
82     return viewStyle.isUpperCasebold();
83   }
84
85   /**
86    * @return
87    * @see jalview.api.ViewStyleI#isSeqNameItalics()
88    */
89   public boolean isSeqNameItalics()
90   {
91     return viewStyle.isSeqNameItalics();
92   }
93
94   /**
95    * @param colourByReferenceSeq
96    * @see jalview.api.ViewStyleI#setColourByReferenceSeq(boolean)
97    */
98   public void setColourByReferenceSeq(boolean colourByReferenceSeq)
99   {
100     viewStyle.setColourByReferenceSeq(colourByReferenceSeq);
101   }
102
103   /**
104    * @param b
105    * @see jalview.api.ViewStyleI#setColourAppliesToAllGroups(boolean)
106    */
107   public void setColourAppliesToAllGroups(boolean b)
108   {
109     viewStyle.setColourAppliesToAllGroups(b);
110   }
111
112   /**
113    * @return
114    * @see jalview.api.ViewStyleI#getColourAppliesToAllGroups()
115    */
116   public boolean getColourAppliesToAllGroups()
117   {
118     return viewStyle.getColourAppliesToAllGroups();
119   }
120
121   /**
122    * @return
123    * @see jalview.api.ViewStyleI#getAbovePIDThreshold()
124    */
125   public boolean getAbovePIDThreshold()
126   {
127     return viewStyle.getAbovePIDThreshold();
128   }
129
130   /**
131    * @param inc
132    * @see jalview.api.ViewStyleI#setIncrement(int)
133    */
134   public void setIncrement(int inc)
135   {
136     viewStyle.setIncrement(inc);
137   }
138
139   /**
140    * @return
141    * @see jalview.api.ViewStyleI#getIncrement()
142    */
143   public int getIncrement()
144   {
145     return viewStyle.getIncrement();
146   }
147
148   /**
149    * @param b
150    * @see jalview.api.ViewStyleI#setConservationSelected(boolean)
151    */
152   public void setConservationSelected(boolean b)
153   {
154     viewStyle.setConservationSelected(b);
155   }
156
157   /**
158    * @param show
159    * @see jalview.api.ViewStyleI#setShowHiddenMarkers(boolean)
160    */
161   public void setShowHiddenMarkers(boolean show)
162   {
163     viewStyle.setShowHiddenMarkers(show);
164   }
165
166   /**
167    * @return
168    * @see jalview.api.ViewStyleI#getShowHiddenMarkers()
169    */
170   public boolean getShowHiddenMarkers()
171   {
172     return viewStyle.getShowHiddenMarkers();
173   }
174
175   /**
176    * @param b
177    * @see jalview.api.ViewStyleI#setScaleRightWrapped(boolean)
178    */
179   public void setScaleRightWrapped(boolean b)
180   {
181     viewStyle.setScaleRightWrapped(b);
182   }
183
184   /**
185    * @param b
186    * @see jalview.api.ViewStyleI#setScaleLeftWrapped(boolean)
187    */
188   public void setScaleLeftWrapped(boolean b)
189   {
190     viewStyle.setScaleLeftWrapped(b);
191   }
192
193   /**
194    * @param b
195    * @see jalview.api.ViewStyleI#setScaleAboveWrapped(boolean)
196    */
197   public void setScaleAboveWrapped(boolean b)
198   {
199     viewStyle.setScaleAboveWrapped(b);
200   }
201
202   /**
203    * @return
204    * @see jalview.api.ViewStyleI#getScaleLeftWrapped()
205    */
206   public boolean getScaleLeftWrapped()
207   {
208     return viewStyle.getScaleLeftWrapped();
209   }
210
211   /**
212    * @return
213    * @see jalview.api.ViewStyleI#getScaleAboveWrapped()
214    */
215   public boolean getScaleAboveWrapped()
216   {
217     return viewStyle.getScaleAboveWrapped();
218   }
219
220   /**
221    * @return
222    * @see jalview.api.ViewStyleI#getScaleRightWrapped()
223    */
224   public boolean getScaleRightWrapped()
225   {
226     return viewStyle.getScaleRightWrapped();
227   }
228
229   /**
230    * @param b
231    * @see jalview.api.ViewStyleI#setAbovePIDThreshold(boolean)
232    */
233   public void setAbovePIDThreshold(boolean b)
234   {
235     viewStyle.setAbovePIDThreshold(b);
236   }
237
238   /**
239    * @param thresh
240    * @see jalview.api.ViewStyleI#setThreshold(int)
241    */
242   public void setThreshold(int thresh)
243   {
244     viewStyle.setThreshold(thresh);
245   }
246
247   /**
248    * @return
249    * @see jalview.api.ViewStyleI#getThreshold()
250    */
251   public int getThreshold()
252   {
253     return viewStyle.getThreshold();
254   }
255
256   /**
257    * @return
258    * @see jalview.api.ViewStyleI#getShowJVSuffix()
259    */
260   public boolean getShowJVSuffix()
261   {
262     return viewStyle.getShowJVSuffix();
263   }
264
265   /**
266    * @param b
267    * @see jalview.api.ViewStyleI#setShowJVSuffix(boolean)
268    */
269   public void setShowJVSuffix(boolean b)
270   {
271     viewStyle.setShowJVSuffix(b);
272   }
273
274   /**
275    * @param state
276    * @see jalview.api.ViewStyleI#setWrapAlignment(boolean)
277    */
278   public void setWrapAlignment(boolean state)
279   {
280     viewStyle.setWrapAlignment(state);
281   }
282
283   /**
284    * @param state
285    * @see jalview.api.ViewStyleI#setShowText(boolean)
286    */
287   public void setShowText(boolean state)
288   {
289     viewStyle.setShowText(state);
290   }
291
292   /**
293    * @param state
294    * @see jalview.api.ViewStyleI#setRenderGaps(boolean)
295    */
296   public void setRenderGaps(boolean state)
297   {
298     viewStyle.setRenderGaps(state);
299   }
300
301   /**
302    * @return
303    * @see jalview.api.ViewStyleI#getColourText()
304    */
305   public boolean getColourText()
306   {
307     return viewStyle.getColourText();
308   }
309
310   /**
311    * @param state
312    * @see jalview.api.ViewStyleI#setColourText(boolean)
313    */
314   public void setColourText(boolean state)
315   {
316     viewStyle.setColourText(state);
317   }
318
319   /**
320    * @return
321    * @see jalview.api.ViewStyleI#getWrapAlignment()
322    */
323   public boolean getWrapAlignment()
324   {
325     return viewStyle.getWrapAlignment();
326   }
327
328   /**
329    * @return
330    * @see jalview.api.ViewStyleI#getShowText()
331    */
332   public boolean getShowText()
333   {
334     return viewStyle.getShowText();
335   }
336
337   /**
338    * @return
339    * @see jalview.api.ViewStyleI#getWrappedWidth()
340    */
341   public int getWrappedWidth()
342   {
343     return viewStyle.getWrappedWidth();
344   }
345
346   /**
347    * @param w
348    * @see jalview.api.ViewStyleI#setWrappedWidth(int)
349    */
350   public void setWrappedWidth(int w)
351   {
352     viewStyle.setWrappedWidth(w);
353   }
354
355   /**
356    * @return
357    * @see jalview.api.ViewStyleI#getCharHeight()
358    */
359   public int getCharHeight()
360   {
361     return viewStyle.getCharHeight();
362   }
363
364   /**
365    * @param h
366    * @see jalview.api.ViewStyleI#setCharHeight(int)
367    */
368   public void setCharHeight(int h)
369   {
370     viewStyle.setCharHeight(h);
371   }
372
373   /**
374    * @return
375    * @see jalview.api.ViewStyleI#getCharWidth()
376    */
377   public int getCharWidth()
378   {
379     return viewStyle.getCharWidth();
380   }
381
382   /**
383    * @param w
384    * @see jalview.api.ViewStyleI#setCharWidth(int)
385    */
386   public void setCharWidth(int w)
387   {
388     viewStyle.setCharWidth(w);
389   }
390
391   /**
392    * @return
393    * @see jalview.api.ViewStyleI#getShowBoxes()
394    */
395   public boolean getShowBoxes()
396   {
397     return viewStyle.getShowBoxes();
398   }
399
400   /**
401    * @return
402    * @see jalview.api.ViewStyleI#getShowUnconserved()
403    */
404   public boolean getShowUnconserved()
405   {
406     return viewStyle.getShowUnconserved();
407   }
408
409   /**
410    * @param showunconserved
411    * @see jalview.api.ViewStyleI#setShowUnconserved(boolean)
412    */
413   public void setShowUnconserved(boolean showunconserved)
414   {
415     viewStyle.setShowUnconserved(showunconserved);
416   }
417
418   /**
419    * @param default1
420    * @see jalview.api.ViewStyleI#setSeqNameItalics(boolean)
421    */
422   public void setSeqNameItalics(boolean default1)
423   {
424     viewStyle.setSeqNameItalics(default1);
425   }
426
427   /**
428    * @param selected
429    * @see jalview.api.ViewStyleI#setShowSeqFeaturesHeight(boolean)
430    */
431   public void setShowSeqFeaturesHeight(boolean selected)
432   {
433     viewStyle.setShowSeqFeaturesHeight(selected);
434   }
435
436   /**
437    * alignment displayed in the viewport. Please use get/setter
438    */
439   protected AlignmentI alignment;
440
441   @Override
442   public AlignmentI getAlignment()
443   {
444     return alignment;
445   }
446
447   @Override
448   public char getGapCharacter()
449   {
450     return alignment.getGapCharacter();
451   }
452
453   protected String sequenceSetID;
454
455   /**
456    * probably unused indicator that view is of a dataset rather than an
457    * alignment
458    */
459   protected boolean isDataset = false;
460
461   public void setDataset(boolean b)
462   {
463     isDataset = b;
464   }
465
466   public boolean isDataset()
467   {
468     return isDataset;
469   }
470
471
472   private Map<SequenceI, SequenceCollectionI> hiddenRepSequences;
473
474   protected ColumnSelection colSel = new ColumnSelection();
475
476   public boolean autoCalculateConsensus = true;
477
478   protected boolean autoCalculateStrucConsensus = true;
479
480   protected boolean ignoreGapsInConsensusCalculation = false;
481
482   protected ColourSchemeI globalColourScheme = null;
483
484
485   @Override
486   public void setGlobalColourScheme(ColourSchemeI cs)
487   {
488     // TODO: logic refactored from AlignFrame changeColour -
489     // autorecalc stuff should be changed to rely on the worker system
490     // check to see if we should implement a changeColour(cs) method rather than
491     // put th logic in here
492     // - means that caller decides if they want to just modify state and defer
493     // calculation till later or to do all calculations in thread.
494     // via changecolour
495     globalColourScheme = cs;
496     boolean recalc = false;
497     if (cs != null)
498     {
499       cs.setConservationApplied(recalc = getConservationSelected());
500       if (getAbovePIDThreshold() || cs instanceof PIDColourScheme
501               || cs instanceof Blosum62ColourScheme)
502       {
503         recalc = true;
504         cs.setThreshold(viewStyle.getThreshold(),
505                 ignoreGapsInConsensusCalculation);
506       }
507       else
508       {
509         cs.setThreshold(0, ignoreGapsInConsensusCalculation);
510       }
511       if (recalc)
512       {
513         cs.setConsensus(hconsensus);
514         cs.setConservation(hconservation);
515       }
516       cs.alignmentChanged(alignment, hiddenRepSequences);
517     }
518     if (getColourAppliesToAllGroups())
519     {
520       for (SequenceGroup sg : getAlignment().getGroups())
521       {
522         if (cs == null)
523         {
524           sg.cs = null;
525           continue;
526         }
527         sg.cs = cs.applyTo(sg, getHiddenRepSequences());
528         sg.setConsPercGaps(ConsPercGaps);
529         if (getAbovePIDThreshold() || cs instanceof PIDColourScheme
530                 || cs instanceof Blosum62ColourScheme)
531         {
532           sg.cs.setThreshold(viewStyle.getThreshold(),
533                   getIgnoreGapsConsensus());
534           recalc = true;
535         }
536         else
537         {
538           sg.cs.setThreshold(0, getIgnoreGapsConsensus());
539         }
540
541         if (getConservationSelected())
542         {
543           sg.cs.setConservationApplied(true);
544           recalc = true;
545         }
546         else
547         {
548           sg.cs.setConservation(null);
549           // sg.cs.setThreshold(0, getIgnoreGapsConsensus());
550         }
551         if (recalc)
552         {
553           sg.recalcConservation();
554         }
555         else
556         {
557           sg.cs.alignmentChanged(sg, hiddenRepSequences);
558         }
559       }
560     }
561
562   }
563
564   @Override
565   public ColourSchemeI getGlobalColourScheme()
566   {
567     return globalColourScheme;
568   }
569
570   protected AlignmentAnnotation consensus;
571
572   protected AlignmentAnnotation strucConsensus;
573
574   protected AlignmentAnnotation conservation;
575
576   protected AlignmentAnnotation quality;
577
578   protected AlignmentAnnotation[] groupConsensus;
579
580   protected AlignmentAnnotation[] groupConservation;
581
582   /**
583    * results of alignment consensus analysis for visible portion of view
584    */
585   protected Hashtable[] hconsensus = null;
586
587   /**
588    * results of secondary structure base pair consensus for visible portion of
589    * view
590    */
591   protected Hashtable[] hStrucConsensus = null;
592
593   protected Conservation hconservation = null;
594
595   @Override
596   public void setConservation(Conservation cons)
597   {
598     hconservation = cons;
599   }
600
601   /**
602    * percentage gaps allowed in a column before all amino acid properties should
603    * be considered unconserved
604    */
605   int ConsPercGaps = 25; // JBPNote : This should be a scalable property!
606
607   @Override
608   public int getConsPercGaps()
609   {
610     return ConsPercGaps;
611   }
612
613   @Override
614   public void setSequenceConsensusHash(Hashtable[] hconsensus)
615   {
616     this.hconsensus = hconsensus;
617
618   }
619
620   @Override
621   public Hashtable[] getSequenceConsensusHash()
622   {
623     return hconsensus;
624   }
625
626   @Override
627   public Hashtable[] getRnaStructureConsensusHash()
628   {
629     return hStrucConsensus;
630   }
631
632   @Override
633   public void setRnaStructureConsensusHash(Hashtable[] hStrucConsensus)
634   {
635     this.hStrucConsensus = hStrucConsensus;
636
637   }
638
639   @Override
640   public AlignmentAnnotation getAlignmentQualityAnnot()
641   {
642     return quality;
643   }
644
645   @Override
646   public AlignmentAnnotation getAlignmentConservationAnnotation()
647   {
648     return conservation;
649   }
650
651   @Override
652   public AlignmentAnnotation getAlignmentConsensusAnnotation()
653   {
654     return consensus;
655   }
656
657   @Override
658   public AlignmentAnnotation getAlignmentStrucConsensusAnnotation()
659   {
660     return strucConsensus;
661   }
662
663   protected AlignCalcManagerI calculator = new AlignCalcManager();
664
665   /**
666    * trigger update of conservation annotation
667    */
668   public void updateConservation(final AlignmentViewPanel ap)
669   {
670     // see note in mantis : issue number 8585
671     if (alignment.isNucleotide() || conservation == null
672             || !autoCalculateConsensus)
673     {
674       return;
675     }
676     if (calculator
677             .getRegisteredWorkersOfClass(jalview.workers.ConservationThread.class) == null)
678     {
679       calculator.registerWorker(new jalview.workers.ConservationThread(
680               this, ap));
681     }
682   }
683
684   /**
685    * trigger update of consensus annotation
686    */
687   public void updateConsensus(final AlignmentViewPanel ap)
688   {
689     // see note in mantis : issue number 8585
690     if (consensus == null || !autoCalculateConsensus)
691     {
692       return;
693     }
694     if (calculator.getRegisteredWorkersOfClass(ConsensusThread.class) == null)
695     {
696       calculator.registerWorker(new ConsensusThread(this, ap));
697     }
698   }
699
700   // --------START Structure Conservation
701   public void updateStrucConsensus(final AlignmentViewPanel ap)
702   {
703     if (autoCalculateStrucConsensus && strucConsensus == null
704             && alignment.isNucleotide() && alignment.hasRNAStructure())
705     {
706       // secondary structure has been added - so init the consensus line
707       initRNAStructure();
708     }
709
710     // see note in mantis : issue number 8585
711     if (strucConsensus == null || !autoCalculateStrucConsensus)
712     {
713       return;
714     }
715     if (calculator.getRegisteredWorkersOfClass(StrucConsensusThread.class) == null)
716     {
717       calculator.registerWorker(new StrucConsensusThread(this, ap));
718     }
719   }
720
721   public boolean isCalcInProgress()
722   {
723     return calculator.isWorking();
724   }
725
726   @Override
727   public boolean isCalculationInProgress(
728           AlignmentAnnotation alignmentAnnotation)
729   {
730     if (!alignmentAnnotation.autoCalculated)
731     {
732       return false;
733     }
734     if (calculator.workingInvolvedWith(alignmentAnnotation))
735     {
736       // System.err.println("grey out ("+alignmentAnnotation.label+")");
737       return true;
738     }
739     return false;
740   }
741
742   @Override
743   public boolean isClosed()
744   {
745     // TODO: check that this isClosed is only true after panel is closed, not
746     // before it is fully constructed.
747     return alignment == null;
748   }
749
750   @Override
751   public AlignCalcManagerI getCalcManager()
752   {
753     return calculator;
754   }
755
756   /**
757    * should conservation rows be shown for groups
758    */
759   protected boolean showGroupConservation = false;
760
761   /**
762    * should consensus rows be shown for groups
763    */
764   protected boolean showGroupConsensus = false;
765
766   /**
767    * should consensus profile be rendered by default
768    */
769   protected boolean showSequenceLogo = false;
770
771   /**
772    * should consensus profile be rendered normalised to row height
773    */
774   protected boolean normaliseSequenceLogo = false;
775
776   /**
777    * should consensus histograms be rendered by default
778    */
779   protected boolean showConsensusHistogram = true;
780
781   /**
782    * @return the showConsensusProfile
783    */
784   @Override
785   public boolean isShowSequenceLogo()
786   {
787     return showSequenceLogo;
788   }
789
790   /**
791    * @param showSequenceLogo
792    *          the new value
793    */
794   public void setShowSequenceLogo(boolean showSequenceLogo)
795   {
796     if (showSequenceLogo != this.showSequenceLogo)
797     {
798       // TODO: decouple settings setting from calculation when refactoring
799       // annotation update method from alignframe to viewport
800       this.showSequenceLogo = showSequenceLogo;
801       calculator.updateAnnotationFor(ConsensusThread.class);
802       calculator.updateAnnotationFor(StrucConsensusThread.class);
803     }
804     this.showSequenceLogo = showSequenceLogo;
805   }
806
807   /**
808    * @param showConsensusHistogram
809    *          the showConsensusHistogram to set
810    */
811   public void setShowConsensusHistogram(boolean showConsensusHistogram)
812   {
813     this.showConsensusHistogram = showConsensusHistogram;
814   }
815
816   /**
817    * @return the showGroupConservation
818    */
819   public boolean isShowGroupConservation()
820   {
821     return showGroupConservation;
822   }
823
824   /**
825    * @param showGroupConservation
826    *          the showGroupConservation to set
827    */
828   public void setShowGroupConservation(boolean showGroupConservation)
829   {
830     this.showGroupConservation = showGroupConservation;
831   }
832
833   /**
834    * @return the showGroupConsensus
835    */
836   public boolean isShowGroupConsensus()
837   {
838     return showGroupConsensus;
839   }
840
841   /**
842    * @param showGroupConsensus
843    *          the showGroupConsensus to set
844    */
845   public void setShowGroupConsensus(boolean showGroupConsensus)
846   {
847     this.showGroupConsensus = showGroupConsensus;
848   }
849
850   /**
851    * 
852    * @return flag to indicate if the consensus histogram should be rendered by
853    *         default
854    */
855   @Override
856   public boolean isShowConsensusHistogram()
857   {
858     return this.showConsensusHistogram;
859   }
860
861   /**
862    * when set, updateAlignment will always ensure sequences are of equal length
863    */
864   private boolean padGaps = false;
865
866   /**
867    * when set, alignment should be reordered according to a newly opened tree
868    */
869   public boolean sortByTree = false;
870
871
872   /**
873    * 
874    * 
875    * @return null or the currently selected sequence region
876    */
877   @Override
878   public SequenceGroup getSelectionGroup()
879   {
880     return selectionGroup;
881   }
882
883   /**
884    * Set the selection group for this window.
885    * 
886    * @param sg
887    *          - group holding references to sequences in this alignment view
888    * 
889    */
890   @Override
891   public void setSelectionGroup(SequenceGroup sg)
892   {
893     selectionGroup = sg;
894   }
895
896   public void setHiddenColumns(ColumnSelection colsel)
897   {
898     this.colSel = colsel;
899   }
900
901   @Override
902   public ColumnSelection getColumnSelection()
903   {
904     return colSel;
905   }
906
907   @Override
908   public void setColumnSelection(ColumnSelection colSel)
909   {
910     this.colSel = colSel;
911     if (colSel != null)
912     {
913       updateHiddenColumns();
914     }
915   }
916
917   /**
918    * 
919    * @return
920    */
921   @Override
922   public Map<SequenceI, SequenceCollectionI> getHiddenRepSequences()
923   {
924     return hiddenRepSequences;
925   }
926
927   @Override
928   public void setHiddenRepSequences(
929           Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
930   {
931     this.hiddenRepSequences = hiddenRepSequences;
932   }
933
934   @Override
935   public boolean hasHiddenColumns()
936   {
937     return colSel != null && colSel.hasHiddenColumns();
938   }
939
940   public void updateHiddenColumns()
941   {
942     // this method doesn't really do anything now. But - it could, since a
943     // column Selection could be in the process of modification
944     // hasHiddenColumns = colSel.hasHiddenColumns();
945   }
946
947   protected boolean hasHiddenRows = false;
948
949   @Override
950   public boolean hasHiddenRows()
951   {
952     return hasHiddenRows;
953   }
954
955   protected SequenceGroup selectionGroup;
956
957   public void setSequenceSetId(String newid)
958   {
959     if (sequenceSetID != null)
960     {
961       System.err
962               .println("Warning - overwriting a sequenceSetId for a viewport!");
963     }
964     sequenceSetID = new String(newid);
965   }
966
967   @Override
968   public String getSequenceSetId()
969   {
970     if (sequenceSetID == null)
971     {
972       sequenceSetID = alignment.hashCode() + "";
973     }
974
975     return sequenceSetID;
976   }
977
978   /**
979    * unique viewId for synchronizing state (e.g. with stored Jalview Project)
980    * 
981    */
982   protected String viewId = null;
983
984   public String getViewId()
985   {
986     if (viewId == null)
987     {
988       viewId = this.getSequenceSetId() + "." + this.hashCode() + "";
989     }
990     return viewId;
991   }
992
993   public void setIgnoreGapsConsensus(boolean b, AlignmentViewPanel ap)
994   {
995     ignoreGapsInConsensusCalculation = b;
996     if (ap != null)
997     {
998       updateConsensus(ap);
999       if (globalColourScheme != null)
1000       {
1001         globalColourScheme.setThreshold(globalColourScheme.getThreshold(),
1002                 ignoreGapsInConsensusCalculation);
1003       }
1004     }
1005
1006   }
1007
1008   private long sgrouphash = -1, colselhash = -1;
1009
1010   /**
1011    * checks current SelectionGroup against record of last hash value, and
1012    * updates record.
1013    * 
1014    * @param b
1015    *          update the record of last hash value
1016    * 
1017    * @return true if SelectionGroup changed since last call (when b is true)
1018    */
1019   public boolean isSelectionGroupChanged(boolean b)
1020   {
1021     int hc = (selectionGroup == null || selectionGroup.getSize() == 0) ? -1
1022             : selectionGroup.hashCode();
1023     if (hc != -1 && hc != sgrouphash)
1024     {
1025       if (b)
1026       {
1027         sgrouphash = hc;
1028       }
1029       return true;
1030     }
1031     return false;
1032   }
1033
1034   /**
1035    * checks current colsel against record of last hash value, and optionally
1036    * updates record.
1037    * 
1038    * @param b
1039    *          update the record of last hash value
1040    * @return true if colsel changed since last call (when b is true)
1041    */
1042   public boolean isColSelChanged(boolean b)
1043   {
1044     int hc = (colSel == null || colSel.size() == 0) ? -1 : colSel
1045             .hashCode();
1046     if (hc != -1 && hc != colselhash)
1047     {
1048       if (b)
1049       {
1050         colselhash = hc;
1051       }
1052       return true;
1053     }
1054     return false;
1055   }
1056
1057   @Override
1058   public boolean getIgnoreGapsConsensus()
1059   {
1060     return ignoreGapsInConsensusCalculation;
1061   }
1062
1063   // / property change stuff
1064
1065   // JBPNote Prolly only need this in the applet version.
1066   private final java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(
1067           this);
1068
1069   protected boolean showConservation = true;
1070
1071   protected boolean showQuality = true;
1072
1073   protected boolean showConsensus = true;
1074
1075   Hashtable sequenceColours;
1076
1077   /**
1078    * Property change listener for changes in alignment
1079    * 
1080    * @param listener
1081    *          DOCUMENT ME!
1082    */
1083   public void addPropertyChangeListener(
1084           java.beans.PropertyChangeListener listener)
1085   {
1086     changeSupport.addPropertyChangeListener(listener);
1087   }
1088
1089   /**
1090    * DOCUMENT ME!
1091    * 
1092    * @param listener
1093    *          DOCUMENT ME!
1094    */
1095   public void removePropertyChangeListener(
1096           java.beans.PropertyChangeListener listener)
1097   {
1098     changeSupport.removePropertyChangeListener(listener);
1099   }
1100
1101   /**
1102    * Property change listener for changes in alignment
1103    * 
1104    * @param prop
1105    *          DOCUMENT ME!
1106    * @param oldvalue
1107    *          DOCUMENT ME!
1108    * @param newvalue
1109    *          DOCUMENT ME!
1110    */
1111   public void firePropertyChange(String prop, Object oldvalue,
1112           Object newvalue)
1113   {
1114     changeSupport.firePropertyChange(prop, oldvalue, newvalue);
1115   }
1116
1117   // common hide/show column stuff
1118
1119   public void hideSelectedColumns()
1120   {
1121     if (colSel.size() < 1)
1122     {
1123       return;
1124     }
1125
1126     colSel.hideSelectedColumns();
1127     setSelectionGroup(null);
1128
1129   }
1130
1131   public void hideColumns(int start, int end)
1132   {
1133     if (start == end)
1134     {
1135       colSel.hideColumns(start);
1136     }
1137     else
1138     {
1139       colSel.hideColumns(start, end);
1140     }
1141   }
1142
1143   public void showColumn(int col)
1144   {
1145     colSel.revealHiddenColumns(col);
1146
1147   }
1148
1149   public void showAllHiddenColumns()
1150   {
1151     colSel.revealAllHiddenColumns();
1152   }
1153
1154   // common hide/show seq stuff
1155   public void showAllHiddenSeqs()
1156   {
1157     if (alignment.getHiddenSequences().getSize() > 0)
1158     {
1159       if (selectionGroup == null)
1160       {
1161         selectionGroup = new SequenceGroup();
1162         selectionGroup.setEndRes(alignment.getWidth() - 1);
1163       }
1164       List<SequenceI> tmp = alignment.getHiddenSequences().showAll(
1165               hiddenRepSequences);
1166       for (SequenceI seq : tmp)
1167       {
1168         selectionGroup.addSequence(seq, false);
1169         setSequenceAnnotationsVisible(seq, true);
1170       }
1171
1172       hasHiddenRows = false;
1173       hiddenRepSequences = null;
1174
1175       firePropertyChange("alignment", null, alignment.getSequences());
1176       // used to set hasHiddenRows/hiddenRepSequences here, after the property
1177       // changed event
1178       sendSelection();
1179     }
1180   }
1181
1182   public void showSequence(int index)
1183   {
1184     List<SequenceI> tmp = alignment.getHiddenSequences().showSequence(
1185             index,
1186             hiddenRepSequences);
1187     if (tmp.size() > 0)
1188     {
1189       if (selectionGroup == null)
1190       {
1191         selectionGroup = new SequenceGroup();
1192         selectionGroup.setEndRes(alignment.getWidth() - 1);
1193       }
1194
1195       for (SequenceI seq : tmp)
1196       {
1197         selectionGroup.addSequence(seq, false);
1198         setSequenceAnnotationsVisible(seq, true);
1199       }
1200       // JBPNote: refactor: only update flag if we modified visiblity (used to
1201       // do this regardless)
1202       if (alignment.getHiddenSequences().getSize() < 1)
1203       {
1204         hasHiddenRows = false;
1205       }
1206       firePropertyChange("alignment", null, alignment.getSequences());
1207       sendSelection();
1208     }
1209   }
1210
1211   public void hideAllSelectedSeqs()
1212   {
1213     if (selectionGroup == null || selectionGroup.getSize() < 1)
1214     {
1215       return;
1216     }
1217
1218     SequenceI[] seqs = selectionGroup.getSequencesInOrder(alignment);
1219
1220     hideSequence(seqs);
1221
1222     setSelectionGroup(null);
1223   }
1224
1225   public void hideSequence(SequenceI[] seq)
1226   {
1227     if (seq != null)
1228     {
1229       for (int i = 0; i < seq.length; i++)
1230       {
1231         alignment.getHiddenSequences().hideSequence(seq[i]);
1232         setSequenceAnnotationsVisible(seq[i], false);
1233       }
1234       hasHiddenRows = true;
1235       firePropertyChange("alignment", null, alignment.getSequences());
1236     }
1237   }
1238
1239   /**
1240    * Set visibility for any annotations for the given sequence.
1241    * 
1242    * @param sequenceI
1243    */
1244   protected void setSequenceAnnotationsVisible(SequenceI sequenceI,
1245           boolean visible)
1246   {
1247     for (AlignmentAnnotation ann : alignment.getAlignmentAnnotation())
1248     {
1249       if (ann.sequenceRef == sequenceI)
1250       {
1251         ann.visible = visible;
1252       }
1253     }
1254   }
1255
1256   public void hideRepSequences(SequenceI repSequence, SequenceGroup sg)
1257   {
1258     int sSize = sg.getSize();
1259     if (sSize < 2)
1260     {
1261       return;
1262     }
1263
1264     if (hiddenRepSequences == null)
1265     {
1266       hiddenRepSequences = new Hashtable();
1267     }
1268
1269     hiddenRepSequences.put(repSequence, sg);
1270
1271     // Hide all sequences except the repSequence
1272     SequenceI[] seqs = new SequenceI[sSize - 1];
1273     int index = 0;
1274     for (int i = 0; i < sSize; i++)
1275     {
1276       if (sg.getSequenceAt(i) != repSequence)
1277       {
1278         if (index == sSize - 1)
1279         {
1280           return;
1281         }
1282
1283         seqs[index++] = sg.getSequenceAt(i);
1284       }
1285     }
1286     sg.setSeqrep(repSequence); // note: not done in 2.7applet
1287     sg.setHidereps(true); // note: not done in 2.7applet
1288     hideSequence(seqs);
1289
1290   }
1291
1292   public boolean isHiddenRepSequence(SequenceI seq)
1293   {
1294     return alignment.getSeqrep()==seq || (hiddenRepSequences != null
1295             && hiddenRepSequences.containsKey(seq));
1296   }
1297
1298   public SequenceGroup getRepresentedSequences(SequenceI seq)
1299   {
1300     return (SequenceGroup) (hiddenRepSequences == null ? null
1301             : hiddenRepSequences.get(seq));
1302   }
1303
1304   @Override
1305   public int adjustForHiddenSeqs(int alignmentIndex)
1306   {
1307     return alignment.getHiddenSequences().adjustForHiddenSeqs(
1308             alignmentIndex);
1309   }
1310
1311   @Override
1312   public abstract void sendSelection();
1313
1314   @Override
1315   public void invertColumnSelection()
1316   {
1317     colSel.invertColumnSelection(0, alignment.getWidth());
1318   }
1319
1320
1321   @Override
1322   public SequenceI[] getSelectionAsNewSequence()
1323   {
1324     SequenceI[] sequences;
1325     // JBPNote: Need to test jalviewLite.getSelectedSequencesAsAlignmentFrom -
1326     // this was the only caller in the applet for this method
1327     // JBPNote: in applet, this method returned references to the alignment
1328     // sequences, and it did not honour the presence/absence of annotation
1329     // attached to the alignment (probably!)
1330     if (selectionGroup == null || selectionGroup.getSize() == 0)
1331     {
1332       sequences = alignment.getSequencesArray();
1333       AlignmentAnnotation[] annots = alignment.getAlignmentAnnotation();
1334       for (int i = 0; i < sequences.length; i++)
1335       {
1336         sequences[i] = new Sequence(sequences[i], annots); // construct new
1337         // sequence with
1338         // subset of visible
1339         // annotation
1340       }
1341     }
1342     else
1343     {
1344       sequences = selectionGroup.getSelectionAsNewSequences(alignment);
1345     }
1346
1347     return sequences;
1348   }
1349
1350
1351   @Override
1352   public SequenceI[] getSequenceSelection()
1353   {
1354     SequenceI[] sequences = null;
1355     if (selectionGroup != null)
1356     {
1357       sequences = selectionGroup.getSequencesInOrder(alignment);
1358     }
1359     if (sequences == null)
1360     {
1361       sequences = alignment.getSequencesArray();
1362     }
1363     return sequences;
1364   }
1365
1366
1367   @Override
1368   public jalview.datamodel.CigarArray getViewAsCigars(
1369           boolean selectedRegionOnly)
1370   {
1371     return new jalview.datamodel.CigarArray(alignment, colSel,
1372             (selectedRegionOnly ? selectionGroup : null));
1373   }
1374
1375
1376   @Override
1377   public jalview.datamodel.AlignmentView getAlignmentView(
1378           boolean selectedOnly)
1379   {
1380     return getAlignmentView(selectedOnly, false);
1381   }
1382
1383
1384   @Override
1385   public jalview.datamodel.AlignmentView getAlignmentView(
1386           boolean selectedOnly, boolean markGroups)
1387   {
1388     return new AlignmentView(alignment, colSel, selectionGroup,
1389             colSel != null && colSel.hasHiddenColumns(), selectedOnly,
1390             markGroups);
1391   }
1392
1393
1394   @Override
1395   public String[] getViewAsString(boolean selectedRegionOnly)
1396   {
1397     String[] selection = null;
1398     SequenceI[] seqs = null;
1399     int i, iSize;
1400     int start = 0, end = 0;
1401     if (selectedRegionOnly && selectionGroup != null)
1402     {
1403       iSize = selectionGroup.getSize();
1404       seqs = selectionGroup.getSequencesInOrder(alignment);
1405       start = selectionGroup.getStartRes();
1406       end = selectionGroup.getEndRes() + 1;
1407     }
1408     else
1409     {
1410       iSize = alignment.getHeight();
1411       seqs = alignment.getSequencesArray();
1412       end = alignment.getWidth();
1413     }
1414
1415     selection = new String[iSize];
1416     if (colSel != null && colSel.hasHiddenColumns())
1417     {
1418       selection = colSel.getVisibleSequenceStrings(start, end, seqs);
1419     }
1420     else
1421     {
1422       for (i = 0; i < iSize; i++)
1423       {
1424         selection[i] = seqs[i].getSequenceAsString(start, end);
1425       }
1426
1427     }
1428     return selection;
1429   }
1430
1431
1432   @Override
1433   public int[][] getVisibleRegionBoundaries(int min, int max)
1434   {
1435     Vector regions = new Vector();
1436     int start = min;
1437     int end = max;
1438
1439     do
1440     {
1441       if (colSel != null && colSel.hasHiddenColumns())
1442       {
1443         if (start == 0)
1444         {
1445           start = colSel.adjustForHiddenColumns(start);
1446         }
1447
1448         end = colSel.getHiddenBoundaryRight(start);
1449         if (start == end)
1450         {
1451           end = max;
1452         }
1453         if (end > max)
1454         {
1455           end = max;
1456         }
1457       }
1458
1459       regions.addElement(new int[]
1460       { start, end });
1461
1462       if (colSel != null && colSel.hasHiddenColumns())
1463       {
1464         start = colSel.adjustForHiddenColumns(end);
1465         start = colSel.getHiddenBoundaryLeft(start) + 1;
1466       }
1467     } while (end < max);
1468
1469     int[][] startEnd = new int[regions.size()][2];
1470
1471     regions.copyInto(startEnd);
1472
1473     return startEnd;
1474
1475   }
1476
1477   @Override
1478   public List<AlignmentAnnotation> getVisibleAlignmentAnnotation(boolean selectedOnly)
1479   {
1480     ArrayList<AlignmentAnnotation> ala = new ArrayList<AlignmentAnnotation>();
1481     AlignmentAnnotation[] aa;
1482     if ((aa=alignment.getAlignmentAnnotation())!=null)
1483     {
1484       for (AlignmentAnnotation annot:aa)
1485       {
1486         AlignmentAnnotation clone = new AlignmentAnnotation(annot);
1487         if (selectedOnly && selectionGroup!=null)
1488         {
1489           colSel.makeVisibleAnnotation(selectionGroup.getStartRes(), selectionGroup.getEndRes(),clone);
1490         } else {
1491           colSel.makeVisibleAnnotation(clone);
1492         }
1493         ala.add(clone);
1494       }
1495     }
1496     return ala;
1497   }
1498
1499
1500   @Override
1501   public boolean isPadGaps()
1502   {
1503     return padGaps;
1504   }
1505
1506
1507   @Override
1508   public void setPadGaps(boolean padGaps)
1509   {
1510     this.padGaps = padGaps;
1511   }
1512
1513   /**
1514    * apply any post-edit constraints and trigger any calculations needed after
1515    * an edit has been performed on the alignment
1516    * 
1517    * @param ap
1518    */
1519   @Override
1520   public void alignmentChanged(AlignmentViewPanel ap)
1521   {
1522     if (isPadGaps())
1523     {
1524       alignment.padGaps();
1525     }
1526     if (autoCalculateConsensus)
1527     {
1528       updateConsensus(ap);
1529     }
1530     if (hconsensus != null && autoCalculateConsensus)
1531     {
1532       updateConservation(ap);
1533     }
1534     if (autoCalculateStrucConsensus)
1535     {
1536       updateStrucConsensus(ap);
1537     }
1538
1539     // Reset endRes of groups if beyond alignment width
1540     int alWidth = alignment.getWidth();
1541     List<SequenceGroup> groups = alignment.getGroups();
1542     if (groups != null)
1543     {
1544       for (SequenceGroup sg : groups)
1545       {
1546         if (sg.getEndRes() > alWidth)
1547         {
1548           sg.setEndRes(alWidth - 1);
1549         }
1550       }
1551     }
1552
1553     if (selectionGroup != null && selectionGroup.getEndRes() > alWidth)
1554     {
1555       selectionGroup.setEndRes(alWidth - 1);
1556     }
1557
1558     resetAllColourSchemes();
1559     calculator.restartWorkers();
1560     // alignment.adjustSequenceAnnotations();
1561   }
1562
1563   /**
1564    * reset scope and do calculations for all applied colourschemes on alignment
1565    */
1566   void resetAllColourSchemes()
1567   {
1568     ColourSchemeI cs = globalColourScheme;
1569     if (cs != null)
1570     {
1571       cs.alignmentChanged(alignment, hiddenRepSequences);
1572
1573       cs.setConsensus(hconsensus);
1574       if (cs.conservationApplied())
1575       {
1576         cs.setConservation(Conservation.calculateConservation("All",
1577                 ResidueProperties.propHash, 3, alignment.getSequences(), 0,
1578                 alignment.getWidth(), false, getConsPercGaps(), false));
1579       }
1580     }
1581
1582     for (SequenceGroup sg : alignment.getGroups())
1583     {
1584       if (sg.cs != null)
1585       {
1586         sg.cs.alignmentChanged(sg, hiddenRepSequences);
1587       }
1588       sg.recalcConservation();
1589     }
1590   }
1591
1592   protected void initAutoAnnotation()
1593   {
1594     // TODO: add menu option action that nulls or creates consensus object
1595     // depending on if the user wants to see the annotation or not in a
1596     // specific alignment
1597
1598     if (hconsensus == null && !isDataset)
1599     {
1600       if (!alignment.isNucleotide())
1601       {
1602         initConservation();
1603         initQuality();
1604       }
1605       else
1606       {
1607         initRNAStructure();
1608       }
1609       initConsensus();
1610     }
1611   }
1612
1613   private void initConsensus()
1614   {
1615
1616     consensus = new AlignmentAnnotation("Consensus", "PID",
1617             new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
1618     consensus.hasText = true;
1619     consensus.autoCalculated = true;
1620
1621     if (showConsensus)
1622     {
1623       alignment.addAnnotation(consensus);
1624     }
1625   }
1626
1627   private void initConservation()
1628   {
1629     if (showConservation)
1630     {
1631       if (conservation == null)
1632       {
1633         conservation = new AlignmentAnnotation("Conservation",
1634                 "Conservation of total alignment less than "
1635                         + getConsPercGaps() + "% gaps", new Annotation[1],
1636                 0f, 11f, AlignmentAnnotation.BAR_GRAPH);
1637         conservation.hasText = true;
1638         conservation.autoCalculated = true;
1639         alignment.addAnnotation(conservation);
1640       }
1641     }
1642   }
1643
1644   private void initQuality()
1645   {
1646     if (showQuality)
1647     {
1648       if (quality == null)
1649       {
1650         quality = new AlignmentAnnotation("Quality",
1651                 "Alignment Quality based on Blosum62 scores",
1652                 new Annotation[1], 0f, 11f, AlignmentAnnotation.BAR_GRAPH);
1653         quality.hasText = true;
1654         quality.autoCalculated = true;
1655         alignment.addAnnotation(quality);
1656       }
1657     }
1658   }
1659
1660   private void initRNAStructure()
1661   {
1662     if (alignment.hasRNAStructure() && strucConsensus == null)
1663     {
1664       strucConsensus = new AlignmentAnnotation("StrucConsensus", "PID",
1665               new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
1666       strucConsensus.hasText = true;
1667       strucConsensus.autoCalculated = true;
1668
1669       if (showConsensus)
1670       {
1671         alignment.addAnnotation(strucConsensus);
1672       }
1673     }
1674   }
1675
1676   /*
1677    * (non-Javadoc)
1678    * 
1679    * @see jalview.api.AlignViewportI#calcPanelHeight()
1680    */
1681   @Override
1682   public int calcPanelHeight()
1683   {
1684     // setHeight of panels
1685     AlignmentAnnotation[] aa = getAlignment().getAlignmentAnnotation();
1686     int height = 0;
1687     int charHeight = getCharHeight();
1688     if (aa != null)
1689     {
1690       BitSet graphgrp = new BitSet();
1691       for (int i = 0; i < aa.length; i++)
1692       {
1693         if (aa[i] == null)
1694         {
1695           System.err.println("Null annotation row: ignoring.");
1696           continue;
1697         }
1698         if (!aa[i].visible)
1699         {
1700           continue;
1701         }
1702         if (aa[i].graphGroup > -1)
1703         {
1704           if (graphgrp.get(aa[i].graphGroup))
1705           {
1706             continue;
1707           }
1708           else
1709           {
1710             graphgrp.set(aa[i].graphGroup);
1711           }
1712         }
1713         aa[i].height = 0;
1714
1715         if (aa[i].hasText)
1716         {
1717           aa[i].height += charHeight;
1718         }
1719
1720         if (aa[i].hasIcons)
1721         {
1722           aa[i].height += 16;
1723         }
1724
1725         if (aa[i].graph > 0)
1726         {
1727           aa[i].height += aa[i].graphHeight;
1728         }
1729
1730         if (aa[i].height == 0)
1731         {
1732           aa[i].height = 20;
1733         }
1734
1735         height += aa[i].height;
1736       }
1737     }
1738     if (height == 0)
1739     {
1740       // set minimum
1741       height = 20;
1742     }
1743     return height;
1744   }
1745
1746   @Override
1747   public void updateGroupAnnotationSettings(boolean applyGlobalSettings,
1748           boolean preserveNewGroupSettings)
1749   {
1750     boolean updateCalcs = false;
1751     boolean conv = isShowGroupConservation();
1752     boolean cons = isShowGroupConsensus();
1753     boolean showprf = isShowSequenceLogo();
1754     boolean showConsHist = isShowConsensusHistogram();
1755     boolean normLogo = isNormaliseSequenceLogo();
1756
1757     /**
1758      * TODO reorder the annotation rows according to group/sequence ordering on
1759      * alignment
1760      */
1761     boolean sortg = true;
1762
1763     // remove old automatic annotation
1764     // add any new annotation
1765
1766     // intersect alignment annotation with alignment groups
1767
1768     AlignmentAnnotation[] aan = alignment.getAlignmentAnnotation();
1769     List<SequenceGroup> oldrfs = new ArrayList<SequenceGroup>();
1770     if (aan != null)
1771     {
1772       for (int an = 0; an < aan.length; an++)
1773       {
1774         if (aan[an].autoCalculated && aan[an].groupRef != null)
1775         {
1776           oldrfs.add(aan[an].groupRef);
1777           alignment.deleteAnnotation(aan[an], false);
1778         }
1779       }
1780     }
1781     if (alignment.getGroups() != null)
1782     {
1783       for (SequenceGroup sg : alignment.getGroups())
1784       {
1785         updateCalcs = false;
1786         if (applyGlobalSettings
1787                 || (!preserveNewGroupSettings && !oldrfs.contains(sg)))
1788         {
1789           // set defaults for this group's conservation/consensus
1790           sg.setshowSequenceLogo(showprf);
1791           sg.setShowConsensusHistogram(showConsHist);
1792           sg.setNormaliseSequenceLogo(normLogo);
1793         }
1794         if (conv)
1795         {
1796           updateCalcs = true;
1797           alignment.addAnnotation(sg.getConservationRow(), 0);
1798         }
1799         if (cons)
1800         {
1801           updateCalcs = true;
1802           alignment.addAnnotation(sg.getConsensus(), 0);
1803         }
1804         // refresh the annotation rows
1805         if (updateCalcs)
1806         {
1807           sg.recalcConservation();
1808         }
1809       }
1810     }
1811     oldrfs.clear();
1812   }
1813   @Override
1814   public boolean isDisplayReferenceSeq()
1815   {
1816     return alignment.hasSeqrep() && viewStyle.isDisplayReferenceSeq();
1817   }
1818
1819   @Override
1820   public void setDisplayReferenceSeq(boolean displayReferenceSeq)
1821   {
1822     viewStyle.setDisplayReferenceSeq(displayReferenceSeq);
1823   }
1824
1825   public boolean isColourByReferenceSeq()
1826   {
1827     return alignment.hasSeqrep() && viewStyle.isColourByReferenceSeq();
1828   }
1829
1830
1831   @Override
1832   public Color getSequenceColour(SequenceI seq)
1833   {
1834     Color sqc = Color.white;
1835     if (sequenceColours != null)
1836     {
1837       sqc = (Color) sequenceColours.get(seq);
1838       if (sqc == null)
1839       {
1840         sqc = Color.white;
1841       }
1842     }
1843     return sqc;
1844   }
1845
1846   @Override
1847   public void setSequenceColour(SequenceI seq, Color col)
1848   {
1849     if (sequenceColours == null)
1850     {
1851       sequenceColours = new Hashtable();
1852     }
1853
1854     if (col == null)
1855     {
1856       sequenceColours.remove(seq);
1857     }
1858     else
1859     {
1860       sequenceColours.put(seq, col);
1861     }
1862   }
1863
1864   @Override
1865   public void updateSequenceIdColours()
1866   {
1867     if (sequenceColours == null)
1868     {
1869       sequenceColours = new Hashtable();
1870     }
1871     for (SequenceGroup sg : alignment.getGroups())
1872     {
1873       if (sg.idColour != null)
1874       {
1875         for (SequenceI s : sg.getSequences(getHiddenRepSequences()))
1876         {
1877           sequenceColours.put(s, sg.idColour);
1878         }
1879       }
1880     }
1881   }
1882
1883   @Override
1884   public void clearSequenceColours()
1885   {
1886     sequenceColours = null;
1887   };
1888
1889   FeaturesDisplayedI featuresDisplayed = null;
1890
1891   @Override
1892   public FeaturesDisplayedI getFeaturesDisplayed()
1893   {
1894     return featuresDisplayed;
1895   }
1896
1897   @Override
1898   public void setFeaturesDisplayed(FeaturesDisplayedI featuresDisplayedI)
1899   {
1900     featuresDisplayed = featuresDisplayedI;
1901   }
1902
1903   @Override
1904   public boolean areFeaturesDisplayed()
1905   {
1906     return featuresDisplayed != null && featuresDisplayed.getRegisterdFeaturesCount()>0;
1907   }
1908
1909   /**
1910    * set the flag
1911    * 
1912    * @param b
1913    *          features are displayed if true
1914    */
1915   @Override
1916   public void setShowSequenceFeatures(boolean b)
1917   {
1918     viewStyle.setShowSequenceFeatures(b);
1919   }
1920   @Override
1921   public boolean isShowSequenceFeatures()
1922   {
1923     return viewStyle.isShowSequenceFeatures();
1924   }
1925
1926   @Override
1927   public void setShowSequenceFeaturesHeight(boolean selected)
1928   {
1929     viewStyle.setShowSeqFeaturesHeight(selected);
1930   }
1931
1932   @Override
1933   public boolean isShowSequenceFeaturesHeight()
1934   {
1935     return viewStyle.isShowSequenceFeaturesHeight();
1936   }
1937
1938
1939
1940   @Override
1941   public void setShowAnnotation(boolean b)
1942   {
1943     viewStyle.setShowAnnotation(b);
1944   }
1945
1946   @Override
1947   public boolean isShowAnnotation()
1948   {
1949     return viewStyle.isShowAnnotation();
1950   }
1951
1952   @Override
1953   public boolean isRightAlignIds()
1954   {
1955     return viewStyle.isRightAlignIds();
1956   }
1957
1958   @Override
1959   public void setRightAlignIds(boolean rightAlignIds)
1960   {
1961     viewStyle.setRightAlignIds(rightAlignIds);
1962   }
1963
1964   @Override
1965   public boolean getConservationSelected()
1966   {
1967     return viewStyle.getConservationSelected();
1968   }
1969
1970   @Override
1971   public void setShowBoxes(boolean state)
1972   {
1973     viewStyle.setShowBoxes(state);
1974   }
1975
1976   /**
1977    * @return
1978    * @see jalview.api.ViewStyleI#getTextColour()
1979    */
1980   public Color getTextColour()
1981   {
1982     return viewStyle.getTextColour();
1983   }
1984
1985   /**
1986    * @return
1987    * @see jalview.api.ViewStyleI#getTextColour2()
1988    */
1989   public Color getTextColour2()
1990   {
1991     return viewStyle.getTextColour2();
1992   }
1993
1994   /**
1995    * @return
1996    * @see jalview.api.ViewStyleI#getThresholdTextColour()
1997    */
1998   public int getThresholdTextColour()
1999   {
2000     return viewStyle.getThresholdTextColour();
2001   }
2002
2003   /**
2004    * @return
2005    * @see jalview.api.ViewStyleI#isConservationColourSelected()
2006    */
2007   public boolean isConservationColourSelected()
2008   {
2009     return viewStyle.isConservationColourSelected();
2010   }
2011
2012   /**
2013    * @return
2014    * @see jalview.api.ViewStyleI#isRenderGaps()
2015    */
2016   public boolean isRenderGaps()
2017   {
2018     return viewStyle.isRenderGaps();
2019   }
2020
2021   /**
2022    * @return
2023    * @see jalview.api.ViewStyleI#isShowColourText()
2024    */
2025   public boolean isShowColourText()
2026   {
2027     return viewStyle.isShowColourText();
2028   }
2029
2030   /**
2031    * @return
2032    * @see jalview.api.ViewStyleI#isShowSeqFeaturesHeight()
2033    */
2034   public boolean isShowSeqFeaturesHeight()
2035   {
2036     return viewStyle.isShowSeqFeaturesHeight();
2037   }
2038
2039   /**
2040    * @param conservationColourSelected
2041    * @see jalview.api.ViewStyleI#setConservationColourSelected(boolean)
2042    */
2043   public void setConservationColourSelected(
2044           boolean conservationColourSelected)
2045   {
2046     viewStyle.setConservationColourSelected(conservationColourSelected);
2047   }
2048
2049   /**
2050    * @param showColourText
2051    * @see jalview.api.ViewStyleI#setShowColourText(boolean)
2052    */
2053   public void setShowColourText(boolean showColourText)
2054   {
2055     viewStyle.setShowColourText(showColourText);
2056   }
2057
2058   /**
2059    * @param textColour
2060    * @see jalview.api.ViewStyleI#setTextColour(java.awt.Color)
2061    */
2062   public void setTextColour(Color textColour)
2063   {
2064     viewStyle.setTextColour(textColour);
2065   }
2066
2067   /**
2068    * @param thresholdTextColour
2069    * @see jalview.api.ViewStyleI#setThresholdTextColour(int)
2070    */
2071   public void setThresholdTextColour(int thresholdTextColour)
2072   {
2073     viewStyle.setThresholdTextColour(thresholdTextColour);
2074   }
2075
2076   /**
2077    * @param textColour2
2078    * @see jalview.api.ViewStyleI#setTextColour2(java.awt.Color)
2079    */
2080   public void setTextColour2(Color textColour2)
2081   {
2082     viewStyle.setTextColour2(textColour2);
2083   }
2084
2085   @Override
2086   public ViewStyleI getViewStyle()
2087   {
2088     return new ViewStyle(viewStyle);
2089   }
2090
2091   @Override
2092   public void setViewStyle(ViewStyleI settingsForView)
2093   {
2094     viewStyle = new ViewStyle(settingsForView);
2095   }
2096
2097   @Override
2098   public boolean sameStyle(ViewStyleI them)
2099   {
2100     return viewStyle.sameStyle(them);
2101   }
2102 }