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