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