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