382fcb6e8b2809568156463ab847531f5ba954ca
[jalview.git] / src / jalview / appletgui / AlignViewport.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 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 showDBPrefix = true;\r
40   boolean showJVSuffix = true;\r
41   boolean showText = true;\r
42   boolean showColourText = false;\r
43   boolean showBoxes = true;\r
44   boolean wrapAlignment = false;\r
45   boolean renderGaps = true;\r
46   boolean showSequenceFeatures = false;\r
47   boolean showAnnotation = true;\r
48   boolean showConservation = true;\r
49   boolean showQuality = true;\r
50   boolean showConsensus = true;\r
51 \r
52   boolean colourAppliesToAllGroups = true;\r
53   ColourSchemeI globalColourScheme = null;\r
54   boolean conservationColourSelected = false;\r
55   boolean abovePIDThreshold = false;\r
56 \r
57   SequenceGroup selectionGroup = new SequenceGroup();\r
58 \r
59   int charHeight;\r
60   int charWidth;\r
61   int wrappedWidth;\r
62 \r
63   Font font = new Font("SansSerif", Font.PLAIN, 10);\r
64   AlignmentI alignment;\r
65 \r
66   ColumnSelection colSel = new ColumnSelection();\r
67 \r
68   int threshold;\r
69   int increment;\r
70 \r
71   NJTree currentTree = null;\r
72 \r
73   boolean scaleAboveWrapped = true;\r
74   boolean scaleLeftWrapped = true;\r
75   boolean scaleRightWrapped = true;\r
76 \r
77   public Vector vconsensus;\r
78   AlignmentAnnotation consensus;\r
79   AlignmentAnnotation conservation;\r
80   AlignmentAnnotation quality;\r
81 \r
82   public int ConsPercGaps = 25; // JBPNote : This should be a scalable property!\r
83 \r
84   private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(this);\r
85 \r
86   boolean ignoreGapsInConsensusCalculation = false;\r
87 \r
88   public AlignViewport(AlignmentI al, JalviewLite applet)\r
89   {\r
90     setAlignment(al);\r
91     this.startRes = 0;\r
92     this.endRes = al.getWidth() - 1;\r
93     this.startSeq = 0;\r
94     this.endSeq = al.getHeight() - 1;\r
95     setFont(font);\r
96 \r
97     if (applet != null)\r
98     {\r
99       String param = applet.getParameter("showFullId");\r
100       if (param != null)\r
101       {\r
102         showJVSuffix = Boolean.valueOf(param).booleanValue();\r
103       }\r
104 \r
105       param = applet.getParameter("showAnnotation");\r
106       if (param != null)\r
107       {\r
108         showAnnotation = Boolean.valueOf(param).booleanValue();\r
109       }\r
110 \r
111       param = applet.getParameter("showConservation");\r
112       if (param != null)\r
113       {\r
114         showConservation = Boolean.valueOf(param).booleanValue();\r
115       }\r
116 \r
117       param = applet.getParameter("showQuality");\r
118       if (param != null)\r
119       {\r
120         showQuality = Boolean.valueOf(param).booleanValue();\r
121       }\r
122 \r
123       param = applet.getParameter("showConsensus");\r
124       if (param != null)\r
125       {\r
126         showConsensus = Boolean.valueOf(param).booleanValue();\r
127       }\r
128     }\r
129     // We must set conservation and consensus before setting colour,\r
130     // as Blosum and Clustal require this to be done\r
131     updateConservation();\r
132     updateConsensus();\r
133 \r
134     if (applet != null && applet.getParameter("defaultColour") != null)\r
135     {\r
136       globalColourScheme = ColourSchemeProperty.getColour(alignment,\r
137           applet.getParameter("defaultColour"));\r
138       if (globalColourScheme != null)\r
139       {\r
140         globalColourScheme.setConsensus(vconsensus);\r
141       }\r
142     }\r
143   }\r
144 \r
145   public void showSequenceFeatures(boolean b)\r
146   {\r
147     showSequenceFeatures = b;\r
148   }\r
149 \r
150 \r
151   public void updateConservation()\r
152   {\r
153     if(alignment.isNucleotide())\r
154           return;\r
155 \r
156     Conservation cons = new jalview.analysis.Conservation("All",\r
157         jalview.schemes.ResidueProperties.propHash, 3,\r
158         alignment.getSequences(), 0,\r
159         alignment.getWidth() - 1);\r
160     cons.calculate();\r
161     cons.verdict(false, ConsPercGaps);\r
162     cons.findQuality();\r
163     int alWidth = alignment.getWidth();\r
164     Annotation[] annotations = new Annotation[alWidth];\r
165     Annotation[] qannotations = new Annotation[alWidth];\r
166     String sequence = cons.getConsSequence().getSequence();\r
167     float minR, minG, minB, maxR, maxG, maxB;\r
168     minR = 0.3f;\r
169     minG = 0.0f;\r
170     minB = 0f;\r
171     maxR = 1.0f - minR;\r
172     maxG = 0.9f - minG;\r
173     maxB = 0f - minB; // scalable range for colouring both Conservation and Quality\r
174     float min = 0f;\r
175     float max = 11f;\r
176     float qmin = cons.qualityRange[0].floatValue();\r
177     float qmax = cons.qualityRange[1].floatValue();\r
178 \r
179     for (int i = 0; i < alWidth; i++)\r
180     {\r
181       float value = 0;\r
182       try\r
183       {\r
184         value = Integer.parseInt(sequence.charAt(i) + "");\r
185       }\r
186       catch (Exception ex)\r
187       {\r
188         if (sequence.charAt(i) == '*')\r
189         {\r
190           value = 11;\r
191         }\r
192         if (sequence.charAt(i) == '+')\r
193         {\r
194           value = 10;\r
195         }\r
196       }\r
197       float vprop = value - min;\r
198       vprop /= max;\r
199 \r
200       annotations[i] = new Annotation(sequence.charAt(i) + "",\r
201                                       "", ' ', value,\r
202                                       new Color(minR + maxR * vprop,\r
203                                                 minG + maxG * vprop,\r
204                                                 minB + maxB * vprop));\r
205       // Quality calc\r
206       value = ( (Double) cons.quality.elementAt(i)).floatValue();\r
207       vprop = value - qmin;\r
208       vprop /= qmax;\r
209       qannotations[i] = new Annotation(" ",\r
210                                        String.valueOf(value), ' ', value,\r
211                                        new\r
212                                        Color(minR + maxR * vprop,\r
213                                              minG + maxG * vprop,\r
214                                              minB + maxB * vprop));\r
215     }\r
216 \r
217     if (conservation == null)\r
218     {\r
219       conservation = new AlignmentAnnotation("Conservation",\r
220                                              "Conservation of total alignment less than " +\r
221                                              ConsPercGaps + "% gaps",\r
222                                              annotations,\r
223                                              0f, // cons.qualityRange[0].floatValue(),\r
224                                              11f, // cons.qualityRange[1].floatValue()\r
225                                              1);\r
226       if (showConservation)\r
227       {\r
228         alignment.addAnnotation(conservation);\r
229       }\r
230       quality = new AlignmentAnnotation("Quality",\r
231                                         "Alignment Quality based on Blosum62 scores",\r
232                                         qannotations,\r
233                                         cons.qualityRange[0].floatValue(),\r
234                                         cons.qualityRange[1].floatValue(),\r
235                                         1);\r
236       if (showQuality)\r
237       {\r
238         alignment.addAnnotation(quality);\r
239       }\r
240     }\r
241     else\r
242     {\r
243       conservation.annotations = annotations;\r
244       quality.annotations = qannotations;\r
245       quality.graphMax = cons.qualityRange[1].floatValue();\r
246     }\r
247 \r
248   }\r
249 \r
250   public void updateConsensus()\r
251   {\r
252     Annotation[] annotations = new Annotation[alignment.getWidth()];\r
253 \r
254     // this routine prevents vconsensus becoming a new object each time\r
255     // consenus is calculated. Important for speed of Blosum62\r
256     // and PID colouring of alignment\r
257     if (vconsensus == null)\r
258     {\r
259       vconsensus = alignment.getAAFrequency();\r
260     }\r
261     else\r
262     {\r
263       Vector temp = alignment.getAAFrequency();\r
264       vconsensus.removeAllElements();\r
265       Enumeration e = temp.elements();\r
266       while (e.hasMoreElements())\r
267       {\r
268         vconsensus.addElement(e.nextElement());\r
269       }\r
270     }\r
271     Hashtable hash = null;\r
272     for (int i = 0; i < alignment.getWidth(); i++)\r
273     {\r
274       hash = (Hashtable) vconsensus.elementAt(i);\r
275       float value = 0;\r
276       if(ignoreGapsInConsensusCalculation)\r
277         value = ((Float)hash.get("pid_nogaps")).floatValue();\r
278       else\r
279         value = ((Float)hash.get("pid_gaps")).floatValue();\r
280 \r
281       String maxRes = hash.get("maxResidue").toString();\r
282       String mouseOver = hash.get("maxResidue") + " ";\r
283       if (maxRes.length() > 1)\r
284       {\r
285         mouseOver = "[" + maxRes + "] ";\r
286         maxRes = "+";\r
287       }\r
288 \r
289 \r
290       mouseOver += (int) value + "%";\r
291       annotations[i] = new Annotation(maxRes, mouseOver, ' ', value);\r
292 \r
293     }\r
294 \r
295     if (consensus == null)\r
296     {\r
297       consensus = new AlignmentAnnotation("Consensus",\r
298                                           "PID", annotations, 0f, 100f, 1);\r
299       if (showConsensus)\r
300       {\r
301         alignment.addAnnotation(consensus);\r
302       }\r
303     }\r
304     else\r
305     {\r
306       consensus.annotations = annotations;\r
307     }\r
308 \r
309     if(globalColourScheme!=null)\r
310           globalColourScheme.setConsensus(vconsensus);\r
311 \r
312   }\r
313 \r
314   public SequenceGroup getSelectionGroup()\r
315   {\r
316     return selectionGroup;\r
317   }\r
318 \r
319   public void setSelectionGroup(SequenceGroup sg)\r
320   {\r
321     selectionGroup = sg;\r
322   }\r
323 \r
324   public boolean getConservationSelected()\r
325   {\r
326     return conservationColourSelected;\r
327   }\r
328 \r
329   public void setConservationSelected(boolean b)\r
330   {\r
331     conservationColourSelected = b;\r
332   }\r
333 \r
334   public boolean getAbovePIDThreshold()\r
335   {\r
336     return abovePIDThreshold;\r
337   }\r
338 \r
339   public void setAbovePIDThreshold(boolean b)\r
340   {\r
341     abovePIDThreshold = b;\r
342   }\r
343 \r
344   public int getStartRes()\r
345   {\r
346     return startRes;\r
347   }\r
348 \r
349   public int getEndRes()\r
350   {\r
351     return endRes;\r
352   }\r
353 \r
354   public int getStartSeq()\r
355   {\r
356     return startSeq;\r
357   }\r
358 \r
359   public void setGlobalColourScheme(ColourSchemeI cs)\r
360   {\r
361     globalColourScheme = cs;\r
362   }\r
363 \r
364   public ColourSchemeI getGlobalColourScheme()\r
365   {\r
366     return globalColourScheme;\r
367   }\r
368 \r
369   public void setStartRes(int res)\r
370   {\r
371     this.startRes = res;\r
372   }\r
373 \r
374   public void setStartSeq(int seq)\r
375   {\r
376     this.startSeq = seq;\r
377   }\r
378 \r
379   public void setEndRes(int res)\r
380   {\r
381     if (res > alignment.getWidth() - 1)\r
382     {\r
383       // log.System.out.println(" Corrected res from " + res + " to maximum " + (alignment.getWidth()-1));\r
384       res = alignment.getWidth() - 1;\r
385     }\r
386     if (res < 0)\r
387     {\r
388       res = 0;\r
389     }\r
390     this.endRes = res;\r
391   }\r
392 \r
393   public void setEndSeq(int seq)\r
394   {\r
395     if (seq > alignment.getHeight())\r
396     {\r
397       seq = alignment.getHeight();\r
398     }\r
399     if (seq < 0)\r
400     {\r
401       seq = 0;\r
402     }\r
403     this.endSeq = seq;\r
404   }\r
405 \r
406   public int getEndSeq()\r
407   {\r
408     return endSeq;\r
409   }\r
410 \r
411   public void setFont(Font f)\r
412   {\r
413     font = f;\r
414     java.awt.Frame temp = new java.awt.Frame();\r
415     temp.addNotify();\r
416     java.awt.FontMetrics fm = temp.getGraphics().getFontMetrics(font);\r
417     setCharHeight(fm.getHeight());\r
418     setCharWidth(fm.charWidth('M'));\r
419   }\r
420 \r
421   public Font getFont()\r
422   {\r
423     return font;\r
424   }\r
425 \r
426   public void setCharWidth(int w)\r
427   {\r
428     this.charWidth = w;\r
429   }\r
430 \r
431   public int getCharWidth()\r
432   {\r
433     return charWidth;\r
434   }\r
435 \r
436   public void setCharHeight(int h)\r
437   {\r
438     this.charHeight = h;\r
439   }\r
440 \r
441   public int getCharHeight()\r
442   {\r
443     return charHeight;\r
444   }\r
445 \r
446   public void setWrappedWidth(int w)\r
447   {\r
448     this.wrappedWidth = w;\r
449   }\r
450 \r
451   public int getwrappedWidth()\r
452   {\r
453     return wrappedWidth;\r
454   }\r
455 \r
456   public AlignmentI getAlignment()\r
457   {\r
458     return alignment;\r
459   }\r
460 \r
461   public void setAlignment(AlignmentI align)\r
462   {\r
463     this.alignment = align;\r
464   }\r
465 \r
466   public void setWrapAlignment(boolean state)\r
467   {\r
468     wrapAlignment = state;\r
469   }\r
470 \r
471   public void setShowText(boolean state)\r
472   {\r
473     showText = state;\r
474   }\r
475 \r
476   public void setRenderGaps(boolean state)\r
477   {\r
478     renderGaps = state;\r
479   }\r
480 \r
481   public boolean getColourText()\r
482   {\r
483     return showColourText;\r
484   }\r
485 \r
486   public void setColourText(boolean state)\r
487   {\r
488     showColourText = state;\r
489   }\r
490 \r
491   public void setShowBoxes(boolean state)\r
492   {\r
493     showBoxes = state;\r
494   }\r
495 \r
496   public boolean getWrapAlignment()\r
497   {\r
498     return wrapAlignment;\r
499   }\r
500 \r
501   public boolean getShowText()\r
502   {\r
503     return showText;\r
504   }\r
505 \r
506   public boolean getShowBoxes()\r
507   {\r
508     return showBoxes;\r
509   }\r
510 \r
511   public char getGapCharacter()\r
512   {\r
513     return getAlignment().getGapCharacter();\r
514   }\r
515 \r
516   public void setGapCharacter(char gap)\r
517   {\r
518     if (getAlignment() != null)\r
519     {\r
520       getAlignment().setGapCharacter(gap);\r
521     }\r
522   }\r
523 \r
524   public void setThreshold(int thresh)\r
525   {\r
526     threshold = thresh;\r
527   }\r
528 \r
529   public int getThreshold()\r
530   {\r
531     return threshold;\r
532   }\r
533 \r
534   public void setIncrement(int inc)\r
535   {\r
536     increment = inc;\r
537   }\r
538 \r
539   public int getIncrement()\r
540   {\r
541     return increment;\r
542   }\r
543 \r
544   public int getIndex(int y)\r
545   {\r
546     int y1 = 0;\r
547     int starty = getStartSeq();\r
548     int endy = getEndSeq();\r
549 \r
550     for (int i = starty; i <= endy; i++)\r
551     {\r
552       if (i < alignment.getHeight() && alignment.getSequenceAt(i) != null)\r
553       {\r
554         int y2 = y1 + getCharHeight();\r
555 \r
556         if (y >= y1 && y <= y2)\r
557         {\r
558           return i;\r
559         }\r
560         y1 = y2;\r
561       }\r
562       else\r
563       {\r
564         return -1;\r
565       }\r
566     }\r
567     return -1;\r
568   }\r
569 \r
570   public ColumnSelection getColumnSelection()\r
571   {\r
572     return colSel;\r
573   }\r
574 \r
575   public void resetSeqLimits(int height)\r
576   {\r
577     setEndSeq(height / getCharHeight());\r
578   }\r
579 \r
580   public void setCurrentTree(NJTree tree)\r
581   {\r
582     currentTree = tree;\r
583   }\r
584 \r
585   public NJTree getCurrentTree()\r
586   {\r
587     return currentTree;\r
588   }\r
589 \r
590   public void setColourAppliesToAllGroups(boolean b)\r
591   {\r
592     colourAppliesToAllGroups = b;\r
593   }\r
594 \r
595   public boolean getColourAppliesToAllGroups()\r
596   {\r
597     return colourAppliesToAllGroups;\r
598   }\r
599 \r
600   public boolean getShowJVSuffix()\r
601   {\r
602     return showJVSuffix;\r
603   }\r
604 \r
605   public void setShowJVSuffix(boolean b)\r
606   {\r
607     showJVSuffix = b;\r
608   }\r
609 \r
610   public boolean getShowDBPrefix()\r
611   {\r
612     return showDBPrefix;\r
613   }\r
614 \r
615   public void setShowDBPrefix(boolean b)\r
616   {\r
617     showDBPrefix = b;\r
618   }\r
619 \r
620   public boolean getShowAnnotation()\r
621   {\r
622     return showAnnotation;\r
623   }\r
624 \r
625   public void setShowAnnotation(boolean b)\r
626   {\r
627     showAnnotation = b;\r
628   }\r
629 \r
630   public boolean getScaleAboveWrapped()\r
631   {\r
632     return scaleAboveWrapped;\r
633   }\r
634 \r
635   public boolean getScaleLeftWrapped()\r
636   {\r
637     return scaleLeftWrapped;\r
638   }\r
639 \r
640   public boolean getScaleRightWrapped()\r
641   {\r
642     return scaleRightWrapped;\r
643   }\r
644 \r
645   public void setScaleAboveWrapped(boolean b)\r
646   {\r
647     scaleAboveWrapped = b;\r
648   }\r
649 \r
650   public void setScaleLeftWrapped(boolean b)\r
651   {\r
652     scaleLeftWrapped = b;\r
653   }\r
654 \r
655   public void setScaleRightWrapped(boolean b)\r
656   {\r
657     scaleRightWrapped = b;\r
658   }\r
659 \r
660   public void setIgnoreGapsConsensus(boolean b)\r
661   {\r
662     ignoreGapsInConsensusCalculation = b;\r
663     updateConsensus();\r
664     if (globalColourScheme!=null)\r
665     {\r
666       globalColourScheme.setThreshold(globalColourScheme.getThreshold(),\r
667           ignoreGapsInConsensusCalculation);\r
668 \r
669     }\r
670   }\r
671 \r
672   /**\r
673    * Property change listener for changes in alignment\r
674    *\r
675    * @param listener DOCUMENT ME!\r
676    */\r
677   public void addPropertyChangeListener(\r
678       java.beans.PropertyChangeListener listener)\r
679   {\r
680       changeSupport.addPropertyChangeListener(listener);\r
681   }\r
682 \r
683   /**\r
684    * DOCUMENT ME!\r
685    *\r
686    * @param listener DOCUMENT ME!\r
687    */\r
688   public void removePropertyChangeListener(\r
689       java.beans.PropertyChangeListener listener)\r
690   {\r
691       changeSupport.removePropertyChangeListener(listener);\r
692   }\r
693 \r
694   /**\r
695    * Property change listener for changes in alignment\r
696    *\r
697    * @param prop DOCUMENT ME!\r
698    * @param oldvalue DOCUMENT ME!\r
699    * @param newvalue DOCUMENT ME!\r
700    */\r
701   public void firePropertyChange(String prop, Object oldvalue, Object newvalue)\r
702   {\r
703       changeSupport.firePropertyChange(prop, oldvalue, newvalue);\r
704   }\r
705 \r
706 \r
707 \r
708   public boolean getIgnoreGapsConsensus()\r
709   {\r
710     return ignoreGapsInConsensusCalculation;\r
711   }\r
712 \r
713 \r
714 }\r