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