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