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