684e005de38152a03c2ef9be6e9c0f979187b786
[jalview.git] / src / jalview / appletgui / 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 package jalview.appletgui;
20
21 import java.util.*;
22
23 import java.awt.*;
24
25 import jalview.analysis.*;
26 import jalview.bin.*;
27 import jalview.datamodel.*;
28 import jalview.schemes.*;
29
30 public class AlignViewport
31 {
32   int startRes;
33
34   int endRes;
35
36   int startSeq;
37
38   int endSeq;
39
40   boolean cursorMode = false;
41
42   boolean showJVSuffix = true;
43
44   boolean showText = true;
45
46   boolean showColourText = false;
47
48   boolean showBoxes = true;
49
50   boolean wrapAlignment = false;
51
52   boolean renderGaps = true;
53
54   boolean showSequenceFeatures = false;
55
56   boolean showAnnotation = true;
57
58   boolean showConservation = true;
59
60   boolean showQuality = true;
61
62   boolean showConsensus = true;
63
64   boolean upperCasebold = false;
65
66   boolean colourAppliesToAllGroups = true;
67
68   ColourSchemeI globalColourScheme = null;
69
70   boolean conservationColourSelected = false;
71
72   boolean abovePIDThreshold = false;
73
74   SequenceGroup selectionGroup;
75
76   int charHeight;
77
78   int charWidth;
79
80   int wrappedWidth;
81
82   Font font = new Font("SansSerif", Font.PLAIN, 10);
83
84   boolean validCharWidth = true;
85
86   AlignmentI alignment;
87
88   ColumnSelection colSel = new ColumnSelection();
89
90   int threshold;
91
92   int increment;
93
94   NJTree currentTree = null;
95
96   boolean scaleAboveWrapped = true;
97
98   boolean scaleLeftWrapped = true;
99
100   boolean scaleRightWrapped = true;
101
102   // The following vector holds the features which are
103   // currently visible, in the correct order or rendering
104   public Hashtable featuresDisplayed;
105
106   boolean hasHiddenColumns = false;
107
108   boolean hasHiddenRows = false;
109
110   boolean showHiddenMarkers = true;
111
112   public Hashtable[] hconsensus;
113
114   AlignmentAnnotation consensus;
115
116   AlignmentAnnotation conservation;
117
118   AlignmentAnnotation quality;
119   AlignmentAnnotation[] groupConsensus;
120   AlignmentAnnotation[] groupConservation;
121
122   boolean autocalculateConsensus = true;
123
124   public int ConsPercGaps = 25; // JBPNote : This should be a scalable property!
125
126   private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(
127           this);
128
129   boolean ignoreGapsInConsensusCalculation = false;
130
131   jalview.bin.JalviewLite applet;
132
133   Hashtable sequenceColours;
134
135   boolean MAC = false;
136
137   Stack historyList = new Stack();
138
139   Stack redoList = new Stack();
140
141   String sequenceSetID;
142
143   Hashtable hiddenRepSequences;
144
145   public AlignViewport(AlignmentI al, JalviewLite applet)
146   {
147     this.applet = applet;
148     setAlignment(al);
149     this.startRes = 0;
150     this.endRes = al.getWidth() - 1;
151     this.startSeq = 0;
152     this.endSeq = al.getHeight() - 1;
153     setFont(font);
154
155     MAC = new jalview.util.Platform().isAMac();
156
157     if (applet != null)
158     {
159       String param = applet.getParameter("showFullId");
160       if (param != null)
161       {
162         showJVSuffix = Boolean.valueOf(param).booleanValue();
163       }
164
165       param = applet.getParameter("showAnnotation");
166       if (param != null)
167       {
168         showAnnotation = Boolean.valueOf(param).booleanValue();
169       }
170
171       param = applet.getParameter("showConservation");
172       if (param != null)
173       {
174         showConservation = Boolean.valueOf(param).booleanValue();
175       }
176
177       param = applet.getParameter("showQuality");
178       if (param != null)
179       {
180         showQuality = Boolean.valueOf(param).booleanValue();
181       }
182
183       param = applet.getParameter("showConsensus");
184       if (param != null)
185       {
186         showConsensus = Boolean.valueOf(param).booleanValue();
187       }
188
189       param = applet.getParameter("showUnconserved");
190       if (param != null)
191       {
192         this.showUnconserved = Boolean.valueOf(param).booleanValue();
193       }
194
195       param = applet.getParameter("upperCase");
196       if (param != null)
197       {
198         if (param.equalsIgnoreCase("bold"))
199         {
200           upperCasebold = true;
201         }
202       }
203       param = applet.getParameter("sortByTree");
204       if (param != null)
205       {
206         sortByTree=Boolean.valueOf(param).booleanValue();
207       }
208
209     }
210
211     if (applet != null)
212     {
213       String colour = applet.getParameter("defaultColour");
214
215       if (colour == null)
216       {
217         colour = applet.getParameter("userDefinedColour");
218         if (colour != null)
219         {
220           colour = "User Defined";
221         }
222       }
223
224       if (colour != null)
225       {
226         globalColourScheme = ColourSchemeProperty.getColour(alignment,
227                 colour);
228         if (globalColourScheme != null)
229         {
230           globalColourScheme.setConsensus(hconsensus);
231         }
232       }
233
234       if (applet.getParameter("userDefinedColour") != null)
235       {
236         ((UserColourScheme) globalColourScheme).parseAppletParameter(applet
237                 .getParameter("userDefinedColour"));
238       }
239     }
240     if (hconsensus == null)
241     {
242       if (!alignment.isNucleotide())
243       {
244         conservation = new AlignmentAnnotation("Conservation",
245                 "Conservation of total alignment less than " + ConsPercGaps
246                         + "% gaps", new Annotation[1], 0f, 11f,
247                 AlignmentAnnotation.BAR_GRAPH);
248         conservation.hasText = true;
249         conservation.autoCalculated = true;
250
251         if (showConservation)
252         {
253           alignment.addAnnotation(conservation);
254         }
255
256         if (showQuality)
257         {
258           quality = new AlignmentAnnotation("Quality",
259                   "Alignment Quality based on Blosum62 scores",
260                   new Annotation[1], 0f, 11f, AlignmentAnnotation.BAR_GRAPH);
261           quality.hasText = true;
262           quality.autoCalculated = true;
263
264           alignment.addAnnotation(quality);
265         }
266       }
267
268       consensus = new AlignmentAnnotation("Consensus", "PID",
269               new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
270       consensus.hasText = true;
271       consensus.autoCalculated = true;
272
273       if (showConsensus)
274       {
275         alignment.addAnnotation(consensus);
276       }
277     }
278
279   }
280
281   public void showSequenceFeatures(boolean b)
282   {
283     showSequenceFeatures = b;
284   }
285
286   public boolean getShowSequenceFeatures()
287   {
288     return showSequenceFeatures;
289   }
290
291   class ConservationThread extends Thread
292   {
293     AlignmentPanel ap;
294
295     public ConservationThread(AlignmentPanel ap)
296     {
297       this.ap = ap;
298     }
299
300     public void run()
301     {
302       try
303       {
304         updatingConservation = true;
305
306         while (UPDATING_CONSERVATION)
307         {
308           try
309           {
310             if (ap != null)
311             {
312               ap.paintAlignment(false);
313             }
314             Thread.sleep(200);
315           } catch (Exception ex)
316           {
317             ex.printStackTrace();
318           }
319         }
320
321         UPDATING_CONSERVATION = true;
322
323         int alWidth = alignment.getWidth();
324         if (alWidth < 0)
325         {
326           return;
327         }
328
329         Conservation cons = new jalview.analysis.Conservation("All",
330                 jalview.schemes.ResidueProperties.propHash, 3, alignment
331                         .getSequences(), 0, alWidth - 1);
332
333         cons.calculate();
334         cons.verdict(false, ConsPercGaps);
335
336         if (quality != null)
337         {
338           cons.findQuality();
339         }
340
341         char[] sequence = cons.getConsSequence().getSequence();
342         float minR;
343         float minG;
344         float minB;
345         float maxR;
346         float maxG;
347         float maxB;
348         minR = 0.3f;
349         minG = 0.0f;
350         minB = 0f;
351         maxR = 1.0f - minR;
352         maxG = 0.9f - minG;
353         maxB = 0f - minB; // scalable range for colouring both Conservation and
354                           // Quality
355
356         float min = 0f;
357         float max = 11f;
358         float qmin = 0f;
359         float qmax = 0f;
360
361         char c;
362
363         conservation.annotations = new Annotation[alWidth];
364
365         if (quality != null)
366         {
367           quality.graphMax = cons.qualityRange[1].floatValue();
368           quality.annotations = new Annotation[alWidth];
369           qmin = cons.qualityRange[0].floatValue();
370           qmax = cons.qualityRange[1].floatValue();
371         }
372
373         for (int i = 0; i < alWidth; i++)
374         {
375           float value = 0;
376
377           c = sequence[i];
378
379           if (Character.isDigit(c))
380           {
381             value = (int) (c - '0');
382           }
383           else if (c == '*')
384           {
385             value = 11;
386           }
387           else if (c == '+')
388           {
389             value = 10;
390           }
391           // TODO - refactor to use a graduatedColorScheme to calculate the histogram colors.
392           float vprop = value - min;
393           vprop /= max;
394           conservation.annotations[i] = new Annotation(String.valueOf(c),
395                   String.valueOf(value), ' ', value, new Color(minR
396                           + (maxR * vprop), minG + (maxG * vprop), minB
397                           + (maxB * vprop)));
398
399           // Quality calc
400           if (quality != null)
401           {
402             value = ((Double) cons.quality.elementAt(i)).floatValue();
403             vprop = value - qmin;
404             vprop /= qmax;
405             quality.annotations[i] = new Annotation(" ", String
406                     .valueOf(value), ' ', value, new Color(minR
407                     + (maxR * vprop), minG + (maxG * vprop), minB
408                     + (maxB * vprop)));
409           }
410         }
411       } catch (OutOfMemoryError error)
412       {
413         System.out.println("Out of memory calculating conservation!!");
414         conservation = null;
415         quality = null;
416         System.gc();
417       }
418
419       UPDATING_CONSERVATION = false;
420       updatingConservation = false;
421
422       if (ap != null)
423       {
424         ap.paintAlignment(true);
425       }
426
427     }
428   }
429
430   ConservationThread conservationThread;
431
432   ConsensusThread consensusThread;
433
434   boolean consUpdateNeeded = false;
435
436   static boolean UPDATING_CONSENSUS = false;
437
438   static boolean UPDATING_CONSERVATION = false;
439
440   boolean updatingConsensus = false;
441
442   boolean updatingConservation = false;
443
444   /**
445    * DOCUMENT ME!
446    */
447   public void updateConservation(final AlignmentPanel ap)
448   {
449     if (alignment.isNucleotide() || conservation == null)
450     {
451       return;
452     }
453
454     conservationThread = new ConservationThread(ap);
455     conservationThread.start();
456   }
457
458   /**
459    * DOCUMENT ME!
460    */
461   public void updateConsensus(final AlignmentPanel ap)
462   {
463     consensusThread = new ConsensusThread(ap);
464     consensusThread.start();
465   }
466
467   class ConsensusThread extends Thread
468   {
469     AlignmentPanel ap;
470
471     public ConsensusThread(AlignmentPanel ap)
472     {
473       this.ap = ap;
474     }
475
476     public void run()
477     {
478       updatingConsensus = true;
479       while (UPDATING_CONSENSUS)
480       {
481         try
482         {
483           if (ap != null)
484           {
485             ap.paintAlignment(false);
486           }
487
488           Thread.sleep(200);
489         } catch (Exception ex)
490         {
491           ex.printStackTrace();
492         }
493       }
494
495       UPDATING_CONSENSUS = true;
496
497       try
498       {
499         int aWidth = alignment.getWidth();
500         if (aWidth < 0)
501         {
502           return;
503         }
504
505         consensus.annotations = null;
506         consensus.annotations = new Annotation[aWidth];
507
508         hconsensus = new Hashtable[aWidth];
509         AAFrequency.calculate(alignment.getSequencesArray(), 0, alignment
510                 .getWidth(), hconsensus, includeAllConsensusSymbols);
511         AAFrequency.completeConsensus(consensus,hconsensus,0,aWidth,ignoreGapsInConsensusCalculation, includeAllConsensusSymbols);
512         
513         if (globalColourScheme != null)
514         {
515           globalColourScheme.setConsensus(hconsensus);
516         }
517
518       } catch (OutOfMemoryError error)
519       {
520         alignment.deleteAnnotation(consensus);
521
522         consensus = null;
523         hconsensus = null;
524         System.out.println("Out of memory calculating consensus!!");
525         System.gc();
526       }
527       UPDATING_CONSENSUS = false;
528       updatingConsensus = false;
529
530       if (ap != null)
531       {
532         ap.paintAlignment(true);
533       }
534     }
535   }
536
537   /**
538    * get the consensus sequence as displayed under the PID consensus annotation
539    * row.
540    * 
541    * @return consensus sequence as a new sequence object
542    */
543   public SequenceI getConsensusSeq()
544   {
545     if (consensus == null)
546     {
547       return null;
548     }
549     StringBuffer seqs = new StringBuffer();
550     for (int i = 0; i < consensus.annotations.length; i++)
551     {
552       if (consensus.annotations[i] != null)
553       {
554         if (consensus.annotations[i].description.charAt(0) == '[')
555         {
556           seqs.append(consensus.annotations[i].description.charAt(1));
557         }
558         else
559         {
560           seqs.append(consensus.annotations[i].displayCharacter);
561         }
562       }
563     }
564     SequenceI sq = new Sequence("Consensus", seqs.toString());
565     sq.setDescription("Percentage Identity Consensus "
566             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
567     return sq;
568   }
569
570   public SequenceGroup getSelectionGroup()
571   {
572     return selectionGroup;
573   }
574
575   public void setSelectionGroup(SequenceGroup sg)
576   {
577     selectionGroup = sg;
578   }
579
580   public boolean getConservationSelected()
581   {
582     return conservationColourSelected;
583   }
584
585   public void setConservationSelected(boolean b)
586   {
587     conservationColourSelected = b;
588   }
589
590   public boolean getAbovePIDThreshold()
591   {
592     return abovePIDThreshold;
593   }
594
595   public void setAbovePIDThreshold(boolean b)
596   {
597     abovePIDThreshold = b;
598   }
599
600   public int getStartRes()
601   {
602     return startRes;
603   }
604
605   public int getEndRes()
606   {
607     return endRes;
608   }
609
610   public int getStartSeq()
611   {
612     return startSeq;
613   }
614
615   public void setGlobalColourScheme(ColourSchemeI cs)
616   {
617     globalColourScheme = cs;
618   }
619
620   public ColourSchemeI getGlobalColourScheme()
621   {
622     return globalColourScheme;
623   }
624
625   public void setStartRes(int res)
626   {
627     this.startRes = res;
628   }
629
630   public void setStartSeq(int seq)
631   {
632     this.startSeq = seq;
633   }
634
635   public void setEndRes(int res)
636   {
637     if (res > alignment.getWidth() - 1)
638     {
639       // log.System.out.println(" Corrected res from " + res + " to maximum " +
640       // (alignment.getWidth()-1));
641       res = alignment.getWidth() - 1;
642     }
643     if (res < 0)
644     {
645       res = 0;
646     }
647     this.endRes = res;
648   }
649
650   public void setEndSeq(int seq)
651   {
652     if (seq > alignment.getHeight())
653     {
654       seq = alignment.getHeight();
655     }
656     if (seq < 0)
657     {
658       seq = 0;
659     }
660     this.endSeq = seq;
661   }
662
663   public int getEndSeq()
664   {
665     return endSeq;
666   }
667
668   java.awt.Frame nullFrame;
669
670   protected FeatureSettings featureSettings = null;
671
672   public void setFont(Font f)
673   {
674     font = f;
675     if (nullFrame == null)
676     {
677       nullFrame = new java.awt.Frame();
678       nullFrame.addNotify();
679     }
680
681     java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
682     setCharHeight(fm.getHeight());
683     charWidth = fm.charWidth('M');
684
685     if (upperCasebold)
686     {
687       Font f2 = new Font(f.getName(), Font.BOLD, f.getSize());
688       fm = nullFrame.getGraphics().getFontMetrics(f2);
689       charWidth = fm.stringWidth("MMMMMMMMMMM") / 10;
690     }
691   }
692
693   public Font getFont()
694   {
695     return font;
696   }
697
698   public int getCharWidth()
699   {
700     return charWidth;
701   }
702
703   public void setCharHeight(int h)
704   {
705     this.charHeight = h;
706   }
707
708   public int getCharHeight()
709   {
710     return charHeight;
711   }
712
713   public void setWrappedWidth(int w)
714   {
715     this.wrappedWidth = w;
716   }
717
718   public int getwrappedWidth()
719   {
720     return wrappedWidth;
721   }
722
723   public AlignmentI getAlignment()
724   {
725     return alignment;
726   }
727
728   public void setAlignment(AlignmentI align)
729   {
730     this.alignment = align;
731   }
732
733   public void setWrapAlignment(boolean state)
734   {
735     wrapAlignment = state;
736   }
737
738   public void setShowText(boolean state)
739   {
740     showText = state;
741   }
742
743   public void setRenderGaps(boolean state)
744   {
745     renderGaps = state;
746   }
747
748   public boolean getColourText()
749   {
750     return showColourText;
751   }
752
753   public void setColourText(boolean state)
754   {
755     showColourText = state;
756   }
757
758   public void setShowBoxes(boolean state)
759   {
760     showBoxes = state;
761   }
762
763   public boolean getWrapAlignment()
764   {
765     return wrapAlignment;
766   }
767
768   public boolean getShowText()
769   {
770     return showText;
771   }
772
773   public boolean getShowBoxes()
774   {
775     return showBoxes;
776   }
777
778   public char getGapCharacter()
779   {
780     return getAlignment().getGapCharacter();
781   }
782
783   public void setGapCharacter(char gap)
784   {
785     if (getAlignment() != null)
786     {
787       getAlignment().setGapCharacter(gap);
788     }
789   }
790
791   public void setThreshold(int thresh)
792   {
793     threshold = thresh;
794   }
795
796   public int getThreshold()
797   {
798     return threshold;
799   }
800
801   public void setIncrement(int inc)
802   {
803     increment = inc;
804   }
805
806   public int getIncrement()
807   {
808     return increment;
809   }
810
811   public void setHiddenColumns(ColumnSelection colsel)
812   {
813     this.colSel = colsel;
814     if (colSel.getHiddenColumns() != null)
815     {
816       hasHiddenColumns = true;
817     }
818   }
819
820   public ColumnSelection getColumnSelection()
821   {
822     return colSel;
823   }
824
825   public void resetSeqLimits(int height)
826   {
827     setEndSeq(height / getCharHeight());
828   }
829
830   public void setCurrentTree(NJTree tree)
831   {
832     currentTree = tree;
833   }
834
835   public NJTree getCurrentTree()
836   {
837     return currentTree;
838   }
839
840   public void setColourAppliesToAllGroups(boolean b)
841   {
842     colourAppliesToAllGroups = b;
843   }
844
845   public boolean getColourAppliesToAllGroups()
846   {
847     return colourAppliesToAllGroups;
848   }
849
850   public boolean getShowJVSuffix()
851   {
852     return showJVSuffix;
853   }
854
855   public void setShowJVSuffix(boolean b)
856   {
857     showJVSuffix = b;
858   }
859
860   public boolean getShowAnnotation()
861   {
862     return showAnnotation;
863   }
864
865   public void setShowAnnotation(boolean b)
866   {
867     showAnnotation = b;
868   }
869
870   public boolean getScaleAboveWrapped()
871   {
872     return scaleAboveWrapped;
873   }
874
875   public boolean getScaleLeftWrapped()
876   {
877     return scaleLeftWrapped;
878   }
879
880   public boolean getScaleRightWrapped()
881   {
882     return scaleRightWrapped;
883   }
884
885   public void setScaleAboveWrapped(boolean b)
886   {
887     scaleAboveWrapped = b;
888   }
889
890   public void setScaleLeftWrapped(boolean b)
891   {
892     scaleLeftWrapped = b;
893   }
894
895   public void setScaleRightWrapped(boolean b)
896   {
897     scaleRightWrapped = b;
898   }
899
900   public void setIgnoreGapsConsensus(boolean b)
901   {
902     ignoreGapsInConsensusCalculation = b;
903     updateConsensus(null);
904     if (globalColourScheme != null)
905     {
906       globalColourScheme.setThreshold(globalColourScheme.getThreshold(),
907               ignoreGapsInConsensusCalculation);
908
909     }
910   }
911
912   /**
913    * Property change listener for changes in alignment
914    * 
915    * @param listener
916    *                DOCUMENT ME!
917    */
918   public void addPropertyChangeListener(
919           java.beans.PropertyChangeListener listener)
920   {
921     changeSupport.addPropertyChangeListener(listener);
922   }
923
924   /**
925    * DOCUMENT ME!
926    * 
927    * @param listener
928    *                DOCUMENT ME!
929    */
930   public void removePropertyChangeListener(
931           java.beans.PropertyChangeListener listener)
932   {
933     changeSupport.removePropertyChangeListener(listener);
934   }
935
936   /**
937    * Property change listener for changes in alignment
938    * 
939    * @param prop
940    *                DOCUMENT ME!
941    * @param oldvalue
942    *                DOCUMENT ME!
943    * @param newvalue
944    *                DOCUMENT ME!
945    */
946   public void firePropertyChange(String prop, Object oldvalue,
947           Object newvalue)
948   {
949     changeSupport.firePropertyChange(prop, oldvalue, newvalue);
950   }
951
952   public boolean getIgnoreGapsConsensus()
953   {
954     return ignoreGapsInConsensusCalculation;
955   }
956
957   public void hideSelectedColumns()
958   {
959     if (colSel.size() < 1)
960     {
961       return;
962     }
963
964     colSel.hideSelectedColumns();
965     setSelectionGroup(null);
966
967     hasHiddenColumns = true;
968   }
969
970   public void invertColumnSelection()
971   {
972     for (int i = 0; i < alignment.getWidth(); i++)
973     {
974       if (colSel.contains(i))
975       {
976         colSel.removeElement(i);
977       }
978       else
979       {
980         if (!hasHiddenColumns || colSel.isVisible(i))
981         {
982           colSel.addElement(i);
983         }
984       }
985     }
986   }
987
988   public void hideColumns(int start, int end)
989   {
990     if (start == end)
991     {
992       colSel.hideColumns(start);
993     }
994     else
995     {
996       colSel.hideColumns(start, end);
997     }
998
999     hasHiddenColumns = true;
1000   }
1001
1002   public void hideRepSequences(SequenceI repSequence, SequenceGroup sg)
1003   {
1004     int sSize = sg.getSize();
1005     if (sSize < 2)
1006     {
1007       return;
1008     }
1009
1010     if (hiddenRepSequences == null)
1011     {
1012       hiddenRepSequences = new Hashtable();
1013     }
1014
1015     hiddenRepSequences.put(repSequence, sg);
1016
1017     // Hide all sequences except the repSequence
1018     SequenceI[] seqs = new SequenceI[sSize - 1];
1019     int index = 0;
1020     for (int i = 0; i < sSize; i++)
1021     {
1022       if (sg.getSequenceAt(i) != repSequence)
1023       {
1024         if (index == sSize - 1)
1025         {
1026           return;
1027         }
1028
1029         seqs[index++] = sg.getSequenceAt(i);
1030       }
1031     }
1032
1033     hideSequence(seqs);
1034
1035   }
1036
1037   public void hideAllSelectedSeqs()
1038   {
1039     if (selectionGroup == null || selectionGroup.getSize() < 1)
1040     {
1041       return;
1042     }
1043
1044     SequenceI[] seqs = selectionGroup.getSequencesInOrder(alignment);
1045
1046     hideSequence(seqs);
1047
1048     setSelectionGroup(null);
1049   }
1050
1051   public void hideSequence(SequenceI[] seq)
1052   {
1053     if (seq != null)
1054     {
1055       for (int i = 0; i < seq.length; i++)
1056       {
1057         alignment.getHiddenSequences().hideSequence(seq[i]);
1058       }
1059
1060       hasHiddenRows = true;
1061       firePropertyChange("alignment", null, alignment.getSequences());
1062     }
1063   }
1064
1065   public void showColumn(int col)
1066   {
1067     colSel.revealHiddenColumns(col);
1068     if (colSel.getHiddenColumns() == null)
1069     {
1070       hasHiddenColumns = false;
1071     }
1072   }
1073
1074   public void showAllHiddenColumns()
1075   {
1076     colSel.revealAllHiddenColumns();
1077     hasHiddenColumns = false;
1078   }
1079
1080   public void showAllHiddenSeqs()
1081   {
1082     if (alignment.getHiddenSequences().getSize() > 0)
1083     {
1084       if (selectionGroup == null)
1085       {
1086         selectionGroup = new SequenceGroup();
1087         selectionGroup.setEndRes(alignment.getWidth() - 1);
1088       }
1089       Vector tmp = alignment.getHiddenSequences().showAll(
1090               hiddenRepSequences);
1091       for (int t = 0; t < tmp.size(); t++)
1092       {
1093         selectionGroup.addSequence((SequenceI) tmp.elementAt(t), false);
1094       }
1095       firePropertyChange("alignment", null, alignment.getSequences());
1096       hasHiddenRows = false;
1097       hiddenRepSequences = null;
1098     }
1099   }
1100
1101   public int adjustForHiddenSeqs(int alignmentIndex)
1102   {
1103     return alignment.getHiddenSequences().adjustForHiddenSeqs(
1104             alignmentIndex);
1105   }
1106
1107   /**
1108    * This method returns the a new SequenceI [] with the selection sequence and
1109    * start and end points adjusted
1110    * 
1111    * @return String[]
1112    */
1113   public SequenceI[] getSelectionAsNewSequence()
1114   {
1115     SequenceI[] sequences;
1116
1117     if (selectionGroup == null)
1118     {
1119       sequences = alignment.getSequencesArray();
1120     }
1121     else
1122     {
1123       sequences = selectionGroup.getSelectionAsNewSequences(alignment);
1124     }
1125
1126     return sequences;
1127   }
1128
1129   /**
1130    * This method returns the visible alignment as text, as seen on the GUI, ie
1131    * if columns are hidden they will not be returned in the result. Use this for
1132    * calculating trees, PCA, redundancy etc on views which contain hidden
1133    * columns.
1134    * 
1135    * @return String[]
1136    */
1137   public jalview.datamodel.CigarArray getViewAsCigars(
1138           boolean selectedRegionOnly)
1139   {
1140     CigarArray selection = null;
1141     SequenceI[] seqs = null;
1142     int i, iSize;
1143     int start = 0, end = 0;
1144     if (selectedRegionOnly && selectionGroup != null)
1145     {
1146       iSize = selectionGroup.getSize();
1147       seqs = selectionGroup.getSequencesInOrder(alignment);
1148       start = selectionGroup.getStartRes();
1149       end = selectionGroup.getEndRes(); // inclusive for start and end in
1150                                         // SeqCigar constructor
1151     }
1152     else
1153     {
1154       iSize = alignment.getHeight();
1155       seqs = alignment.getSequencesArray();
1156       end = alignment.getWidth() - 1;
1157     }
1158     SeqCigar[] selseqs = new SeqCigar[iSize];
1159     for (i = 0; i < iSize; i++)
1160     {
1161       selseqs[i] = new SeqCigar(seqs[i], start, end);
1162     }
1163     selection = new CigarArray(selseqs);
1164     // now construct the CigarArray operations
1165     if (hasHiddenColumns)
1166     {
1167       Vector regions = colSel.getHiddenColumns();
1168       int[] region;
1169       int hideStart, hideEnd;
1170       int last = start;
1171       for (int j = 0; last < end & j < regions.size(); j++)
1172       {
1173         region = (int[]) regions.elementAt(j);
1174         hideStart = region[0];
1175         hideEnd = region[1];
1176         // edit hidden regions to selection range
1177         if (hideStart < last)
1178         {
1179           if (hideEnd > last)
1180           {
1181             hideStart = last;
1182           }
1183           else
1184           {
1185             continue;
1186           }
1187         }
1188
1189         if (hideStart > end)
1190         {
1191           break;
1192         }
1193
1194         if (hideEnd > end)
1195         {
1196           hideEnd = end;
1197         }
1198
1199         if (hideStart > hideEnd)
1200         {
1201           break;
1202         }
1203         /**
1204          * form operations...
1205          */
1206         if (last < hideStart)
1207         {
1208           selection.addOperation(CigarArray.M, hideStart - last);
1209         }
1210         selection.addOperation(CigarArray.D, 1 + hideEnd - hideStart);
1211         last = hideEnd + 1;
1212       }
1213       // Final match if necessary.
1214       if (last < end)
1215       {
1216         selection.addOperation(CigarArray.M, end - last + 1);
1217       }
1218     }
1219     else
1220     {
1221       selection.addOperation(CigarArray.M, end - start + 1);
1222     }
1223     return selection;
1224   }
1225
1226   /**
1227    * return a compact representation of the current alignment selection to pass
1228    * to an analysis function
1229    * 
1230    * @param selectedOnly
1231    *                boolean true to just return the selected view
1232    * @return AlignmentView
1233    */
1234   jalview.datamodel.AlignmentView getAlignmentView(boolean selectedOnly)
1235   {
1236     // JBPNote:
1237     // this is here because the AlignmentView constructor modifies the
1238     // CigarArray
1239     // object. Refactoring of Cigar and alignment view representation should
1240     // be done to remove redundancy.
1241     CigarArray aligview = getViewAsCigars(selectedOnly);
1242     if (aligview != null)
1243     {
1244       return new AlignmentView(aligview,
1245               (selectedOnly && selectionGroup != null) ? selectionGroup
1246                       .getStartRes() : 0);
1247     }
1248     return null;
1249   }
1250
1251   /**
1252    * This method returns the visible alignment as text, as seen on the GUI, ie
1253    * if columns are hidden they will not be returned in the result. Use this for
1254    * calculating trees, PCA, redundancy etc on views which contain hidden
1255    * columns.
1256    * 
1257    * @return String[]
1258    */
1259   public String[] getViewAsString(boolean selectedRegionOnly)
1260   {
1261     String[] selection = null;
1262     SequenceI[] seqs = null;
1263     int i, iSize;
1264     int start = 0, end = 0;
1265     if (selectedRegionOnly && selectionGroup != null)
1266     {
1267       iSize = selectionGroup.getSize();
1268       seqs = selectionGroup.getSequencesInOrder(alignment);
1269       start = selectionGroup.getStartRes();
1270       end = selectionGroup.getEndRes() + 1;
1271     }
1272     else
1273     {
1274       iSize = alignment.getHeight();
1275       seqs = alignment.getSequencesArray();
1276       end = alignment.getWidth();
1277     }
1278
1279     selection = new String[iSize];
1280
1281     for (i = 0; i < iSize; i++)
1282     {
1283       if (hasHiddenColumns)
1284       {
1285         StringBuffer visibleSeq = new StringBuffer();
1286         Vector regions = colSel.getHiddenColumns();
1287
1288         int blockStart = start, blockEnd = end;
1289         int[] region;
1290         int hideStart, hideEnd;
1291
1292         for (int j = 0; j < regions.size(); j++)
1293         {
1294           region = (int[]) regions.elementAt(j);
1295           hideStart = region[0];
1296           hideEnd = region[1];
1297
1298           if (hideStart < start)
1299           {
1300             continue;
1301           }
1302
1303           blockStart = Math.min(blockStart, hideEnd + 1);
1304           blockEnd = Math.min(blockEnd, hideStart);
1305
1306           if (blockStart > blockEnd)
1307           {
1308             break;
1309           }
1310
1311           visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd));
1312
1313           blockStart = hideEnd + 1;
1314           blockEnd = end;
1315         }
1316
1317         if (end > blockStart)
1318         {
1319           visibleSeq.append(seqs[i].getSequence(blockStart, end));
1320         }
1321
1322         selection[i] = visibleSeq.toString();
1323       }
1324       else
1325       {
1326         selection[i] = seqs[i].getSequenceAsString(start, end);
1327       }
1328     }
1329
1330     return selection;
1331   }
1332
1333   public boolean getShowHiddenMarkers()
1334   {
1335     return showHiddenMarkers;
1336   }
1337
1338   public void setShowHiddenMarkers(boolean show)
1339   {
1340     showHiddenMarkers = show;
1341   }
1342
1343   public Color getSequenceColour(SequenceI seq)
1344   {
1345     if (sequenceColours == null || !sequenceColours.containsKey(seq))
1346     {
1347       return Color.white;
1348     }
1349     else
1350     {
1351       return (Color) sequenceColours.get(seq);
1352     }
1353   }
1354
1355   public void setSequenceColour(SequenceI seq, Color col)
1356   {
1357     if (sequenceColours == null)
1358     {
1359       sequenceColours = new Hashtable();
1360     }
1361
1362     if (col == null)
1363     {
1364       sequenceColours.remove(seq);
1365     }
1366     else
1367     {
1368       sequenceColours.put(seq, col);
1369     }
1370   }
1371
1372   public String getSequenceSetId()
1373   {
1374     if (sequenceSetID == null)
1375     {
1376       sequenceSetID = alignment.hashCode() + "";
1377     }
1378
1379     return sequenceSetID;
1380   }
1381
1382   public void alignmentChanged(AlignmentPanel ap)
1383   {
1384     alignment.padGaps();
1385
1386     if (hconsensus != null && autocalculateConsensus)
1387     {
1388       updateConsensus(ap);
1389       updateConservation(ap);
1390     }
1391
1392     // Reset endRes of groups if beyond alignment width
1393     int alWidth = alignment.getWidth();
1394     Vector groups = alignment.getGroups();
1395     if (groups != null)
1396     {
1397       for (int i = 0; i < groups.size(); i++)
1398       {
1399         SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
1400         if (sg.getEndRes() > alWidth)
1401         {
1402           sg.setEndRes(alWidth - 1);
1403         }
1404       }
1405     }
1406
1407     if (selectionGroup != null && selectionGroup.getEndRes() > alWidth)
1408     {
1409       selectionGroup.setEndRes(alWidth - 1);
1410     }
1411
1412     resetAllColourSchemes();
1413
1414     // AW alignment.adjustSequenceAnnotations();
1415   }
1416
1417   void resetAllColourSchemes()
1418   {
1419     ColourSchemeI cs = globalColourScheme;
1420     if (cs != null)
1421     {
1422       if (cs instanceof ClustalxColourScheme)
1423       {
1424         ((ClustalxColourScheme) cs).resetClustalX(alignment.getSequences(),
1425                 alignment.getWidth());
1426       }
1427
1428       cs.setConsensus(hconsensus);
1429       if (cs.conservationApplied())
1430       {
1431         Alignment al = (Alignment) alignment;
1432         Conservation c = new Conservation("All",
1433                 ResidueProperties.propHash, 3, al.getSequences(), 0, al
1434                         .getWidth() - 1);
1435         c.calculate();
1436         c.verdict(false, ConsPercGaps);
1437
1438         cs.setConservation(c);
1439       }
1440     }
1441
1442     int s, sSize = alignment.getGroups().size();
1443     for (s = 0; s < sSize; s++)
1444     {
1445       SequenceGroup sg = (SequenceGroup) alignment.getGroups().elementAt(s);
1446       if (sg.cs != null && sg.cs instanceof ClustalxColourScheme)
1447       {
1448         ((ClustalxColourScheme) sg.cs).resetClustalX(sg
1449                 .getSequences(hiddenRepSequences), sg.getWidth());
1450       }
1451       sg.recalcConservation();
1452     }
1453   }
1454
1455   boolean centreColumnLabels;
1456
1457   
1458   public boolean getCentreColumnLabels()
1459   {
1460     return centreColumnLabels;
1461   }
1462
1463   public void updateSequenceIdColours()
1464   {
1465     Vector groups = alignment.getGroups();
1466     for (int ig = 0, igSize = groups.size(); ig < igSize; ig++)
1467     {
1468       SequenceGroup sg = (SequenceGroup) groups.elementAt(ig);
1469       if (sg.idColour != null)
1470       {
1471         Vector sqs = sg.getSequences(hiddenRepSequences);
1472         for (int s = 0, sSize = sqs.size(); s < sSize; s++)
1473         {
1474           this.setSequenceColour((SequenceI) sqs.elementAt(s), sg.idColour);
1475         }
1476       }
1477     }
1478   }
1479   public boolean followHighlight=false;
1480   public boolean getFollowHighlight() {
1481     return followHighlight;
1482   }
1483   /**
1484    * show non-conserved residues only
1485    */
1486   public boolean showUnconserved=false;
1487
1488   /**
1489    * when set, alignment should be reordered according to a newly opened tree
1490    */
1491   public boolean sortByTree=false;
1492
1493   /**
1494    * @return the showUnconserved
1495    */
1496   public boolean getShowunconserved()
1497   {
1498     return showUnconserved;
1499   }
1500
1501   /**
1502    * @param showUnconserved the showUnconserved to set
1503    */
1504   public void setShowunconserved(boolean displayNonconserved)
1505   {
1506     this.showUnconserved = displayNonconserved;
1507   }
1508
1509   /**
1510    * consensus annotation includes all percentage for all symbols in column
1511    * DISABLED FOR 2.5 RELEASE (bug #60064 logo rendering is not AWT 1.1 compatible)  
1512    */
1513   private boolean includeAllConsensusSymbols=false;
1514   
1515   /**
1516    * should conservation rows be shown for groups
1517    * DISABLED FOR 2.5 RELEASE (bug 62446)
1518    */
1519   boolean showGroupConservation = false;
1520   /**
1521    * should consensus rows be shown for groups
1522    * DISABLED FOR 2.5 RELEASE (bug 62446)
1523    */
1524   boolean showGroupConsensus = false;
1525   /**
1526    * should consensus profile be rendered by default
1527    * DISABLED FOR 2.5 RELEASE (bug #60064 logo rendering is not AWT 1.1 compatible)  
1528    */
1529   public boolean showSequenceLogo = false;
1530   /**
1531    * should consensus histograms be rendered by default
1532    */
1533   public boolean showConsensusHistogram = true;
1534   /**
1535    * @return the showConsensusProfile
1536    */
1537   public boolean isShowSequenceLogo()
1538   {
1539     return showSequenceLogo;
1540   }
1541   /**
1542    * @param showSequenceLogo the new value
1543   public void setShowSequenceLogo(boolean showSequenceLogo)
1544   {
1545     this.showSequenceLogo = showSequenceLogo;
1546   }
1547    */
1548   /**
1549    * @param showGroupConsensus the showGroupConsensus to set
1550    */
1551   public void setShowGroupConsensus(boolean showGroupConsensus)
1552   {
1553     this.showGroupConsensus = showGroupConsensus;
1554   }
1555   /**
1556    * @return the includeAllConsensusSymbols
1557    */
1558   public boolean isIncludeAllConsensusSymbols()
1559   {
1560     return false;
1561   }
1562   
1563   /**
1564    * 
1565    * @return flag to indicate if the consensus histogram should be rendered by default
1566    */
1567   public boolean isShowConsensusHistogram()
1568   {
1569     return this.showConsensusHistogram;
1570   }
1571 }