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