GraphGroups added
[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     final String HELIX = "Helix";\r
42     final String SHEET = "Sheet";\r
43     final String LABEL = "Label";\r
44     final String REMOVE = "Remove Annotation";\r
45     final String COLOUR = "Colour";\r
46     final Color HELIX_COLOUR = Color.red.darker();\r
47     final Color SHEET_COLOUR = Color.green.darker().darker();\r
48 \r
49     /** DOCUMENT ME!! */\r
50     AlignViewport av;\r
51     AlignmentPanel ap;\r
52     int activeRow = -1;\r
53     Vector activeRes;\r
54     BufferedImage image;\r
55     Graphics2D gg;\r
56     FontMetrics fm;\r
57     int imgWidth = 0;\r
58     boolean fastPaint = false;\r
59 \r
60     //Used For mouse Dragging and resizing graphs\r
61     int graphStretch = -1;\r
62     int graphStretchY = -1;\r
63 \r
64     /**\r
65      * Creates a new AnnotationPanel object.\r
66      *\r
67      * @param ap DOCUMENT ME!\r
68      */\r
69     public AnnotationPanel(AlignmentPanel ap)\r
70     {\r
71         ToolTipManager.sharedInstance().registerComponent(this);\r
72         ToolTipManager.sharedInstance().setInitialDelay(0);\r
73         ToolTipManager.sharedInstance().setDismissDelay(10000);\r
74         this.ap = ap;\r
75         av = ap.av;\r
76         this.setLayout(null);\r
77         addMouseListener(this);\r
78         addMouseMotionListener(this);\r
79         ap.annotationScroller.getVerticalScrollBar().addAdjustmentListener(this);\r
80     }\r
81 \r
82     public AnnotationPanel(AlignViewport av)\r
83     {\r
84       this.av = av;\r
85     }\r
86 \r
87 \r
88     /**\r
89      * DOCUMENT ME!\r
90      *\r
91      * @param evt DOCUMENT ME!\r
92      */\r
93     public void adjustmentValueChanged(AdjustmentEvent evt)\r
94     {\r
95         ap.alabels.setScrollOffset(-evt.getValue());\r
96     }\r
97 \r
98     /**\r
99      * DOCUMENT ME!\r
100      */\r
101     public int adjustPanelHeight()\r
102     {\r
103         // setHeight of panels\r
104         image = null;\r
105         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
106         int height = 0;\r
107 \r
108         if (aa != null)\r
109         {\r
110             for (int i = 0; i < aa.length; i++)\r
111             {\r
112                 if (!aa[i].visible)\r
113                 {\r
114                     continue;\r
115                 }\r
116 \r
117                 aa[i].height = 0;\r
118 \r
119                 if (aa[i].hasText)\r
120                 {\r
121                     aa[i].height += av.charHeight;\r
122                 }\r
123 \r
124                 if (aa[i].hasIcons)\r
125                 {\r
126                     aa[i].height += 16;\r
127                 }\r
128 \r
129                 if (aa[i].graph>0)\r
130                 {\r
131                     aa[i].height += aa[i].graphHeight;\r
132                 }\r
133 \r
134                 if (aa[i].height == 0)\r
135                 {\r
136                     aa[i].height = 20;\r
137                 }\r
138 \r
139                 height += aa[i].height;\r
140             }\r
141         }\r
142         else\r
143         {\r
144             height = 20;\r
145         }\r
146 \r
147         this.setPreferredSize(new Dimension(1, height));\r
148 \r
149         return height;\r
150     }\r
151 \r
152     /**\r
153      * DOCUMENT ME!\r
154      *\r
155      * @param col DOCUMENT ME!\r
156      */\r
157     public void removeEditableColumn(int col)\r
158     {\r
159         if (activeRow == -1)\r
160         {\r
161             AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
162             if(aa==null)\r
163               return;\r
164 \r
165             for (int j = 0; j < aa.length; j++)\r
166             {\r
167                 if (aa[j].editable)\r
168                 {\r
169                     activeRow = j;\r
170 \r
171                     break;\r
172                 }\r
173             }\r
174         }\r
175 \r
176         if ((activeRes != null) && activeRes.contains(String.valueOf(col)))\r
177         {\r
178             activeRes.removeElement(String.valueOf(col));\r
179         }\r
180 \r
181         repaint();\r
182     }\r
183 \r
184     /**\r
185      * DOCUMENT ME!\r
186      *\r
187      * @param col DOCUMENT ME!\r
188      */\r
189     public void addEditableColumn(int col)\r
190     {\r
191         if (activeRow == -1)\r
192         {\r
193             AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
194             if(aa==null)\r
195               return;\r
196 \r
197             for (int j = 0; j < aa.length; j++)\r
198             {\r
199                 if (aa[j].editable)\r
200                 {\r
201                     activeRow = j;\r
202 \r
203                     break;\r
204                 }\r
205             }\r
206         }\r
207 \r
208         if (activeRes == null)\r
209         {\r
210             activeRes = new Vector();\r
211         }\r
212 \r
213         if (!activeRes.contains(String.valueOf(col)))\r
214         {\r
215             activeRes.addElement(String.valueOf(col));\r
216         }\r
217 \r
218         repaint();\r
219     }\r
220 \r
221     /**\r
222      * DOCUMENT ME!\r
223      *\r
224      * @param evt DOCUMENT ME!\r
225      */\r
226     public void actionPerformed(ActionEvent evt)\r
227     {\r
228         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
229         Annotation[] anot = aa[activeRow].annotations;\r
230 \r
231         if (evt.getActionCommand().equals(REMOVE))\r
232         {\r
233             for (int i = 0; i < activeRes.size(); i++)\r
234             {\r
235                 anot[Integer.parseInt(activeRes.get(i).toString())] = null;\r
236                 anot[Integer.parseInt(activeRes.get(i).toString())] = null;\r
237             }\r
238         }\r
239         else if (evt.getActionCommand().equals(LABEL))\r
240         {\r
241             String label = JOptionPane.showInputDialog(this, "Enter Label ",\r
242                     "Enter label", JOptionPane.QUESTION_MESSAGE);\r
243 \r
244             if (label == null)\r
245             {\r
246                 return;\r
247             }\r
248 \r
249             if ((label.length() > 0) && !aa[activeRow].hasText)\r
250             {\r
251                 aa[activeRow].hasText = true;\r
252             }\r
253 \r
254             for (int i = 0; i < activeRes.size(); i++)\r
255             {\r
256                 int index = Integer.parseInt(activeRes.get(i).toString());\r
257 \r
258                 if (anot[index] == null)\r
259                 {\r
260                     anot[index] = new Annotation(label, "", ' ', 0);\r
261                 }\r
262 \r
263                 anot[index].displayCharacter = label;\r
264             }\r
265         }\r
266         else if (evt.getActionCommand().equals(COLOUR))\r
267         {\r
268             Color col = JColorChooser.showDialog(this,\r
269                     "Choose foreground colour", Color.black);\r
270 \r
271             for (int i = 0; i < activeRes.size(); i++)\r
272             {\r
273                 int index = Integer.parseInt(activeRes.get(i).toString());\r
274 \r
275                 if (anot[index] == null)\r
276                 {\r
277                     anot[index] = new Annotation("", "", ' ', 0);\r
278                 }\r
279 \r
280                 anot[index].colour = col;\r
281             }\r
282         }\r
283         else // HELIX OR SHEET\r
284         {\r
285             char type = 0;\r
286             String symbol = "\u03B1";\r
287 \r
288             if (evt.getActionCommand().equals(HELIX))\r
289             {\r
290                 type = 'H';\r
291             }\r
292             else if (evt.getActionCommand().equals(SHEET))\r
293             {\r
294                 type = 'E';\r
295                 symbol = "\u03B2";\r
296             }\r
297 \r
298             if (!aa[activeRow].hasIcons)\r
299             {\r
300                 aa[activeRow].hasIcons = true;\r
301             }\r
302 \r
303             String label = JOptionPane.showInputDialog("Enter a label for the structure?",\r
304                     symbol);\r
305 \r
306             if (label == null)\r
307             {\r
308                 return;\r
309             }\r
310 \r
311             if ((label.length() > 0) && !aa[activeRow].hasText)\r
312             {\r
313                 aa[activeRow].hasText = true;\r
314             }\r
315 \r
316             for (int i = 0; i < activeRes.size(); i++)\r
317             {\r
318                 int index = Integer.parseInt(activeRes.get(i).toString());\r
319 \r
320                 if (anot[index] == null)\r
321                 {\r
322                     anot[index] = new Annotation(label, "", type, 0);\r
323                 }\r
324 \r
325                 anot[index].secondaryStructure = type;\r
326                 anot[index].displayCharacter = label;\r
327             }\r
328         }\r
329 \r
330         adjustPanelHeight();\r
331         activeRes = null;\r
332         repaint();\r
333 \r
334         return;\r
335     }\r
336 \r
337     /**\r
338      * DOCUMENT ME!\r
339      *\r
340      * @param evt DOCUMENT ME!\r
341      */\r
342     public void mousePressed(MouseEvent evt)\r
343     {\r
344         int height = 0;\r
345         activeRow = -1;\r
346 \r
347         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
348         if(aa==null)\r
349           return;\r
350 \r
351         for (int i = 0; i < aa.length; i++)\r
352         {\r
353             if (aa[i].visible)\r
354             {\r
355               height += aa[i].height;\r
356             }\r
357 \r
358             if (evt.getY() < height)\r
359             {\r
360                 if (aa[i].editable)\r
361                 {\r
362                     activeRow = i;\r
363                 }\r
364                 else if(aa[i].graph>0)\r
365                 {\r
366                   if(SwingUtilities.isRightMouseButton(evt)\r
367                       && aa[i].graphLines!=null\r
368                        && aa[i].graphLines.size()>0)\r
369                   {\r
370                     SliderPanel sp = new SliderPanel(aa[i], ap);\r
371                     return;\r
372                   }\r
373                   else\r
374                   {\r
375                     //Stretch Graph\r
376                     graphStretch = i;\r
377                     graphStretchY = evt.getY();\r
378                     activeRes = null;\r
379                   }\r
380                 }\r
381                 else\r
382                 {\r
383                     activeRes = null;\r
384                 }\r
385 \r
386                 break;\r
387             }\r
388         }\r
389 \r
390         if (SwingUtilities.isRightMouseButton(evt))\r
391         {\r
392             if (activeRes == null)\r
393             {\r
394                 return;\r
395             }\r
396 \r
397             JPopupMenu pop = new JPopupMenu("Structure type");\r
398             JMenuItem item = new JMenuItem(HELIX);\r
399             item.addActionListener(this);\r
400             pop.add(item);\r
401             item = new JMenuItem(SHEET);\r
402             item.addActionListener(this);\r
403             pop.add(item);\r
404             item = new JMenuItem(LABEL);\r
405             item.addActionListener(this);\r
406             pop.add(item);\r
407             item = new JMenuItem(COLOUR);\r
408             item.addActionListener(this);\r
409             pop.add(item);\r
410             item = new JMenuItem(REMOVE);\r
411             item.addActionListener(this);\r
412             pop.add(item);\r
413             pop.show(this, evt.getX(), evt.getY());\r
414 \r
415             return;\r
416         }\r
417 \r
418         if (aa == null)\r
419         {\r
420             return;\r
421         }\r
422 \r
423         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
424 \r
425         if (evt.isControlDown() || evt.isAltDown())\r
426         {\r
427             addEditableColumn(res);\r
428         }\r
429         else if (evt.isShiftDown())\r
430         {\r
431             if (activeRes == null)\r
432             {\r
433                 activeRes = new Vector();\r
434             }\r
435             else\r
436             {\r
437                 int start = Integer.parseInt(activeRes.get(activeRes.size() -\r
438                             1).toString());\r
439                 int end = res;\r
440 \r
441                 if (end < start)\r
442                 {\r
443                     int temp = end;\r
444                     end = start;\r
445                     start = temp;\r
446                 }\r
447 \r
448                 for (int n = start; n <= end; n++)\r
449                 {\r
450                     addEditableColumn(n);\r
451                 }\r
452             }\r
453         }\r
454         else\r
455         {\r
456             activeRes = new Vector();\r
457             activeRes.addElement(String.valueOf(res));\r
458         }\r
459     }\r
460 \r
461     /**\r
462      * DOCUMENT ME!\r
463      *\r
464      * @param evt DOCUMENT ME!\r
465      */\r
466     public void mouseReleased(MouseEvent evt)\r
467     {\r
468       graphStretch = -1;\r
469       graphStretchY = -1;\r
470     }\r
471 \r
472     /**\r
473      * DOCUMENT ME!\r
474      *\r
475      * @param evt DOCUMENT ME!\r
476      */\r
477     public void mouseEntered(MouseEvent evt)\r
478     {\r
479     }\r
480 \r
481     /**\r
482      * DOCUMENT ME!\r
483      *\r
484      * @param evt DOCUMENT ME!\r
485      */\r
486     public void mouseExited(MouseEvent evt)\r
487     {\r
488     }\r
489 \r
490     /**\r
491      * DOCUMENT ME!\r
492      *\r
493      * @param evt DOCUMENT ME!\r
494      */\r
495     public void mouseDragged(MouseEvent evt)\r
496     {\r
497       if(graphStretch>-1)\r
498       {\r
499         av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight += graphStretchY - evt.getY();\r
500         if(av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight <10)\r
501           av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight = 10;\r
502         graphStretchY = evt.getY();\r
503         adjustPanelHeight();\r
504         ap.repaint();\r
505       }\r
506     }\r
507 \r
508     /**\r
509      * DOCUMENT ME!\r
510      *\r
511      * @param evt DOCUMENT ME!\r
512      */\r
513     public void mouseMoved(MouseEvent evt)\r
514     {\r
515         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
516 \r
517         if (aa == null)\r
518         {\r
519             return;\r
520         }\r
521 \r
522         int row = -1;\r
523         int height = 0;\r
524 \r
525         for (int i = 0; i < aa.length; i++)\r
526         {\r
527             if (aa[i].visible)\r
528             {\r
529                 height += aa[i].height;\r
530             }\r
531 \r
532             if (evt.getY() < height)\r
533             {\r
534                 row = i;\r
535 \r
536                 break;\r
537             }\r
538         }\r
539 \r
540         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
541 \r
542         if ((row > -1) && (res < aa[row].annotations.length) &&\r
543                 (aa[row].annotations[res] != null))\r
544         {\r
545 \r
546 \r
547             if(aa[row].graphGroup>-1)\r
548             {\r
549               StringBuffer tip = new StringBuffer("<html>");\r
550               for (int gg = 0; gg < aa.length; gg++)\r
551               {\r
552                 if (aa[gg].graphGroup == aa[row].graphGroup && aa[gg].annotations[res]!=null)\r
553                   tip.append(aa[gg].label+" "+aa[gg].annotations[res].description+"<br>" );\r
554               }\r
555               tip.setLength(tip.length()-4);\r
556               this.setToolTipText(tip.toString()+"</html>");\r
557             }\r
558             else\r
559               this.setToolTipText(aa[row].annotations[res].description);\r
560 \r
561             StringBuffer text = new StringBuffer("Sequence position " +\r
562                     (res + 1) + "  " + aa[row].annotations[res].description);\r
563             ap.alignFrame.statusBar.setText(text.toString());\r
564         }\r
565     }\r
566 \r
567     /**\r
568      * DOCUMENT ME!\r
569      *\r
570      * @param evt DOCUMENT ME!\r
571      */\r
572     public void mouseClicked(MouseEvent evt)\r
573     {\r
574     }\r
575 \r
576     /**\r
577      * DOCUMENT ME!\r
578      *\r
579      * @param g DOCUMENT ME!\r
580      */\r
581     public void paintComponent(Graphics g)\r
582     {\r
583       g.setColor(Color.white);\r
584       g.fillRect(0, 0, getWidth(), getHeight());\r
585 \r
586       if(image!=null)\r
587       {if (fastPaint\r
588             || (getVisibleRect().width != g.getClipBounds().width)\r
589             || (getVisibleRect().height != g.getClipBounds().height))\r
590         {\r
591           g.drawImage(image, 0, 0, this);\r
592           fastPaint = false;\r
593           return;\r
594         }\r
595       }\r
596       imgWidth = (av.endRes - av.startRes + 1) * av.charWidth;\r
597 \r
598       if (image == null || imgWidth != image.getWidth()\r
599           || image.getHeight(this) != getHeight())\r
600       {\r
601         image = new BufferedImage(imgWidth, ap.annotationPanel.getHeight(),\r
602                                   BufferedImage.TYPE_INT_RGB);\r
603         gg = (Graphics2D) image.getGraphics();\r
604 \r
605         if(av.antiAlias)\r
606         gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
607                             RenderingHints.VALUE_ANTIALIAS_ON);\r
608 \r
609         gg.setFont(av.getFont());\r
610         fm = gg.getFontMetrics();\r
611       }\r
612 \r
613 \r
614       drawComponent(gg, av.startRes, av.endRes + 1);\r
615       g.drawImage(image, 0, 0, this);\r
616     }\r
617 \r
618     /**\r
619      * DOCUMENT ME!\r
620      *\r
621      * @param horizontal DOCUMENT ME!\r
622      */\r
623     public void fastPaint(int horizontal)\r
624     {\r
625         if ((horizontal == 0) ||\r
626                 (av.alignment.getAlignmentAnnotation() == null) ||\r
627                 (av.alignment.getAlignmentAnnotation().length < 1))\r
628         {\r
629             repaint();\r
630             return;\r
631         }\r
632 \r
633         gg.copyArea(0, 0, imgWidth, getHeight(), -horizontal * av.charWidth, 0);\r
634 \r
635         int sr = av.startRes;\r
636         int er = av.endRes + 1;\r
637         int transX = 0;\r
638 \r
639         if (horizontal > 0) // scrollbar pulled right, image to the left\r
640         {\r
641             transX = (er - sr - horizontal) * av.charWidth;\r
642             sr = er - horizontal;\r
643         }\r
644         else if (horizontal < 0)\r
645         {\r
646             er = sr - horizontal;\r
647         }\r
648 \r
649         gg.translate(transX, 0);\r
650 \r
651         drawComponent(gg, sr, er);\r
652 \r
653         gg.translate(-transX, 0);\r
654 \r
655         fastPaint = true;\r
656 \r
657         repaint();\r
658 \r
659     }\r
660 \r
661     /**\r
662      * DOCUMENT ME!\r
663      *\r
664      * @param g DOCUMENT ME!\r
665      * @param startRes DOCUMENT ME!\r
666      * @param endRes DOCUMENT ME!\r
667      */\r
668     public void drawComponent(Graphics g, int startRes, int endRes)\r
669     {\r
670       g.setFont(av.getFont());\r
671 \r
672       if (fm == null)\r
673         fm = g.getFontMetrics();\r
674 \r
675 \r
676         g.setColor(Color.white);\r
677         g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getHeight());\r
678 \r
679         if ((av.alignment.getAlignmentAnnotation() == null) ||\r
680                 (av.alignment.getAlignmentAnnotation().length < 1))\r
681         {\r
682             g.setColor(Color.white);\r
683             g.fillRect(0, 0, getWidth(), getHeight());\r
684             g.setColor(Color.black);\r
685             g.drawString("Alignment has no annotations", 20, 15);\r
686 \r
687             return;\r
688         }\r
689 \r
690         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
691 \r
692         int j;\r
693         int x = 0;\r
694         int y = 0;\r
695         char[] lastSS = new char[aa.length];\r
696         int[] lastSSX = new int[aa.length];\r
697         int iconOffset = av.charHeight / 2;\r
698         boolean validRes = false;\r
699 \r
700         boolean [] graphGroupDrawn = new boolean[aa.length];\r
701 \r
702 \r
703         //\u03B2 \u03B1\r
704         for (int i = 0; i < aa.length; i++)\r
705         {\r
706             AlignmentAnnotation row = aa[i];\r
707 \r
708             if (!row.visible)\r
709             {\r
710                 continue;\r
711             }\r
712 \r
713 \r
714             if (row.graph>0)\r
715             {\r
716                 if(row.graphGroup>-1 && graphGroupDrawn[ row.graphGroup ] )\r
717                   continue;\r
718 \r
719                 // this is so that we draw the characters below the graph\r
720                 y += row.height;\r
721 \r
722                 if (row.hasText)\r
723                 {\r
724                     y -= av.charHeight;\r
725                 }\r
726             }\r
727 \r
728             if (row.hasText)\r
729             {\r
730                 iconOffset = av.charHeight / 2;\r
731             }\r
732             else\r
733             {\r
734                 iconOffset = 0;\r
735             }\r
736 \r
737             for (j = startRes; j < endRes; j++)\r
738             {\r
739                 if ((row.annotations.length <= j) ||\r
740                         (row.annotations[j] == null))\r
741                 {\r
742                     validRes = false;\r
743                 }\r
744                 else\r
745                 {\r
746                     validRes = true;\r
747                 }\r
748 \r
749                 x = (j - startRes) * av.charWidth;\r
750 \r
751                 if (activeRow == i)\r
752                 {\r
753                     g.setColor(Color.red);\r
754 \r
755                     if (activeRes != null)\r
756                     {\r
757                         for (int n = 0; n < activeRes.size(); n++)\r
758                         {\r
759                             int v = Integer.parseInt(activeRes.get(n).toString());\r
760 \r
761                             if (v == j)\r
762                             {\r
763                                 g.fillRect((j - startRes) * av.charWidth, y,\r
764                                     av.charWidth, row.height);\r
765                             }\r
766                         }\r
767                     }\r
768                 }\r
769 \r
770                 if (validRes &&\r
771                         (row.annotations[j].displayCharacter.length() > 0))\r
772                 {\r
773 \r
774                     int charOffset = (av.charWidth -\r
775                         fm.charWidth(row.annotations[j].displayCharacter.charAt(\r
776                                 0))) / 2;\r
777                     g.setColor(row.annotations[j].colour);\r
778 \r
779                     if (j == 0 || row.graph>0)\r
780                     {\r
781                         g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
782                             y + iconOffset + 3);\r
783                     }\r
784                     else if (((row.annotations[j - 1] == null) ||\r
785                             (row.annotations[j].displayCharacter != row.annotations[j -\r
786                             1].displayCharacter)))\r
787                     {\r
788                         g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
789                             y + iconOffset + 3);\r
790                     }\r
791                 }\r
792 \r
793                 if (row.hasIcons)\r
794                 {\r
795                     if (!validRes ||\r
796                             (row.annotations[j].secondaryStructure != lastSS[i]))\r
797                     {\r
798                         switch (lastSS[i])\r
799                         {\r
800                         case 'H':\r
801                             g.setColor(HELIX_COLOUR);\r
802                             g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
803                                 x - lastSSX[i], 7, 8, 8);\r
804 \r
805                             break;\r
806 \r
807                         case 'E':\r
808                             g.setColor(SHEET_COLOUR);\r
809                             g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
810                                 x - lastSSX[i] - 4, 7);\r
811                             g.fillPolygon(new int[] { x - 4, x - 4, x },\r
812                                 new int[]\r
813                                 {\r
814                                     y + iconOffset, y + 14 + iconOffset,\r
815                                     y + 8 + iconOffset\r
816                                 }, 3);\r
817 \r
818                             break;\r
819 \r
820 \r
821                         default:\r
822                             g.setColor(Color.gray);\r
823                             g.fillRect(lastSSX[i], y + 6 + iconOffset,\r
824                                 x - lastSSX[i], 2);\r
825 \r
826                             break;\r
827                         }\r
828 \r
829                         if (validRes)\r
830                         {\r
831                             lastSS[i] = row.annotations[j].secondaryStructure;\r
832                         }\r
833                         else\r
834                         {\r
835                             lastSS[i] = ' ';\r
836                         }\r
837 \r
838                         lastSSX[i] = x;\r
839                     }\r
840                 }\r
841             }\r
842 \r
843             x += av.charWidth;\r
844 \r
845             if (row.hasIcons)\r
846             {\r
847                 switch (lastSS[i])\r
848                 {\r
849                 case 'H':\r
850                     g.setColor(HELIX_COLOUR);\r
851                     g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
852                         x - lastSSX[i], 7, 8, 8);\r
853 \r
854                     break;\r
855 \r
856                 case 'E':\r
857                     g.setColor(SHEET_COLOUR);\r
858 \r
859                     if (row.annotations[endRes].secondaryStructure != 'E')\r
860                     {\r
861                       g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
862                                  x - lastSSX[i] - 4, 7);\r
863                       g.fillPolygon(new int[]\r
864                                     {x - 4, x - 4, x},\r
865                                     new int[]\r
866                                     {\r
867                                     y + iconOffset, y + 14 + iconOffset,\r
868                                     y + 7 + iconOffset\r
869                       }, 3);\r
870                     }\r
871                     else\r
872                       g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
873                                  x - lastSSX[i], 7);\r
874 \r
875                     break;\r
876 \r
877                 case 'C':\r
878                     break;\r
879 \r
880                 default:\r
881                     g.setColor(Color.gray);\r
882                     g.fillRect(lastSSX[i], y + 6 + iconOffset, x - lastSSX[i], 2);\r
883 \r
884                     break;\r
885                 }\r
886             }\r
887 \r
888             if (row.graph>0)\r
889             {\r
890                 if(row.graph == AlignmentAnnotation.LINE_GRAPH )\r
891                 {\r
892                   if(row.graphGroup>-1 && !graphGroupDrawn[row.graphGroup])\r
893                    {\r
894                      float groupmax=-999999, groupmin=9999999;\r
895                      for(int gg=0; gg<aa.length; gg++)\r
896                      {\r
897                        if(aa[gg].graphGroup!=row.graphGroup)\r
898                          continue;\r
899 \r
900                        if(aa[gg]!=row)\r
901                          aa[gg].visible = false;\r
902 \r
903                        if(aa[gg].graphMax>groupmax)\r
904                          groupmax = aa[gg].graphMax;\r
905                        if(aa[gg].graphMin<groupmin)\r
906                          groupmin = aa[gg].graphMin;\r
907                      }\r
908 \r
909                      for (int gg = 0; gg < aa.length; gg++)\r
910                      {\r
911                        if (aa[gg].graphGroup == row.graphGroup)\r
912                        {\r
913                          drawLineGraph(g, aa[gg], startRes, endRes, y,\r
914                                        groupmin, groupmax,\r
915                                        row.graphHeight);\r
916                        }\r
917                      }\r
918 \r
919                      graphGroupDrawn[ row.graphGroup ] = true;\r
920                    }\r
921                    else\r
922                      drawLineGraph(g, row, startRes, endRes,\r
923                                    y, row.graphMin, row.graphMax, row.graphHeight  );\r
924                 }\r
925                 else if(row.graph == AlignmentAnnotation.BAR_GRAPH )\r
926                    drawBarGraph(g, row, startRes, endRes,\r
927                                 row.graphMin, row.graphMax, y);\r
928             }\r
929 \r
930             if (row.graph>0 && row.hasText)\r
931             {\r
932                 y += av.charHeight;\r
933             }\r
934 \r
935             if (row.graph==0)\r
936             {\r
937                 y += aa[i].height;\r
938             }\r
939         }\r
940     }\r
941 \r
942     public void drawLineGraph(Graphics g, AlignmentAnnotation aa,\r
943                               int sRes, int eRes,\r
944                               int y,\r
945                               float min, float max,\r
946                               int graphHeight)\r
947     {\r
948       if(sRes>aa.annotations.length)\r
949         return;\r
950 \r
951       int x = 0;\r
952 \r
953       //Adjustment for fastpaint to left\r
954       if(eRes<av.endRes)\r
955         eRes++;\r
956 \r
957       if(sRes==0)\r
958       {\r
959         sRes++;\r
960         x+=av.charWidth;\r
961       }\r
962 \r
963       int y1=y, y2=y;\r
964       float range = max - min;\r
965 \r
966       ////Draw origin\r
967       if(min<0)\r
968         y2 = (int)(y - (0-min / range)*graphHeight);\r
969 \r
970       g.setColor(Color.gray);\r
971       g.drawLine(x-av.charWidth,y2,(eRes-sRes+1)*av.charWidth,y2);\r
972 \r
973 \r
974       if(aa.graphLines!=null)\r
975       {\r
976         for(int l=0; l<aa.graphLines.size(); l++)\r
977         {\r
978           g.setColor(aa.getGraphLine(l).colour);\r
979           Graphics2D g2 = (Graphics2D)g;\r
980           g2.setStroke(new BasicStroke(1,\r
981                                         BasicStroke.CAP_SQUARE,\r
982                                         BasicStroke.JOIN_ROUND, 3f,\r
983                                         new float[] { 5f, 3f }, 0f));\r
984 \r
985           y2 = (int)(y - ((aa.getGraphLine(l).value-min) / range)*graphHeight);\r
986           g.drawLine(x-av.charWidth,y2,(eRes-sRes+1)*av.charWidth,y2);\r
987           g2.setStroke(new BasicStroke());\r
988         }\r
989       }\r
990 \r
991       eRes = Math.min(eRes, aa.annotations.length);\r
992       for (int j = sRes; j < eRes; j++)\r
993       {\r
994         if(aa.annotations[j]==null || aa.annotations[j-1]==null)\r
995         {\r
996           x+=av.charWidth;\r
997           continue;\r
998         }\r
999           g.setColor(aa.annotations[j].colour);\r
1000           y1 = y - (int) (((aa.annotations[j-1].value-min) / range) * graphHeight);\r
1001           y2 = y - (int) (((aa.annotations[j].value-min) / range) * graphHeight);\r
1002           g.drawLine(x-av.charWidth/2, y1, x+av.charWidth/2, y2);\r
1003           x += av.charWidth;\r
1004        }\r
1005     }\r
1006 \r
1007     public void drawBarGraph(Graphics g, AlignmentAnnotation aa,\r
1008                              int sRes, int eRes,\r
1009                              float min, float max,\r
1010                              int y)\r
1011     {\r
1012       if(sRes>aa.annotations.length)\r
1013         return;\r
1014 \r
1015       int x=0, y1, y2;\r
1016 \r
1017       float range = max - min;\r
1018 \r
1019       if(aa.graphLines!=null)\r
1020       {\r
1021         for(int l=0; l<aa.graphLines.size(); l++)\r
1022         {\r
1023           g.setColor(aa.getGraphLine(l).colour);\r
1024           Graphics2D g2 = (Graphics2D)g;\r
1025           g2.setStroke(new BasicStroke(1,\r
1026                                         BasicStroke.CAP_SQUARE,\r
1027                                         BasicStroke.JOIN_ROUND, 3f,\r
1028                                         new float[] { 5f, 3f }, 0f));\r
1029 \r
1030           y2 = (int)(y - ((aa.getGraphLine(l).value-min) / range)*aa.graphHeight);\r
1031           g.drawLine(x-av.charWidth,y2,(eRes-sRes+1)*av.charWidth,y2);\r
1032           g2.setStroke(new BasicStroke());\r
1033         }\r
1034       }\r
1035 \r
1036       y1 = y2 = y;\r
1037 \r
1038       if(min<0)\r
1039         y2 = (int)(y - (0-min / (range))*aa.graphHeight);\r
1040 \r
1041       g.setColor(Color.gray);\r
1042       g.drawLine(x,y2,eRes*av.charWidth,y2);\r
1043 \r
1044       eRes = Math.min(eRes, aa.annotations.length-1);\r
1045 \r
1046 \r
1047       for (int j = sRes; j < eRes; j++)\r
1048       {\r
1049         if (aa.annotations[j] == null)\r
1050         {\r
1051           x += av.charWidth;\r
1052           continue;\r
1053         }\r
1054 \r
1055           g.setColor(aa.annotations[j].colour);\r
1056           y1 = y - (int) (((aa.annotations[j].value-min) / (range)) * aa.graphHeight);\r
1057 \r
1058           if(y1-y2>0)\r
1059             g.fillRect(x, y2, av.charWidth, y1-y2 );\r
1060           else\r
1061             g.fillRect(x, y1, av.charWidth, y2-y1 );\r
1062 \r
1063           x += av.charWidth;\r
1064       }\r
1065 \r
1066     }\r
1067 \r
1068     // used by overview window\r
1069     public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y, int sRes, int eRes)\r
1070     {\r
1071       g.setColor(Color.white);\r
1072       g.fillRect(0, 0, width, y);\r
1073       g.setColor(new Color(0, 0, 180));\r
1074 \r
1075       int x = 0, height;\r
1076 \r
1077       for (int j = sRes; j < eRes; j++)\r
1078       {\r
1079           g.setColor(aa.annotations[j].colour);\r
1080 \r
1081           height = (int) ((aa.annotations[j].value / aa.graphMax) * y);\r
1082           if(height>y)\r
1083             height = y;\r
1084 \r
1085           g.fillRect(x, y - height, av.charWidth, height);\r
1086           x += av.charWidth;\r
1087       }\r
1088     }\r
1089 \r
1090 }\r