Make sure fontmetrics exists for headless state
[jalview.git] / src / jalview / gui / AnnotationPanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 package jalview.gui;\r
20 \r
21 import 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 java.util.*;\r
28 \r
29 import javax.swing.*;\r
30 \r
31 \r
32 /**\r
33  * DOCUMENT ME!\r
34  *\r
35  * @author $author$\r
36  * @version $Revision$\r
37  */\r
38 public class AnnotationPanel extends JPanel implements MouseListener,\r
39     MouseMotionListener, ActionListener, AdjustmentListener\r
40 {\r
41     static String HELIX = "Helix";\r
42     static String SHEET = "Sheet";\r
43     static String LABEL = "Label";\r
44     static String REMOVE = "Remove Annotation";\r
45     static String COLOUR = "Colour";\r
46     static Color HELIX_COLOUR = Color.red.darker();\r
47     static Color SHEET_COLOUR = Color.green.darker().darker();\r
48 \r
49     /** DOCUMENT ME!! */\r
50     public static int GRAPH_HEIGHT = 40;\r
51     AlignViewport av;\r
52     AlignmentPanel ap;\r
53     int activeRow = -1;\r
54     Vector activeRes;\r
55     BufferedImage image;\r
56     Graphics2D gg;\r
57     FontMetrics fm;\r
58     int imgWidth = 0;\r
59     boolean fastPaint = false;\r
60 \r
61     /**\r
62      * Creates a new AnnotationPanel object.\r
63      *\r
64      * @param ap DOCUMENT ME!\r
65      */\r
66     public AnnotationPanel(AlignmentPanel ap)\r
67     {\r
68         ToolTipManager.sharedInstance().registerComponent(this);\r
69         ToolTipManager.sharedInstance().setInitialDelay(0);\r
70         ToolTipManager.sharedInstance().setDismissDelay(10000);\r
71         this.ap = ap;\r
72         av = ap.av;\r
73         this.setLayout(null);\r
74         addMouseListener(this);\r
75         addMouseMotionListener(this);\r
76         ap.annotationScroller.getVerticalScrollBar().addAdjustmentListener(this);\r
77     }\r
78 \r
79     /**\r
80      * DOCUMENT ME!\r
81      *\r
82      * @param evt DOCUMENT ME!\r
83      */\r
84     public void adjustmentValueChanged(AdjustmentEvent evt)\r
85     {\r
86         ap.alabels.setScrollOffset(-evt.getValue());\r
87     }\r
88 \r
89     /**\r
90      * DOCUMENT ME!\r
91      */\r
92     public void adjustPanelHeight()\r
93     {\r
94         // setHeight of panels\r
95         image = null;\r
96         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
97         int height = 0;\r
98 \r
99         if (aa != null)\r
100         {\r
101             for (int i = 0; i < aa.length; i++)\r
102             {\r
103                 if (!aa[i].visible)\r
104                 {\r
105                     continue;\r
106                 }\r
107 \r
108                 aa[i].height = 0;\r
109 \r
110                 if (aa[i].hasText)\r
111                 {\r
112                     aa[i].height += av.charHeight;\r
113                 }\r
114 \r
115                 if (aa[i].hasIcons)\r
116                 {\r
117                     aa[i].height += 16;\r
118                 }\r
119 \r
120                 if (aa[i].isGraph)\r
121                 {\r
122                     aa[i].height += GRAPH_HEIGHT;\r
123                 }\r
124 \r
125                 if (aa[i].height == 0)\r
126                 {\r
127                     aa[i].height = 20;\r
128                 }\r
129 \r
130                 height += aa[i].height;\r
131             }\r
132         }\r
133         else\r
134         {\r
135             height = 20;\r
136         }\r
137 \r
138         this.setPreferredSize(new Dimension(1, height));\r
139     }\r
140 \r
141     /**\r
142      * DOCUMENT ME!\r
143      *\r
144      * @param col DOCUMENT ME!\r
145      */\r
146     public void removeEditableColumn(int col)\r
147     {\r
148         if (activeRow == -1)\r
149         {\r
150             AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
151             if(aa==null)\r
152               return;\r
153 \r
154             for (int j = 0; j < aa.length; j++)\r
155             {\r
156                 if (aa[j].editable)\r
157                 {\r
158                     activeRow = j;\r
159 \r
160                     break;\r
161                 }\r
162             }\r
163         }\r
164 \r
165         if ((activeRes != null) && activeRes.contains(String.valueOf(col)))\r
166         {\r
167             activeRes.removeElement(String.valueOf(col));\r
168         }\r
169 \r
170         repaint();\r
171     }\r
172 \r
173     /**\r
174      * DOCUMENT ME!\r
175      *\r
176      * @param col DOCUMENT ME!\r
177      */\r
178     public void addEditableColumn(int col)\r
179     {\r
180         if (activeRow == -1)\r
181         {\r
182             AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
183             if(aa==null)\r
184               return;\r
185 \r
186             for (int j = 0; j < aa.length; j++)\r
187             {\r
188                 if (aa[j].editable)\r
189                 {\r
190                     activeRow = j;\r
191 \r
192                     break;\r
193                 }\r
194             }\r
195         }\r
196 \r
197         if (activeRes == null)\r
198         {\r
199             activeRes = new Vector();\r
200         }\r
201 \r
202         if (!activeRes.contains(String.valueOf(col)))\r
203         {\r
204             activeRes.addElement(String.valueOf(col));\r
205         }\r
206 \r
207         repaint();\r
208     }\r
209 \r
210     /**\r
211      * DOCUMENT ME!\r
212      *\r
213      * @param evt DOCUMENT ME!\r
214      */\r
215     public void actionPerformed(ActionEvent evt)\r
216     {\r
217         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
218         Annotation[] anot = aa[activeRow].annotations;\r
219 \r
220         if (evt.getActionCommand().equals(REMOVE))\r
221         {\r
222             for (int i = 0; i < activeRes.size(); i++)\r
223             {\r
224                 anot[Integer.parseInt(activeRes.get(i).toString())] = null;\r
225                 anot[Integer.parseInt(activeRes.get(i).toString())] = null;\r
226             }\r
227         }\r
228         else if (evt.getActionCommand().equals(LABEL))\r
229         {\r
230             String label = JOptionPane.showInputDialog(this, "Enter Label ",\r
231                     "Enter label", JOptionPane.QUESTION_MESSAGE);\r
232 \r
233             if (label == null)\r
234             {\r
235                 return;\r
236             }\r
237 \r
238             if ((label.length() > 0) && !aa[activeRow].hasText)\r
239             {\r
240                 aa[activeRow].hasText = true;\r
241             }\r
242 \r
243             for (int i = 0; i < activeRes.size(); i++)\r
244             {\r
245                 int index = Integer.parseInt(activeRes.get(i).toString());\r
246 \r
247                 if (anot[index] == null)\r
248                 {\r
249                     anot[index] = new Annotation(label, "", ' ', 0);\r
250                 }\r
251 \r
252                 anot[index].displayCharacter = label;\r
253             }\r
254         }\r
255         else if (evt.getActionCommand().equals(COLOUR))\r
256         {\r
257             Color col = JColorChooser.showDialog(this,\r
258                     "Choose foreground colour", Color.black);\r
259 \r
260             for (int i = 0; i < activeRes.size(); i++)\r
261             {\r
262                 int index = Integer.parseInt(activeRes.get(i).toString());\r
263 \r
264                 if (anot[index] == null)\r
265                 {\r
266                     anot[index] = new Annotation("", "", ' ', 0);\r
267                 }\r
268 \r
269                 anot[index].colour = col;\r
270             }\r
271         }\r
272         else // HELIX OR SHEET\r
273         {\r
274             char type = 0;\r
275             String symbol = "\u03B1";\r
276 \r
277             if (evt.getActionCommand().equals(HELIX))\r
278             {\r
279                 type = 'H';\r
280             }\r
281             else if (evt.getActionCommand().equals(SHEET))\r
282             {\r
283                 type = 'E';\r
284                 symbol = "\u03B2";\r
285             }\r
286 \r
287             if (!aa[activeRow].hasIcons)\r
288             {\r
289                 aa[activeRow].hasIcons = true;\r
290             }\r
291 \r
292             String label = JOptionPane.showInputDialog("Enter a label for the structure?",\r
293                     symbol);\r
294 \r
295             if (label == null)\r
296             {\r
297                 return;\r
298             }\r
299 \r
300             if ((label.length() > 0) && !aa[activeRow].hasText)\r
301             {\r
302                 aa[activeRow].hasText = true;\r
303             }\r
304 \r
305             for (int i = 0; i < activeRes.size(); i++)\r
306             {\r
307                 int index = Integer.parseInt(activeRes.get(i).toString());\r
308 \r
309                 if (anot[index] == null)\r
310                 {\r
311                     anot[index] = new Annotation(label, "", type, 0);\r
312                 }\r
313 \r
314                 anot[index].secondaryStructure = type;\r
315                 anot[index].displayCharacter = label;\r
316             }\r
317         }\r
318 \r
319         adjustPanelHeight();\r
320         activeRes = null;\r
321         repaint();\r
322 \r
323         return;\r
324     }\r
325 \r
326     /**\r
327      * DOCUMENT ME!\r
328      *\r
329      * @param evt DOCUMENT ME!\r
330      */\r
331     public void mousePressed(MouseEvent evt)\r
332     {\r
333         int height = 0;\r
334         activeRow = -1;\r
335 \r
336         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
337 \r
338         for (int i = 0; i < aa.length; i++)\r
339         {\r
340             if (aa[i].visible)\r
341             {\r
342               height += aa[i].height;\r
343             }\r
344 \r
345             if (evt.getY() < height)\r
346             {\r
347                 if (aa[i].editable)\r
348                 {\r
349                     activeRow = i;\r
350                 }\r
351                 else\r
352                 {\r
353                     activeRes = null;\r
354                 }\r
355 \r
356                 break;\r
357             }\r
358         }\r
359 \r
360         if (SwingUtilities.isRightMouseButton(evt))\r
361         {\r
362             if (activeRes == null)\r
363             {\r
364                 return;\r
365             }\r
366 \r
367             JPopupMenu pop = new JPopupMenu("Structure type");\r
368             JMenuItem item = new JMenuItem(HELIX);\r
369             item.addActionListener(this);\r
370             pop.add(item);\r
371             item = new JMenuItem(SHEET);\r
372             item.addActionListener(this);\r
373             pop.add(item);\r
374             item = new JMenuItem(LABEL);\r
375             item.addActionListener(this);\r
376             pop.add(item);\r
377             item = new JMenuItem(COLOUR);\r
378             item.addActionListener(this);\r
379             pop.add(item);\r
380             item = new JMenuItem(REMOVE);\r
381             item.addActionListener(this);\r
382             pop.add(item);\r
383             pop.show(this, evt.getX(), evt.getY());\r
384 \r
385             return;\r
386         }\r
387 \r
388         if (aa == null)\r
389         {\r
390             return;\r
391         }\r
392 \r
393         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
394 \r
395         if (evt.isControlDown() || evt.isAltDown())\r
396         {\r
397             addEditableColumn(res);\r
398         }\r
399         else if (evt.isShiftDown())\r
400         {\r
401             if (activeRes == null)\r
402             {\r
403                 activeRes = new Vector();\r
404             }\r
405             else\r
406             {\r
407                 int start = Integer.parseInt(activeRes.get(activeRes.size() -\r
408                             1).toString());\r
409                 int end = res;\r
410 \r
411                 if (end < start)\r
412                 {\r
413                     int temp = end;\r
414                     end = start;\r
415                     start = temp;\r
416                 }\r
417 \r
418                 for (int n = start; n <= end; n++)\r
419                 {\r
420                     addEditableColumn(n);\r
421                 }\r
422             }\r
423         }\r
424         else\r
425         {\r
426             activeRes = new Vector();\r
427             activeRes.addElement(String.valueOf(res));\r
428         }\r
429 \r
430         repaint();\r
431     }\r
432 \r
433     /**\r
434      * DOCUMENT ME!\r
435      *\r
436      * @param evt DOCUMENT ME!\r
437      */\r
438     public void mouseReleased(MouseEvent evt)\r
439     {\r
440     }\r
441 \r
442     /**\r
443      * DOCUMENT ME!\r
444      *\r
445      * @param evt DOCUMENT ME!\r
446      */\r
447     public void mouseEntered(MouseEvent evt)\r
448     {\r
449     }\r
450 \r
451     /**\r
452      * DOCUMENT ME!\r
453      *\r
454      * @param evt DOCUMENT ME!\r
455      */\r
456     public void mouseExited(MouseEvent evt)\r
457     {\r
458     }\r
459 \r
460     /**\r
461      * DOCUMENT ME!\r
462      *\r
463      * @param evt DOCUMENT ME!\r
464      */\r
465     public void mouseDragged(MouseEvent evt)\r
466     {\r
467     }\r
468 \r
469     /**\r
470      * DOCUMENT ME!\r
471      *\r
472      * @param evt DOCUMENT ME!\r
473      */\r
474     public void mouseMoved(MouseEvent evt)\r
475     {\r
476         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
477 \r
478         if (aa == null)\r
479         {\r
480             return;\r
481         }\r
482 \r
483         int row = -1;\r
484         int height = 0;\r
485 \r
486         for (int i = 0; i < aa.length; i++)\r
487         {\r
488             if (aa[i].visible)\r
489             {\r
490                 height += aa[i].height;\r
491             }\r
492 \r
493             if (evt.getY() < height)\r
494             {\r
495                 row = i;\r
496 \r
497                 break;\r
498             }\r
499         }\r
500 \r
501         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
502 \r
503         if ((row > -1) && (res < aa[row].annotations.length) &&\r
504                 (aa[row].annotations[res] != null))\r
505         {\r
506             this.setToolTipText(aa[row].annotations[res].description);\r
507 \r
508             StringBuffer text = new StringBuffer("Sequence position " +\r
509                     (res + 1) + "  " + aa[row].annotations[res].description);\r
510             ap.alignFrame.statusBar.setText(text.toString());\r
511         }\r
512     }\r
513 \r
514     /**\r
515      * DOCUMENT ME!\r
516      *\r
517      * @param evt DOCUMENT ME!\r
518      */\r
519     public void mouseClicked(MouseEvent evt)\r
520     {\r
521     }\r
522 \r
523     /**\r
524      * DOCUMENT ME!\r
525      *\r
526      * @param g DOCUMENT ME!\r
527      */\r
528     public void paintComponent(Graphics g)\r
529     {\r
530       g.setColor(Color.white);\r
531       g.fillRect(0, 0, getWidth(), getHeight());\r
532 \r
533       if (fastPaint && image!=null)\r
534       {\r
535         g.drawImage(image, 0, 0, this);\r
536         fastPaint = false;\r
537         return;\r
538       }\r
539 \r
540       imgWidth = (av.endRes - av.startRes + 1) * av.charWidth;\r
541 \r
542       if (image == null || imgWidth != image.getWidth())\r
543       {\r
544         image = new BufferedImage(imgWidth, ap.annotationPanel.getHeight(),\r
545                                   BufferedImage.TYPE_INT_RGB);\r
546         gg = (Graphics2D) image.getGraphics();\r
547         gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
548                             RenderingHints.VALUE_ANTIALIAS_ON);\r
549 \r
550         gg.setFont(av.getFont());\r
551         fm = gg.getFontMetrics();\r
552       }\r
553 \r
554       drawComponent(gg, av.startRes, av.endRes + 1);\r
555       g.drawImage(image, 0, 0, this);\r
556     }\r
557 \r
558     /**\r
559      * DOCUMENT ME!\r
560      *\r
561      * @param horizontal DOCUMENT ME!\r
562      */\r
563     public void fastPaint(int horizontal)\r
564     {\r
565         if ((horizontal == 0) ||\r
566                 (av.alignment.getAlignmentAnnotation() == null) ||\r
567                 (av.alignment.getAlignmentAnnotation().length < 1))\r
568         {\r
569             repaint();\r
570 \r
571             return;\r
572         }\r
573 \r
574         gg.copyArea(0, 0, imgWidth, getHeight(), -horizontal * av.charWidth, 0);\r
575 \r
576         int sr = av.startRes;\r
577         int er = av.endRes + 1;\r
578         int transX = 0;\r
579 \r
580         if (horizontal > 0) // scrollbar pulled right, image to the left\r
581         {\r
582             transX = (er - sr - horizontal) * av.charWidth;\r
583             sr = er - horizontal;\r
584         }\r
585         else if (horizontal < 0)\r
586         {\r
587             er = sr - horizontal;\r
588         }\r
589 \r
590         gg.translate(transX, 0);\r
591 \r
592         drawComponent(gg, sr, er);\r
593 \r
594         gg.translate(-transX, 0);\r
595 \r
596         fastPaint = true;\r
597 \r
598         repaint();\r
599 \r
600     }\r
601 \r
602     /**\r
603      * DOCUMENT ME!\r
604      *\r
605      * @param g DOCUMENT ME!\r
606      * @param startRes DOCUMENT ME!\r
607      * @param endRes DOCUMENT ME!\r
608      */\r
609     public void drawComponent(Graphics2D g, int startRes, int endRes)\r
610     {\r
611                 if(fm==null)\r
612                         fm = g.getFontMetrics();\r
613 \r
614         g.setColor(Color.white);\r
615         g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getHeight());\r
616 \r
617         if ((av.alignment.getAlignmentAnnotation() == null) ||\r
618                 (av.alignment.getAlignmentAnnotation().length < 1))\r
619         {\r
620             g.setColor(Color.white);\r
621             g.fillRect(0, 0, getWidth(), getHeight());\r
622             g.setColor(Color.black);\r
623             g.drawString("Alignment has no annotations", 20, 15);\r
624 \r
625             return;\r
626         }\r
627 \r
628         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
629 \r
630         int j;\r
631         int x = 0;\r
632         int y = 0;\r
633         char[] lastSS = new char[aa.length];\r
634         int[] lastSSX = new int[aa.length];\r
635         int iconOffset = av.charHeight / 2;\r
636         boolean validRes = false;\r
637 \r
638         //\u03B2 \u03B1\r
639         for (int i = 0; i < aa.length; i++)\r
640         {\r
641             AlignmentAnnotation row = aa[i];\r
642 \r
643             if (!row.visible)\r
644             {\r
645                 continue;\r
646             }\r
647 \r
648 \r
649             if (row.isGraph)\r
650             {\r
651                 // this is so that we draw the characters below the graph\r
652                 y += row.height;\r
653 \r
654                 if (row.hasText)\r
655                 {\r
656                     y -= av.charHeight;\r
657                 }\r
658             }\r
659 \r
660             if (row.hasText)\r
661             {\r
662                 iconOffset = av.charHeight / 2;\r
663             }\r
664             else\r
665             {\r
666                 iconOffset = 0;\r
667             }\r
668 \r
669             for (j = startRes; j < endRes; j++)\r
670             {\r
671                 if ((row.annotations.length <= j) ||\r
672                         (row.annotations[j] == null))\r
673                 {\r
674                     validRes = false;\r
675                 }\r
676                 else\r
677                 {\r
678                     validRes = true;\r
679                 }\r
680 \r
681                 x = (j - startRes) * av.charWidth;\r
682 \r
683                 if (activeRow == i)\r
684                 {\r
685                     g.setColor(Color.red);\r
686 \r
687                     if (activeRes != null)\r
688                     {\r
689                         for (int n = 0; n < activeRes.size(); n++)\r
690                         {\r
691                             int v = Integer.parseInt(activeRes.get(n).toString());\r
692 \r
693                             if (v == j)\r
694                             {\r
695                                 g.fillRect((j - startRes) * av.charWidth, y,\r
696                                     av.charWidth, row.height);\r
697                             }\r
698                         }\r
699                     }\r
700                 }\r
701 \r
702                 if (validRes &&\r
703                         (row.annotations[j].displayCharacter.length() > 0))\r
704                 {\r
705 \r
706                     int charOffset = (av.charWidth -\r
707                         fm.charWidth(row.annotations[j].displayCharacter.charAt(\r
708                                 0))) / 2;\r
709                     g.setColor(row.annotations[j].colour);\r
710 \r
711                     if (j == 0 || row.isGraph)\r
712                     {\r
713                         g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
714                             y + iconOffset + 3);\r
715                     }\r
716                     else if (((row.annotations[j - 1] == null) ||\r
717                             (row.annotations[j].displayCharacter != row.annotations[j -\r
718                             1].displayCharacter)))\r
719                     {\r
720                         g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
721                             y + iconOffset + 3);\r
722                     }\r
723                 }\r
724 \r
725                 if (row.hasIcons)\r
726                 {\r
727                     if (!validRes ||\r
728                             (row.annotations[j].secondaryStructure != lastSS[i]))\r
729                     {\r
730                         switch (lastSS[i])\r
731                         {\r
732                         case 'H':\r
733                             g.setColor(HELIX_COLOUR);\r
734                             g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
735                                 x - lastSSX[i], 7, 8, 8);\r
736 \r
737                             break;\r
738 \r
739                         case 'E':\r
740                             g.setColor(SHEET_COLOUR);\r
741                             g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
742                                 x - lastSSX[i] - 4, 7);\r
743                             g.fillPolygon(new int[] { x - 4, x - 4, x },\r
744                                 new int[]\r
745                                 {\r
746                                     y + iconOffset, y + 14 + iconOffset,\r
747                                     y + 8 + iconOffset\r
748                                 }, 3);\r
749 \r
750                             break;\r
751 \r
752                         case 'C':\r
753                             break;\r
754 \r
755                         default:\r
756                             g.setColor(Color.gray);\r
757                             g.fillRect(lastSSX[i], y + 6 + iconOffset,\r
758                                 x - lastSSX[i], 2);\r
759 \r
760                             break;\r
761                         }\r
762 \r
763                         if (validRes)\r
764                         {\r
765                             lastSS[i] = row.annotations[j].secondaryStructure;\r
766                         }\r
767                         else\r
768                         {\r
769                             lastSS[i] = ' ';\r
770                         }\r
771 \r
772                         lastSSX[i] = x;\r
773                     }\r
774                 }\r
775 \r
776                 if (validRes && row.isGraph)\r
777                 {\r
778                     g.setColor(new Color(0, 0, 180));\r
779 \r
780                     int height = (int) ((row.annotations[j].value / row.graphMax) * GRAPH_HEIGHT);\r
781 \r
782                     if (row.windowLength > 1)\r
783                     {\r
784                         int total = 0;\r
785 \r
786                         for (int i2 = j - (row.windowLength / 2);\r
787                                 i2 < (j + (row.windowLength / 2)); i2++)\r
788                         {\r
789                             if ((i2 < 0) || (i2 >= av.alignment.getWidth()))\r
790                             {\r
791                                 continue;\r
792                             }\r
793 \r
794                             total += row.annotations[i2].value;\r
795                         }\r
796 \r
797                         total /= row.windowLength;\r
798                         height = (int) ((total / row.graphMax) * GRAPH_HEIGHT);\r
799                     }\r
800 \r
801                     g.setColor(row.annotations[j].colour);\r
802                     g.fillRect(x, y - height, av.charWidth, height);\r
803                 }\r
804             }\r
805 \r
806             x += av.charWidth;\r
807 \r
808             if (row.hasIcons)\r
809             {\r
810                 switch (lastSS[i])\r
811                 {\r
812                 case 'H':\r
813                     g.setColor(HELIX_COLOUR);\r
814                     g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
815                         x - lastSSX[i], 7, 8, 8);\r
816 \r
817                     break;\r
818 \r
819                 case 'E':\r
820                     g.setColor(SHEET_COLOUR);\r
821                     g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
822                         x - lastSSX[i] - 4, 7);\r
823                     g.fillPolygon(new int[] { x - 4, x - 4, x },\r
824                         new int[]\r
825                         {\r
826                             y + iconOffset, y + 14 + iconOffset,\r
827                             y + 7 + iconOffset\r
828                         }, 3);\r
829 \r
830                     break;\r
831 \r
832                 case 'C':\r
833                     break;\r
834 \r
835                 default:\r
836                     g.setColor(Color.gray);\r
837                     g.fillRect(lastSSX[i], y + 6 + iconOffset, x - lastSSX[i], 2);\r
838 \r
839                     break;\r
840                 }\r
841             }\r
842 \r
843             if (row.isGraph && row.hasText)\r
844             {\r
845                 y += av.charHeight;\r
846             }\r
847 \r
848             if (!row.isGraph)\r
849             {\r
850                 y += aa[i].height;\r
851             }\r
852         }\r
853     }\r
854 \r
855     // used by overview window\r
856     public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y, int sRes, int eRes)\r
857     {\r
858         g.setColor(Color.white);\r
859         g.fillRect(0, 0, width, y);\r
860         g.setColor(new Color(0, 0, 180));\r
861 \r
862 \r
863         int x = 0, height;\r
864 \r
865         for (int j = sRes; j < eRes; j++)\r
866         {\r
867             g.setColor(new Color(0, 0, 180));\r
868 \r
869             height = (int) ((aa.annotations[j].value / aa.graphMax) * GRAPH_HEIGHT);\r
870             if(height>y)\r
871               height = y;\r
872 \r
873             g.fillRect(x, y - height, av.charWidth, height);\r
874             x += av.charWidth;\r
875         }\r
876     }\r
877 }\r