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