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