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