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