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