Formatting
[jalview.git] / src / jalview / gui / AnnotationPanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2007 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.awt.*;\r
22 import java.awt.event.*;\r
23 import java.awt.image.*;\r
24 import javax.swing.*;\r
25 \r
26 import jalview.datamodel.*;\r
27 \r
28 /**\r
29  * DOCUMENT ME!\r
30  *\r
31  * @author $author$\r
32  * @version $Revision$\r
33  */\r
34 public class AnnotationPanel\r
35     extends JPanel implements MouseListener,\r
36     MouseMotionListener, ActionListener, AdjustmentListener\r
37 {\r
38   final String HELIX = "Helix";\r
39   final String SHEET = "Sheet";\r
40   final String LABEL = "Label";\r
41   final String REMOVE = "Remove Annotation";\r
42   final String COLOUR = "Colour";\r
43   final Color HELIX_COLOUR = Color.red.darker();\r
44   final Color SHEET_COLOUR = Color.green.darker().darker();\r
45 \r
46   /** DOCUMENT ME!! */\r
47   AlignViewport av;\r
48   AlignmentPanel ap;\r
49   int activeRow = -1;\r
50   BufferedImage image;\r
51   BufferedImage fadedImage;\r
52   Graphics2D gg;\r
53   FontMetrics fm;\r
54   int imgWidth = 0;\r
55   boolean fastPaint = false;\r
56 \r
57   //Used For mouse Dragging and resizing graphs\r
58   int graphStretch = -1;\r
59   int graphStretchY = -1;\r
60   int min; //used by mouseDragged to see if user\r
61   int max; //used by mouseDragged to see if user\r
62   boolean mouseDragging = false;\r
63 \r
64   boolean MAC = false;\r
65 \r
66   /**\r
67    * Creates a new AnnotationPanel object.\r
68    *\r
69    * @param ap DOCUMENT ME!\r
70    */\r
71   public AnnotationPanel(AlignmentPanel ap)\r
72   {\r
73 \r
74     if (System.getProperty("os.name").startsWith("Mac"))\r
75     {\r
76       MAC = true;\r
77     }\r
78 \r
79     ToolTipManager.sharedInstance().registerComponent(this);\r
80     ToolTipManager.sharedInstance().setInitialDelay(0);\r
81     ToolTipManager.sharedInstance().setDismissDelay(10000);\r
82     this.ap = ap;\r
83     av = ap.av;\r
84     this.setLayout(null);\r
85     addMouseListener(this);\r
86     addMouseMotionListener(this);\r
87     ap.annotationScroller.getVerticalScrollBar().addAdjustmentListener(this);\r
88   }\r
89 \r
90   public AnnotationPanel(AlignViewport av)\r
91   {\r
92     this.av = av;\r
93   }\r
94 \r
95   /**\r
96    * DOCUMENT ME!\r
97    *\r
98    * @param evt DOCUMENT ME!\r
99    */\r
100   public void adjustmentValueChanged(AdjustmentEvent evt)\r
101   {\r
102     ap.alabels.setScrollOffset( -evt.getValue());\r
103   }\r
104 \r
105   /**\r
106    * DOCUMENT ME!\r
107    */\r
108   public int adjustPanelHeight()\r
109   {\r
110     // setHeight of panels\r
111     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
112     int height = 0;\r
113 \r
114     if (aa != null)\r
115     {\r
116       for (int i = 0; i < aa.length; i++)\r
117       {\r
118         if (!aa[i].visible)\r
119         {\r
120           continue;\r
121         }\r
122 \r
123         aa[i].height = 0;\r
124 \r
125         if (aa[i].hasText)\r
126         {\r
127           aa[i].height += av.charHeight;\r
128         }\r
129 \r
130         if (aa[i].hasIcons)\r
131         {\r
132           aa[i].height += 16;\r
133         }\r
134 \r
135         if (aa[i].graph > 0)\r
136         {\r
137           aa[i].height += aa[i].graphHeight;\r
138         }\r
139 \r
140         if (aa[i].height == 0)\r
141         {\r
142           aa[i].height = 20;\r
143         }\r
144 \r
145         height += aa[i].height;\r
146       }\r
147     }\r
148     else\r
149     {\r
150       height = 20;\r
151     }\r
152 \r
153     this.setPreferredSize(new Dimension(1, height));\r
154 \r
155     return height;\r
156   }\r
157 \r
158   /**\r
159    * DOCUMENT ME!\r
160    *\r
161    * @param evt DOCUMENT ME!\r
162    */\r
163   public void actionPerformed(ActionEvent evt)\r
164   {\r
165     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
166     Annotation[] anot = aa[activeRow].annotations;\r
167 \r
168     if (anot.length < av.getColumnSelection().getMax())\r
169     {\r
170       Annotation[] temp = new Annotation[av.getColumnSelection().getMax() + 2];\r
171       System.arraycopy(anot, 0, temp, 0, anot.length);\r
172       anot = temp;\r
173       aa[activeRow].annotations = anot;\r
174     }\r
175 \r
176     if (evt.getActionCommand().equals(REMOVE))\r
177     {\r
178       for (int i = 0; i < av.getColumnSelection().size(); i++)\r
179       {\r
180         anot[av.getColumnSelection().columnAt(i)] = null;\r
181       }\r
182     }\r
183     else if (evt.getActionCommand().equals(LABEL))\r
184     {\r
185       String label = JOptionPane.showInputDialog(this, "Enter Label ",\r
186                                                  "Enter label",\r
187                                                  JOptionPane.QUESTION_MESSAGE);\r
188 \r
189       if (label == null)\r
190       {\r
191         return;\r
192       }\r
193 \r
194       if ( (label.length() > 0) && !aa[activeRow].hasText)\r
195       {\r
196         aa[activeRow].hasText = true;\r
197       }\r
198 \r
199       for (int i = 0; i < av.getColumnSelection().size(); i++)\r
200       {\r
201         int index = av.getColumnSelection().columnAt(i);\r
202 \r
203         if (anot[index] == null)\r
204         {\r
205           anot[index] = new Annotation(label, "", ' ', 0);\r
206         }\r
207 \r
208         anot[index].displayCharacter = label;\r
209       }\r
210     }\r
211     else if (evt.getActionCommand().equals(COLOUR))\r
212     {\r
213       Color col = JColorChooser.showDialog(this,\r
214                                            "Choose foreground colour",\r
215                                            Color.black);\r
216 \r
217       for (int i = 0; i < av.getColumnSelection().size(); i++)\r
218       {\r
219         int index = av.getColumnSelection().columnAt(i);\r
220 \r
221         if (anot[index] == null)\r
222         {\r
223           anot[index] = new Annotation("", "", ' ', 0);\r
224         }\r
225 \r
226         anot[index].colour = col;\r
227       }\r
228     }\r
229     else // HELIX OR SHEET\r
230     {\r
231       char type = 0;\r
232       String symbol = "\u03B1";\r
233 \r
234       if (evt.getActionCommand().equals(HELIX))\r
235       {\r
236         type = 'H';\r
237       }\r
238       else if (evt.getActionCommand().equals(SHEET))\r
239       {\r
240         type = 'E';\r
241         symbol = "\u03B2";\r
242       }\r
243 \r
244       if (!aa[activeRow].hasIcons)\r
245       {\r
246         aa[activeRow].hasIcons = true;\r
247       }\r
248 \r
249       String label = JOptionPane.showInputDialog(\r
250           "Enter a label for the structure?",\r
251           symbol);\r
252 \r
253       if (label == null)\r
254       {\r
255         return;\r
256       }\r
257 \r
258       if ( (label.length() > 0) && !aa[activeRow].hasText)\r
259       {\r
260         aa[activeRow].hasText = true;\r
261       }\r
262 \r
263       for (int i = 0; i < av.getColumnSelection().size(); i++)\r
264       {\r
265         int index = av.getColumnSelection().columnAt(i);\r
266 \r
267         if (anot[index] == null)\r
268         {\r
269           anot[index] = new Annotation(label, "", type, 0);\r
270         }\r
271 \r
272         anot[index].secondaryStructure = type;\r
273         anot[index].displayCharacter = label;\r
274       }\r
275     }\r
276 \r
277     adjustPanelHeight();\r
278     repaint();\r
279 \r
280     return;\r
281   }\r
282 \r
283   /**\r
284    * DOCUMENT ME!\r
285    *\r
286    * @param evt DOCUMENT ME!\r
287    */\r
288   public void mousePressed(MouseEvent evt)\r
289   {\r
290 \r
291     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
292     if (aa == null)\r
293     {\r
294       return;\r
295     }\r
296 \r
297     int height = 0;\r
298     activeRow = -1;\r
299 \r
300     for (int i = 0; i < aa.length; i++)\r
301     {\r
302       if (aa[i].visible)\r
303       {\r
304         height += aa[i].height;\r
305       }\r
306 \r
307       if (evt.getY() < height)\r
308       {\r
309         if (aa[i].editable)\r
310         {\r
311           activeRow = i;\r
312         }\r
313         else if (aa[i].graph > 0)\r
314         {\r
315           //Stretch Graph\r
316           graphStretch = i;\r
317           graphStretchY = evt.getY();\r
318         }\r
319 \r
320         break;\r
321       }\r
322     }\r
323 \r
324     if (SwingUtilities.isRightMouseButton(evt) && activeRow != -1)\r
325     {\r
326       if (av.getColumnSelection() == null)\r
327       {\r
328         return;\r
329       }\r
330 \r
331       JPopupMenu pop = new JPopupMenu("Structure type");\r
332       JMenuItem item = new JMenuItem(HELIX);\r
333       item.addActionListener(this);\r
334       pop.add(item);\r
335       item = new JMenuItem(SHEET);\r
336       item.addActionListener(this);\r
337       pop.add(item);\r
338       item = new JMenuItem(LABEL);\r
339       item.addActionListener(this);\r
340       pop.add(item);\r
341       item = new JMenuItem(COLOUR);\r
342       item.addActionListener(this);\r
343       pop.add(item);\r
344       item = new JMenuItem(REMOVE);\r
345       item.addActionListener(this);\r
346       pop.add(item);\r
347       pop.show(this, evt.getX(), evt.getY());\r
348 \r
349       return;\r
350     }\r
351 \r
352     if (aa == null)\r
353     {\r
354       return;\r
355     }\r
356 \r
357     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
358 \r
359     if (av.hasHiddenColumns)\r
360     {\r
361       res = av.getColumnSelection().adjustForHiddenColumns(res);\r
362     }\r
363 \r
364     min = res;\r
365     max = res;\r
366 \r
367     if (av.getColumnSelection().contains(res))\r
368     {\r
369       av.getColumnSelection().removeElement(res);\r
370     }\r
371     else\r
372     {\r
373       av.getColumnSelection().addElement(res);\r
374       SequenceGroup sg = new SequenceGroup();\r
375 \r
376       for (int i = 0; i < av.alignment.getSequences().size(); i++)\r
377       {\r
378         sg.addSequence(av.alignment.getSequenceAt(i), false);\r
379       }\r
380 \r
381       sg.setStartRes(res);\r
382       sg.setEndRes(res);\r
383       av.setSelectionGroup(sg);\r
384     }\r
385 \r
386     ap.repaint();\r
387 \r
388   }\r
389 \r
390   /**\r
391    * DOCUMENT ME!\r
392    *\r
393    * @param evt DOCUMENT ME!\r
394    */\r
395   public void mouseReleased(MouseEvent evt)\r
396   {\r
397     graphStretch = -1;\r
398     graphStretchY = -1;\r
399     mouseDragging = false;\r
400   }\r
401 \r
402   /**\r
403    * DOCUMENT ME!\r
404    *\r
405    * @param evt DOCUMENT ME!\r
406    */\r
407   public void mouseEntered(MouseEvent evt)\r
408   {\r
409     if (mouseDragging)\r
410     {\r
411       ap.seqPanel.scrollCanvas(null);\r
412     }\r
413   }\r
414 \r
415   /**\r
416    * DOCUMENT ME!\r
417    *\r
418    * @param evt DOCUMENT ME!\r
419    */\r
420   public void mouseExited(MouseEvent evt)\r
421   {\r
422     if (mouseDragging)\r
423     {\r
424       ap.seqPanel.scrollCanvas(evt);\r
425     }\r
426   }\r
427 \r
428   /**\r
429    * DOCUMENT ME!\r
430    *\r
431    * @param evt DOCUMENT ME!\r
432    */\r
433   public void mouseDragged(MouseEvent evt)\r
434   {\r
435     if (graphStretch > -1)\r
436     {\r
437       av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight +=\r
438           graphStretchY - evt.getY();\r
439       if (av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight < 0)\r
440       {\r
441         av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight = 0;\r
442       }\r
443       graphStretchY = evt.getY();\r
444       adjustPanelHeight();\r
445       ap.repaint();\r
446     }\r
447     else\r
448     {\r
449       mouseDragging = true;\r
450 \r
451       int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
452 \r
453       if (av.hasHiddenColumns)\r
454       {\r
455         res = av.getColumnSelection().adjustForHiddenColumns(res);\r
456       }\r
457 \r
458       SequenceGroup sg = av.getSelectionGroup();\r
459 \r
460       if (res < min)\r
461       {\r
462         min = res;\r
463       }\r
464 \r
465       if (res > max)\r
466       {\r
467         max = res;\r
468       }\r
469 \r
470       if (sg != null)\r
471       {\r
472         if (!av.getColumnSelection().contains(res))\r
473         {\r
474           av.getColumnSelection().addElement(res);\r
475         }\r
476 \r
477         if (res > sg.getStartRes())\r
478         {\r
479           sg.setEndRes(res);\r
480         }\r
481         else if (res < sg.getStartRes())\r
482         {\r
483           sg.setStartRes(res);\r
484         }\r
485 \r
486         for (int i = min; i <= max; i++)\r
487         {\r
488           if ( (i < sg.getStartRes()) || (i > sg.getEndRes()))\r
489           {\r
490             av.getColumnSelection().removeElement(i);\r
491           }\r
492           else\r
493           {\r
494             av.getColumnSelection().addElement(i);\r
495           }\r
496         }\r
497 \r
498         ap.repaint();\r
499       }\r
500 \r
501     }\r
502   }\r
503 \r
504   /**\r
505    * DOCUMENT ME!\r
506    *\r
507    * @param evt DOCUMENT ME!\r
508    */\r
509   public void mouseMoved(MouseEvent evt)\r
510   {\r
511     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
512 \r
513     if (aa == null)\r
514     {\r
515       this.setToolTipText(null);\r
516       return;\r
517     }\r
518 \r
519     int row = -1;\r
520     int height = 0;\r
521 \r
522     for (int i = 0; i < aa.length; i++)\r
523     {\r
524       if (aa[i].visible)\r
525       {\r
526         height += aa[i].height;\r
527       }\r
528 \r
529       if (evt.getY() < height)\r
530       {\r
531         row = i;\r
532 \r
533         break;\r
534       }\r
535     }\r
536 \r
537     if (row == -1)\r
538     {\r
539       this.setToolTipText(null);\r
540       return;\r
541     }\r
542 \r
543     int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
544 \r
545     if (av.hasHiddenColumns)\r
546     {\r
547       res = av.getColumnSelection().adjustForHiddenColumns(res);\r
548     }\r
549 \r
550     if (aa[row].annotations != null\r
551         && row > -1\r
552         && res < (int) aa[row].annotations.length)\r
553     {\r
554       if (aa[row].graphGroup > -1)\r
555       {\r
556         StringBuffer tip = new StringBuffer("<html>");\r
557         for (int gg = 0; gg < aa.length; gg++)\r
558         {\r
559           if (aa[gg].graphGroup == aa[row].graphGroup && aa[gg].annotations[res] != null)\r
560           {\r
561             tip.append(aa[gg].label + " " + aa[gg].annotations[res].description +\r
562                        "<br>");\r
563           }\r
564         }\r
565         if (tip.length() != 6)\r
566         {\r
567           tip.setLength(tip.length() - 4);\r
568           this.setToolTipText(tip.toString() + "</html>");\r
569         }\r
570       }\r
571       else if (aa[row].annotations[res] != null\r
572                && aa[row].annotations[res].description != null)\r
573       {\r
574         this.setToolTipText(aa[row].annotations[res].description);\r
575       }\r
576 \r
577       if (aa[row].annotations[res] != null)\r
578       {\r
579         StringBuffer text = new StringBuffer("Sequence position " +\r
580                                              (res + 1));\r
581 \r
582         if (aa[row].annotations[res].description != null)\r
583         {\r
584           text.append("  " + aa[row].annotations[res].description);\r
585         }\r
586 \r
587         ap.alignFrame.statusBar.setText(text.toString());\r
588       }\r
589     }\r
590     else\r
591     {\r
592       this.setToolTipText(null);\r
593     }\r
594   }\r
595 \r
596   /**\r
597    * DOCUMENT ME!\r
598    *\r
599    * @param evt DOCUMENT ME!\r
600    */\r
601   public void mouseClicked(MouseEvent evt)\r
602   {\r
603   }\r
604 \r
605   /**\r
606    * DOCUMENT ME!\r
607    *\r
608    * @param g DOCUMENT ME!\r
609    */\r
610   public void paintComponent(Graphics g)\r
611   {\r
612     g.setColor(Color.white);\r
613     g.fillRect(0, 0, getWidth(), getHeight());\r
614 \r
615     if (image != null)\r
616     {\r
617       if (fastPaint\r
618           || (getVisibleRect().width != g.getClipBounds().width)\r
619           || (getVisibleRect().height != g.getClipBounds().height))\r
620       {\r
621         g.drawImage(image, 0, 0, this);\r
622         fastPaint = false;\r
623         return;\r
624       }\r
625     }\r
626     imgWidth = (av.endRes - av.startRes + 1) * av.charWidth;\r
627 \r
628     if (image == null || imgWidth != image.getWidth()\r
629         || image.getHeight(this) != getHeight())\r
630     {\r
631       image = new BufferedImage(imgWidth, ap.annotationPanel.getHeight(),\r
632                                 BufferedImage.TYPE_INT_RGB);\r
633       gg = (Graphics2D) image.getGraphics();\r
634 \r
635       if (av.antiAlias)\r
636       {\r
637         gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
638                             RenderingHints.VALUE_ANTIALIAS_ON);\r
639       }\r
640 \r
641       gg.setFont(av.getFont());\r
642       fm = gg.getFontMetrics();\r
643       gg.setColor(Color.white);\r
644       gg.fillRect(0, 0, imgWidth, image.getHeight());\r
645     }\r
646 \r
647     drawComponent(gg, av.startRes, av.endRes + 1);\r
648     g.drawImage(image, 0, 0, this);\r
649   }\r
650 \r
651   /**\r
652    * DOCUMENT ME!\r
653    *\r
654    * @param horizontal DOCUMENT ME!\r
655    */\r
656   public void fastPaint(int horizontal)\r
657   {\r
658     if ( (horizontal == 0)\r
659         || gg == null\r
660         || av.alignment.getAlignmentAnnotation() == null\r
661         || av.alignment.getAlignmentAnnotation().length < 1\r
662         || av.updatingConsensus\r
663         || av.updatingConservation)\r
664     {\r
665       repaint();\r
666       return;\r
667     }\r
668 \r
669     gg.copyArea(0, 0, imgWidth, getHeight(), -horizontal * av.charWidth, 0);\r
670 \r
671     int sr = av.startRes;\r
672     int er = av.endRes + 1;\r
673     int transX = 0;\r
674 \r
675     if (horizontal > 0) // scrollbar pulled right, image to the left\r
676     {\r
677       transX = (er - sr - horizontal) * av.charWidth;\r
678       sr = er - horizontal;\r
679     }\r
680     else if (horizontal < 0)\r
681     {\r
682       er = sr - horizontal;\r
683     }\r
684 \r
685     gg.translate(transX, 0);\r
686 \r
687     drawComponent(gg, sr, er);\r
688 \r
689     gg.translate( -transX, 0);\r
690 \r
691     fastPaint = true;\r
692 \r
693     repaint();\r
694 \r
695   }\r
696 \r
697   /**\r
698    * DOCUMENT ME!\r
699    *\r
700    * @param g DOCUMENT ME!\r
701    * @param startRes DOCUMENT ME!\r
702    * @param endRes DOCUMENT ME!\r
703    */\r
704   public void drawComponent(Graphics g, int startRes, int endRes)\r
705   {\r
706     if (av.updatingConsensus || av.updatingConservation)\r
707     {\r
708       if (image == null)\r
709       {\r
710         return;\r
711       }\r
712       //We'll keep a record of the old image,\r
713       //and draw a faded image until the calculation\r
714       //has completed\r
715       if (fadedImage == null\r
716           || fadedImage.getWidth() != imgWidth\r
717           || fadedImage.getHeight() != image.getHeight())\r
718       {\r
719         fadedImage = new BufferedImage(\r
720             imgWidth, image.getHeight(),\r
721             BufferedImage.TYPE_INT_RGB);\r
722 \r
723         Graphics2D fadedG = (Graphics2D) fadedImage.getGraphics();\r
724 \r
725         fadedG.setColor(Color.white);\r
726         fadedG.fillRect(0, 0, imgWidth, image.getHeight());\r
727 \r
728         fadedG.setComposite(\r
729             AlphaComposite.getInstance(\r
730                 AlphaComposite.SRC_OVER, .3f));\r
731         fadedG.drawImage(image, 0, 0, this);\r
732 \r
733       }\r
734 \r
735     }\r
736     else\r
737     {\r
738       fadedImage = null;\r
739     }\r
740 \r
741     g.setColor(Color.white);\r
742     g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getHeight());\r
743 \r
744     g.setFont(av.getFont());\r
745     if (fm == null)\r
746     {\r
747       fm = g.getFontMetrics();\r
748     }\r
749 \r
750     if ( (av.alignment.getAlignmentAnnotation() == null) ||\r
751         (av.alignment.getAlignmentAnnotation().length < 1))\r
752     {\r
753       g.setColor(Color.white);\r
754       g.fillRect(0, 0, getWidth(), getHeight());\r
755       g.setColor(Color.black);\r
756       if (av.validCharWidth)\r
757       {\r
758         g.drawString("Alignment has no annotations", 20, 15);\r
759       }\r
760 \r
761       return;\r
762     }\r
763 \r
764     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
765 \r
766     int x = 0, y = 0;\r
767     int column = 0;\r
768     char lastSS;\r
769     int lastSSX;\r
770     int iconOffset = av.charHeight / 2;\r
771     boolean validRes = false;\r
772 \r
773     boolean[] graphGroupDrawn = new boolean[aa.length];\r
774 \r
775     //\u03B2 \u03B1\r
776     for (int i = 0; i < aa.length; i++)\r
777     {\r
778       AlignmentAnnotation row = aa[i];\r
779 \r
780       if (!row.visible)\r
781       {\r
782         continue;\r
783       }\r
784 \r
785       lastSS = ' ';\r
786       lastSSX = 0;\r
787 \r
788       if (row.graph > 0)\r
789       {\r
790         if (row.graphGroup > -1 && graphGroupDrawn[row.graphGroup])\r
791         {\r
792           continue;\r
793         }\r
794 \r
795         // this is so that we draw the characters below the graph\r
796         y += row.height;\r
797 \r
798         if (row.hasText)\r
799         {\r
800           y -= av.charHeight;\r
801         }\r
802       }\r
803 \r
804       if (av.updatingConsensus && aa[i] == av.consensus)\r
805       {\r
806         y += av.charHeight;\r
807 \r
808         g.drawImage(fadedImage,\r
809                     0, y - row.height, imgWidth, y,\r
810                     0, y - row.height, imgWidth, y, this);\r
811         g.setColor(Color.black);\r
812         // g.drawString("Calculating Consensus....",20, y-row.height/2);\r
813 \r
814         continue;\r
815       }\r
816       else if (av.updatingConservation && aa[i].label.equals("Conservation"))\r
817       {\r
818 \r
819         y += av.charHeight;\r
820         g.drawImage(fadedImage,\r
821                     0, y - row.height, imgWidth, y,\r
822                     0, y - row.height, imgWidth, y, this);\r
823 \r
824         g.setColor(Color.black);\r
825         //  g.drawString("Calculating Conservation.....",20, y-row.height/2);\r
826 \r
827         continue;\r
828       }\r
829       else if (av.updatingConservation && aa[i].label.equals("Quality"))\r
830       {\r
831 \r
832         y += av.charHeight;\r
833         g.drawImage(fadedImage,\r
834                     0, y - row.height, imgWidth, y,\r
835                     0, y - row.height, imgWidth, y, this);\r
836         g.setColor(Color.black);\r
837         /// g.drawString("Calculating Quality....",20, y-row.height/2);\r
838 \r
839         continue;\r
840       }\r
841 \r
842       if (row.hasText)\r
843       {\r
844         iconOffset = av.charHeight / 2 + 4;\r
845       }\r
846       else\r
847       {\r
848         iconOffset = 0;\r
849       }\r
850 \r
851       x = 0;\r
852       while (x < endRes - startRes)\r
853       {\r
854         if (av.hasHiddenColumns)\r
855         {\r
856           column = av.getColumnSelection().adjustForHiddenColumns(startRes + x);\r
857           if (column > row.annotations.length - 1)\r
858           {\r
859             break;\r
860           }\r
861         }\r
862         else\r
863         {\r
864           column = startRes + x;\r
865         }\r
866 \r
867         if ( (row.annotations.length <= column) ||\r
868             (row.annotations[column] == null))\r
869         {\r
870           validRes = false;\r
871         }\r
872         else\r
873         {\r
874           validRes = true;\r
875         }\r
876 \r
877         if (activeRow == i)\r
878         {\r
879           g.setColor(Color.red);\r
880 \r
881           if (av.getColumnSelection() != null)\r
882           {\r
883             for (int n = 0; n < av.getColumnSelection().size(); n++)\r
884             {\r
885               int v = av.getColumnSelection().columnAt(n);\r
886 \r
887               if (v == column)\r
888               {\r
889                 g.fillRect(x * av.charWidth, y,\r
890                            av.charWidth, av.charHeight);\r
891               }\r
892             }\r
893           }\r
894         }\r
895 \r
896         if (av.validCharWidth && validRes &&\r
897             (row.annotations[column].displayCharacter.length() > 0))\r
898         {\r
899 \r
900           int charOffset = (av.charWidth -\r
901                             fm.charWidth(row.annotations[column].\r
902                                          displayCharacter.charAt(\r
903                                              0))) / 2;\r
904           g.setColor(row.annotations[column].colour);\r
905 \r
906           if (column == 0 || row.graph > 0)\r
907           {\r
908             g.drawString(row.annotations[column].displayCharacter,\r
909                          (x * av.charWidth) + charOffset,\r
910                          y + iconOffset);\r
911           }\r
912           else if (\r
913               row.annotations[column - 1] == null\r
914               || (!row.annotations[column].displayCharacter.equals(\r
915                   row.annotations[column - 1].displayCharacter)\r
916                   ||\r
917                   (row.annotations[column].displayCharacter.length() < 2 &&\r
918                    row.annotations[column].secondaryStructure == ' ')))\r
919           {\r
920             g.drawString(row.annotations[column].displayCharacter,\r
921                          x * av.charWidth + charOffset,\r
922                          y + iconOffset);\r
923           }\r
924         }\r
925 \r
926         if (row.hasIcons)\r
927         {\r
928           if (!validRes ||\r
929               (row.annotations[column].secondaryStructure != lastSS))\r
930           {\r
931             switch (lastSS)\r
932             {\r
933               case 'H':\r
934                 g.setColor(HELIX_COLOUR);\r
935                 if (MAC)\r
936                 {\r
937                   //Off by 1 offset when drawing rects and ovals\r
938                   //to offscreen image on the MAC\r
939                   g.fillRoundRect(lastSSX, y + 4 + iconOffset,\r
940                                   (x * av.charWidth) - lastSSX, 7, 8, 8);\r
941                   break;\r
942                 }\r
943 \r
944                 int sCol = (lastSSX / av.charWidth) + startRes;\r
945                 int x1 = lastSSX;\r
946                 int x2 = (x * av.charWidth);\r
947 \r
948                 if (sCol == 0 ||\r
949                     row.annotations[sCol - 1] == null ||\r
950                     row.annotations[sCol - 1].secondaryStructure != 'H')\r
951                 {\r
952                   g.fillArc(lastSSX, y + 4 + iconOffset, av.charWidth, 8, 90,\r
953                             180);\r
954                   x1 += av.charWidth / 2;\r
955                 }\r
956 \r
957                 if (row.annotations[column] == null ||\r
958                     row.annotations[column].secondaryStructure != 'H')\r
959                 {\r
960                   g.fillArc( (x * av.charWidth) - av.charWidth,\r
961                             y + 4 + iconOffset, av.charWidth, 8, 270, 180);\r
962                   x2 -= av.charWidth / 2;\r
963                 }\r
964 \r
965                 g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);\r
966                 break;\r
967 \r
968               case 'E':\r
969                 g.setColor(SHEET_COLOUR);\r
970                 g.fillRect(lastSSX, y + 4 + iconOffset,\r
971                            (x * av.charWidth) - lastSSX - 4, 7);\r
972                 g.fillPolygon(new int[]\r
973                               { (x * av.charWidth) - 4,\r
974                               (x * av.charWidth) - 4,\r
975                               (x * av.charWidth)},\r
976                               new int[]\r
977                               {\r
978                               y + iconOffset, y + 14 + iconOffset,\r
979                               y + 8 + iconOffset\r
980                 }, 3);\r
981 \r
982                 break;\r
983 \r
984               default:\r
985                 g.setColor(Color.gray);\r
986                 g.fillRect(lastSSX, y + 6 + iconOffset,\r
987                            (x * av.charWidth) - lastSSX, 2);\r
988 \r
989                 break;\r
990             }\r
991 \r
992             if (validRes)\r
993             {\r
994               lastSS = row.annotations[column].secondaryStructure;\r
995             }\r
996             else\r
997             {\r
998               lastSS = ' ';\r
999             }\r
1000 \r
1001             lastSSX = (x * av.charWidth);\r
1002           }\r
1003         }\r
1004 \r
1005         column++;\r
1006         x++;\r
1007       }\r
1008 \r
1009       if (column >= row.annotations.length)\r
1010       {\r
1011         column = row.annotations.length - 1;\r
1012       }\r
1013 \r
1014       //  x ++;\r
1015 \r
1016       if (row.hasIcons)\r
1017       {\r
1018         switch (lastSS)\r
1019         {\r
1020           case 'H':\r
1021             g.setColor(HELIX_COLOUR);\r
1022             if (MAC)\r
1023             {\r
1024               //Off by 1 offset when drawing rects and ovals\r
1025               //to offscreen image on the MAC\r
1026               g.fillRoundRect(lastSSX, y + 4 + iconOffset,\r
1027                               (x * av.charWidth) - lastSSX, 7, 8, 8);\r
1028               break;\r
1029             }\r
1030 \r
1031             int sCol = (lastSSX / av.charWidth) + startRes;\r
1032             int x1 = lastSSX;\r
1033             int x2 = (x * av.charWidth);\r
1034 \r
1035             if (sCol == 0 ||\r
1036                 row.annotations[sCol - 1] == null ||\r
1037                 row.annotations[sCol - 1].secondaryStructure != 'H')\r
1038             {\r
1039               g.fillArc(lastSSX, y + 4 + iconOffset, av.charWidth, 8, 90, 180);\r
1040               x1 += av.charWidth / 2;\r
1041             }\r
1042 \r
1043             if (row.annotations[column] == null ||\r
1044                 row.annotations[column].secondaryStructure != 'H')\r
1045             {\r
1046               g.fillArc( (x * av.charWidth) - av.charWidth,\r
1047                         y + 4 + iconOffset, av.charWidth, 8, 270,\r
1048                         180);\r
1049               x2 -= av.charWidth / 2;\r
1050             }\r
1051 \r
1052             g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);\r
1053 \r
1054             break;\r
1055 \r
1056           case 'E':\r
1057             g.setColor(SHEET_COLOUR);\r
1058 \r
1059             if (row.annotations[endRes] == null\r
1060                 || row.annotations[endRes].secondaryStructure != 'E')\r
1061             {\r
1062               g.fillRect(lastSSX, y + 4 + iconOffset,\r
1063                          (x * av.charWidth) - lastSSX - 4, 7);\r
1064               g.fillPolygon(new int[]\r
1065                             { (x * av.charWidth) - 4,\r
1066                             (x * av.charWidth) - 4,\r
1067                             (x * av.charWidth)},\r
1068                             new int[]\r
1069                             {\r
1070                             y + iconOffset, y + 14 + iconOffset,\r
1071                             y + 7 + iconOffset\r
1072               }, 3);\r
1073             }\r
1074             else\r
1075             {\r
1076               g.fillRect(lastSSX, y + 4 + iconOffset,\r
1077                          (x + 1) * av.charWidth - lastSSX, 7);\r
1078             }\r
1079             break;\r
1080 \r
1081           default:\r
1082             g.setColor(Color.gray);\r
1083             g.fillRect(lastSSX, y + 6 + iconOffset,\r
1084                        (x * av.charWidth) - lastSSX, 2);\r
1085 \r
1086             break;\r
1087         }\r
1088       }\r
1089 \r
1090       if (row.graph > 0 && row.graphHeight > 0)\r
1091       {\r
1092         if (row.graph == AlignmentAnnotation.LINE_GRAPH)\r
1093         {\r
1094           if (row.graphGroup > -1 && !graphGroupDrawn[row.graphGroup])\r
1095           {\r
1096             float groupmax = -999999, groupmin = 9999999;\r
1097             for (int gg = 0; gg < aa.length; gg++)\r
1098             {\r
1099               if (aa[gg].graphGroup != row.graphGroup)\r
1100               {\r
1101                 continue;\r
1102               }\r
1103 \r
1104               if (aa[gg] != row)\r
1105               {\r
1106                 aa[gg].visible = false;\r
1107               }\r
1108 \r
1109               if (aa[gg].graphMax > groupmax)\r
1110               {\r
1111                 groupmax = aa[gg].graphMax;\r
1112               }\r
1113               if (aa[gg].graphMin < groupmin)\r
1114               {\r
1115                 groupmin = aa[gg].graphMin;\r
1116               }\r
1117             }\r
1118 \r
1119             for (int gg = 0; gg < aa.length; gg++)\r
1120             {\r
1121               if (aa[gg].graphGroup == row.graphGroup)\r
1122               {\r
1123                 drawLineGraph(g, aa[gg], startRes, endRes, y,\r
1124                               groupmin, groupmax,\r
1125                               row.graphHeight);\r
1126               }\r
1127             }\r
1128 \r
1129             graphGroupDrawn[row.graphGroup] = true;\r
1130           }\r
1131           else\r
1132           {\r
1133             drawLineGraph(g, row, startRes, endRes,\r
1134                           y, row.graphMin, row.graphMax, row.graphHeight);\r
1135           }\r
1136         }\r
1137         else if (row.graph == AlignmentAnnotation.BAR_GRAPH)\r
1138         {\r
1139           drawBarGraph(g, row, startRes, endRes,\r
1140                        row.graphMin, row.graphMax, y);\r
1141         }\r
1142       }\r
1143 \r
1144       if (row.graph > 0 && row.hasText)\r
1145       {\r
1146         y += av.charHeight;\r
1147       }\r
1148 \r
1149       if (row.graph == 0)\r
1150       {\r
1151         y += aa[i].height;\r
1152       }\r
1153     }\r
1154   }\r
1155 \r
1156   public void drawLineGraph(Graphics g, AlignmentAnnotation aa,\r
1157                             int sRes, int eRes,\r
1158                             int y,\r
1159                             float min, float max,\r
1160                             int graphHeight)\r
1161   {\r
1162     if (sRes > aa.annotations.length)\r
1163     {\r
1164       return;\r
1165     }\r
1166 \r
1167     int x = 0;\r
1168 \r
1169     //Adjustment for fastpaint to left\r
1170     if (eRes < av.endRes)\r
1171     {\r
1172       eRes++;\r
1173     }\r
1174 \r
1175     eRes = Math.min(eRes, aa.annotations.length);\r
1176 \r
1177     if (sRes == 0)\r
1178     {\r
1179       x++;\r
1180     }\r
1181 \r
1182     int y1 = y, y2 = y;\r
1183     float range = max - min;\r
1184 \r
1185     ////Draw origin\r
1186     if (min < 0)\r
1187     {\r
1188       y2 = y - (int) ( (0 - min / range) * graphHeight);\r
1189     }\r
1190 \r
1191     g.setColor(Color.gray);\r
1192     g.drawLine(x - av.charWidth, y2, (eRes - sRes + 1) * av.charWidth, y2);\r
1193 \r
1194     eRes = Math.min(eRes, aa.annotations.length);\r
1195 \r
1196     int column;\r
1197     int aaMax = aa.annotations.length - 1;\r
1198 \r
1199     while (x < eRes - sRes)\r
1200     {\r
1201       column = sRes + x;\r
1202       if (av.hasHiddenColumns)\r
1203       {\r
1204         column = av.getColumnSelection().adjustForHiddenColumns(column);\r
1205       }\r
1206 \r
1207       if (column > aaMax)\r
1208       {\r
1209         break;\r
1210       }\r
1211 \r
1212       if (aa.annotations[column] == null || aa.annotations[column - 1] == null)\r
1213       {\r
1214         x++;\r
1215         continue;\r
1216       }\r
1217 \r
1218       g.setColor(aa.annotations[column].colour);\r
1219       y1 = y -\r
1220           (int) ( ( (aa.annotations[column - 1].value - min) / range) * graphHeight);\r
1221       y2 = y -\r
1222           (int) ( ( (aa.annotations[column].value - min) / range) * graphHeight);\r
1223 \r
1224       g.drawLine(x * av.charWidth - av.charWidth / 2, y1,\r
1225                  x * av.charWidth + av.charWidth / 2, y2);\r
1226       x++;\r
1227     }\r
1228 \r
1229     if (aa.threshold != null)\r
1230     {\r
1231       g.setColor(aa.threshold.colour);\r
1232       Graphics2D g2 = (Graphics2D) g;\r
1233       g2.setStroke(new BasicStroke(1,\r
1234                                    BasicStroke.CAP_SQUARE,\r
1235                                    BasicStroke.JOIN_ROUND, 3f,\r
1236                                    new float[]\r
1237                                    {5f, 3f}, 0f));\r
1238 \r
1239       y2 = (int) (y - ( (aa.threshold.value - min) / range) * graphHeight);\r
1240       g.drawLine(0, y2, (eRes - sRes) * av.charWidth, y2);\r
1241       g2.setStroke(new BasicStroke());\r
1242     }\r
1243   }\r
1244 \r
1245   public void drawBarGraph(Graphics g, AlignmentAnnotation aa,\r
1246                            int sRes, int eRes,\r
1247                            float min, float max,\r
1248                            int y)\r
1249   {\r
1250     if (sRes > aa.annotations.length)\r
1251     {\r
1252       return;\r
1253     }\r
1254 \r
1255     eRes = Math.min(eRes, aa.annotations.length);\r
1256 \r
1257     int x = 0, y1 = y, y2 = y;\r
1258 \r
1259     float range = max - min;\r
1260 \r
1261     if (min < 0)\r
1262     {\r
1263       y2 = y - (int) ( (0 - min / (range)) * aa.graphHeight);\r
1264     }\r
1265 \r
1266     g.setColor(Color.gray);\r
1267 \r
1268     g.drawLine(x, y2, (eRes - sRes) * av.charWidth, y2);\r
1269 \r
1270     int column;\r
1271     int aaMax = aa.annotations.length - 1;\r
1272 \r
1273     while (x < eRes - sRes)\r
1274     {\r
1275       column = sRes + x;\r
1276       if (av.hasHiddenColumns)\r
1277       {\r
1278         column = av.getColumnSelection().adjustForHiddenColumns(column);\r
1279       }\r
1280 \r
1281       if (column > aaMax)\r
1282       {\r
1283         break;\r
1284       }\r
1285 \r
1286       if (aa.annotations[column] == null)\r
1287       {\r
1288         x++;\r
1289         continue;\r
1290       }\r
1291 \r
1292       g.setColor(aa.annotations[column].colour);\r
1293       y1 = y -\r
1294           (int) ( ( (aa.annotations[column].value - min) / (range)) * aa.graphHeight);\r
1295 \r
1296       if (y1 - y2 > 0)\r
1297       {\r
1298         g.fillRect(x * av.charWidth, y2, av.charWidth, y1 - y2);\r
1299       }\r
1300       else\r
1301       {\r
1302         g.fillRect(x * av.charWidth, y1, av.charWidth, y2 - y1);\r
1303       }\r
1304 \r
1305       x++;\r
1306 \r
1307     }\r
1308     if (aa.threshold != null)\r
1309     {\r
1310       g.setColor(aa.threshold.colour);\r
1311       Graphics2D g2 = (Graphics2D) g;\r
1312       g2.setStroke(new BasicStroke(1,\r
1313                                    BasicStroke.CAP_SQUARE,\r
1314                                    BasicStroke.JOIN_ROUND, 3f,\r
1315                                    new float[]\r
1316                                    {5f, 3f}, 0f));\r
1317 \r
1318       y2 = (int) (y - ( (aa.threshold.value - min) / range) * aa.graphHeight);\r
1319       g.drawLine(0, y2, (eRes - sRes) * av.charWidth, y2);\r
1320       g2.setStroke(new BasicStroke());\r
1321     }\r
1322   }\r
1323 \r
1324   // used by overview window\r
1325   public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y,\r
1326                         int sRes, int eRes)\r
1327   {\r
1328     eRes = Math.min(eRes, aa.annotations.length);\r
1329     g.setColor(Color.white);\r
1330     g.fillRect(0, 0, width, y);\r
1331     g.setColor(new Color(0, 0, 180));\r
1332 \r
1333     int x = 0, height;\r
1334 \r
1335     for (int j = sRes; j < eRes; j++)\r
1336     {\r
1337       if (aa.annotations[j] != null)\r
1338       {\r
1339         g.setColor(aa.annotations[j].colour);\r
1340 \r
1341         height = (int) ( (aa.annotations[j].value / aa.graphMax) * y);\r
1342         if (height > y)\r
1343         {\r
1344           height = y;\r
1345         }\r
1346 \r
1347         g.fillRect(x, y - height, av.charWidth, height);\r
1348       }\r
1349       x += av.charWidth;\r
1350     }\r
1351   }\r
1352 \r
1353 }\r