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