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