Threshold single element
[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].threshold!=null)\r
368                   {\r
369                     SliderPanel sp = new SliderPanel(aa[i], ap);\r
370                     return;\r
371                   }\r
372                   else\r
373                   {\r
374                     //Stretch Graph\r
375                     graphStretch = i;\r
376                     graphStretchY = evt.getY();\r
377                     activeRes = null;\r
378                   }\r
379                 }\r
380                 else\r
381                 {\r
382                     activeRes = null;\r
383                 }\r
384 \r
385                 break;\r
386             }\r
387         }\r
388 \r
389         if (SwingUtilities.isRightMouseButton(evt))\r
390         {\r
391             if (activeRes == null)\r
392             {\r
393                 return;\r
394             }\r
395 \r
396             JPopupMenu pop = new JPopupMenu("Structure type");\r
397             JMenuItem item = new JMenuItem(HELIX);\r
398             item.addActionListener(this);\r
399             pop.add(item);\r
400             item = new JMenuItem(SHEET);\r
401             item.addActionListener(this);\r
402             pop.add(item);\r
403             item = new JMenuItem(LABEL);\r
404             item.addActionListener(this);\r
405             pop.add(item);\r
406             item = new JMenuItem(COLOUR);\r
407             item.addActionListener(this);\r
408             pop.add(item);\r
409             item = new JMenuItem(REMOVE);\r
410             item.addActionListener(this);\r
411             pop.add(item);\r
412             pop.show(this, evt.getX(), evt.getY());\r
413 \r
414             return;\r
415         }\r
416 \r
417         if (aa == null)\r
418         {\r
419             return;\r
420         }\r
421 \r
422         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
423 \r
424         if (evt.isControlDown() || evt.isAltDown())\r
425         {\r
426             addEditableColumn(res);\r
427         }\r
428         else if (evt.isShiftDown())\r
429         {\r
430             if (activeRes == null)\r
431             {\r
432                 activeRes = new Vector();\r
433             }\r
434             else\r
435             {\r
436                 int start = Integer.parseInt(activeRes.get(activeRes.size() -\r
437                             1).toString());\r
438                 int end = res;\r
439 \r
440                 if (end < start)\r
441                 {\r
442                     int temp = end;\r
443                     end = start;\r
444                     start = temp;\r
445                 }\r
446 \r
447                 for (int n = start; n <= end; n++)\r
448                 {\r
449                     addEditableColumn(n);\r
450                 }\r
451             }\r
452         }\r
453         else\r
454         {\r
455             activeRes = new Vector();\r
456             activeRes.addElement(String.valueOf(res));\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 mouseReleased(MouseEvent evt)\r
466     {\r
467       graphStretch = -1;\r
468       graphStretchY = -1;\r
469     }\r
470 \r
471     /**\r
472      * DOCUMENT ME!\r
473      *\r
474      * @param evt DOCUMENT ME!\r
475      */\r
476     public void mouseEntered(MouseEvent evt)\r
477     {\r
478     }\r
479 \r
480     /**\r
481      * DOCUMENT ME!\r
482      *\r
483      * @param evt DOCUMENT ME!\r
484      */\r
485     public void mouseExited(MouseEvent evt)\r
486     {\r
487     }\r
488 \r
489     /**\r
490      * DOCUMENT ME!\r
491      *\r
492      * @param evt DOCUMENT ME!\r
493      */\r
494     public void mouseDragged(MouseEvent evt)\r
495     {\r
496       if(graphStretch>-1)\r
497       {\r
498         av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight += graphStretchY - evt.getY();\r
499         if(av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight <10)\r
500           av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight = 10;\r
501         graphStretchY = evt.getY();\r
502         adjustPanelHeight();\r
503         ap.repaint();\r
504       }\r
505     }\r
506 \r
507     /**\r
508      * DOCUMENT ME!\r
509      *\r
510      * @param evt DOCUMENT ME!\r
511      */\r
512     public void mouseMoved(MouseEvent evt)\r
513     {\r
514         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
515 \r
516         if (aa == null)\r
517         {\r
518             return;\r
519         }\r
520 \r
521         int row = -1;\r
522         int height = 0;\r
523 \r
524         for (int i = 0; i < aa.length; i++)\r
525         {\r
526             if (aa[i].visible)\r
527             {\r
528                 height += aa[i].height;\r
529             }\r
530 \r
531             if (evt.getY() < height)\r
532             {\r
533                 row = i;\r
534 \r
535                 break;\r
536             }\r
537         }\r
538 \r
539         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
540 \r
541         if (row > -1 && res<aa[row].annotations.length)\r
542         {\r
543             if(aa[row].graphGroup>-1)\r
544             {\r
545               StringBuffer tip = new StringBuffer("<html>");\r
546               for (int gg = 0; gg < aa.length; gg++)\r
547               {\r
548                 if (aa[gg].graphGroup == aa[row].graphGroup && aa[gg].annotations[res]!=null)\r
549                   tip.append(aa[gg].label+" "+aa[gg].annotations[res].description+"<br>" );\r
550               }\r
551               if(tip.length()!=6)\r
552               {\r
553                 tip.setLength(tip.length() - 4);\r
554                 this.setToolTipText(tip.toString() + "</html>");\r
555               }\r
556             }\r
557             else if(aa[row].annotations[res] != null)\r
558               this.setToolTipText(aa[row].annotations[res].description);\r
559 \r
560             if(aa[row].annotations[res]!=null)\r
561             {\r
562               StringBuffer text = new StringBuffer("Sequence position " +\r
563                                                    (res + 1) + "  " +\r
564                                                    aa[row].annotations[res].description);\r
565 \r
566               ap.alignFrame.statusBar.setText(text.toString());\r
567             }\r
568         }\r
569     }\r
570 \r
571     /**\r
572      * DOCUMENT ME!\r
573      *\r
574      * @param evt DOCUMENT ME!\r
575      */\r
576     public void mouseClicked(MouseEvent evt)\r
577     {\r
578     }\r
579 \r
580     /**\r
581      * DOCUMENT ME!\r
582      *\r
583      * @param g DOCUMENT ME!\r
584      */\r
585     public void paintComponent(Graphics g)\r
586     {\r
587       g.setColor(Color.white);\r
588       g.fillRect(0, 0, getWidth(), getHeight());\r
589 \r
590       if(image!=null)\r
591       {if (fastPaint\r
592             || (getVisibleRect().width != g.getClipBounds().width)\r
593             || (getVisibleRect().height != g.getClipBounds().height))\r
594         {\r
595           g.drawImage(image, 0, 0, this);\r
596           fastPaint = false;\r
597           return;\r
598         }\r
599       }\r
600       imgWidth = (av.endRes - av.startRes + 1) * av.charWidth;\r
601 \r
602       if (image == null || imgWidth != image.getWidth()\r
603           || image.getHeight(this) != getHeight())\r
604       {\r
605         image = new BufferedImage(imgWidth, ap.annotationPanel.getHeight(),\r
606                                   BufferedImage.TYPE_INT_RGB);\r
607         gg = (Graphics2D) image.getGraphics();\r
608 \r
609         if(av.antiAlias)\r
610         gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
611                             RenderingHints.VALUE_ANTIALIAS_ON);\r
612 \r
613         gg.setFont(av.getFont());\r
614         fm = gg.getFontMetrics();\r
615       }\r
616 \r
617 \r
618       drawComponent(gg, av.startRes, av.endRes + 1);\r
619       g.drawImage(image, 0, 0, this);\r
620     }\r
621 \r
622     /**\r
623      * DOCUMENT ME!\r
624      *\r
625      * @param horizontal DOCUMENT ME!\r
626      */\r
627     public void fastPaint(int horizontal)\r
628     {\r
629         if ((horizontal == 0) || gg==null ||\r
630                 (av.alignment.getAlignmentAnnotation() == null) ||\r
631                 (av.alignment.getAlignmentAnnotation().length < 1))\r
632         {\r
633             repaint();\r
634             return;\r
635         }\r
636 \r
637         gg.copyArea(0, 0, imgWidth, getHeight(), -horizontal * av.charWidth, 0);\r
638 \r
639         int sr = av.startRes;\r
640         int er = av.endRes + 1;\r
641         int transX = 0;\r
642 \r
643         if (horizontal > 0) // scrollbar pulled right, image to the left\r
644         {\r
645             transX = (er - sr - horizontal) * av.charWidth;\r
646             sr = er - horizontal;\r
647         }\r
648         else if (horizontal < 0)\r
649         {\r
650             er = sr - horizontal;\r
651         }\r
652 \r
653         gg.translate(transX, 0);\r
654 \r
655         drawComponent(gg, sr, er);\r
656 \r
657         gg.translate(-transX, 0);\r
658 \r
659         fastPaint = true;\r
660 \r
661         repaint();\r
662 \r
663     }\r
664 \r
665     /**\r
666      * DOCUMENT ME!\r
667      *\r
668      * @param g DOCUMENT ME!\r
669      * @param startRes DOCUMENT ME!\r
670      * @param endRes DOCUMENT ME!\r
671      */\r
672     public void drawComponent(Graphics g, int startRes, int endRes)\r
673     {\r
674       g.setFont(av.getFont());\r
675 \r
676       if (fm == null)\r
677         fm = g.getFontMetrics();\r
678 \r
679 \r
680         g.setColor(Color.white);\r
681         g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getHeight());\r
682 \r
683         if ((av.alignment.getAlignmentAnnotation() == null) ||\r
684                 (av.alignment.getAlignmentAnnotation().length < 1))\r
685         {\r
686             g.setColor(Color.white);\r
687             g.fillRect(0, 0, getWidth(), getHeight());\r
688             g.setColor(Color.black);\r
689             g.drawString("Alignment has no annotations", 20, 15);\r
690 \r
691             return;\r
692         }\r
693 \r
694         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
695 \r
696         int j;\r
697         int x = 0;\r
698         int y = 0;\r
699         char[] lastSS = new char[aa.length];\r
700         int[] lastSSX = new int[aa.length];\r
701         int iconOffset = av.charHeight / 2;\r
702         boolean validRes = false;\r
703 \r
704         boolean [] graphGroupDrawn = new boolean[aa.length];\r
705 \r
706 \r
707         //\u03B2 \u03B1\r
708         for (int i = 0; i < aa.length; i++)\r
709         {\r
710             AlignmentAnnotation row = aa[i];\r
711 \r
712             if (!row.visible)\r
713             {\r
714                 continue;\r
715             }\r
716 \r
717 \r
718 \r
719             if (row.graph>0)\r
720             {\r
721                 if(row.graphGroup>-1 && graphGroupDrawn[ row.graphGroup ] )\r
722                   continue;\r
723 \r
724                 // this is so that we draw the characters below the graph\r
725                 y += row.height;\r
726 \r
727                 if (row.hasText)\r
728                 {\r
729                     y -= av.charHeight;\r
730                 }\r
731             }\r
732 \r
733             if (row.hasText)\r
734             {\r
735                 iconOffset = av.charHeight / 2;\r
736             }\r
737             else\r
738             {\r
739                 iconOffset = 0;\r
740             }\r
741 \r
742             for (j = startRes; j < endRes; j++)\r
743             {\r
744                 if ((row.annotations.length <= j) ||\r
745                         (row.annotations[j] == null))\r
746                 {\r
747                     validRes = false;\r
748                 }\r
749                 else\r
750                 {\r
751                     validRes = true;\r
752                 }\r
753 \r
754                 x = (j - startRes) * av.charWidth;\r
755 \r
756                 if (activeRow == i)\r
757                 {\r
758                     g.setColor(Color.red);\r
759 \r
760                     if (activeRes != null)\r
761                     {\r
762                         for (int n = 0; n < activeRes.size(); n++)\r
763                         {\r
764                             int v = Integer.parseInt(activeRes.get(n).toString());\r
765 \r
766                             if (v == j)\r
767                             {\r
768                                 g.fillRect((j - startRes) * av.charWidth, y,\r
769                                     av.charWidth, row.height);\r
770                             }\r
771                         }\r
772                     }\r
773                 }\r
774 \r
775                 if (validRes &&\r
776                         (row.annotations[j].displayCharacter.length() > 0))\r
777                 {\r
778 \r
779                     int charOffset = (av.charWidth -\r
780                         fm.charWidth(row.annotations[j].displayCharacter.charAt(\r
781                                 0))) / 2;\r
782                     g.setColor(row.annotations[j].colour);\r
783 \r
784                     if (j == 0 || row.graph>0)\r
785                     {\r
786                         g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
787                             y + iconOffset + 3);\r
788                     }\r
789                     else if (((row.annotations[j - 1] == null) ||\r
790                             (row.annotations[j].displayCharacter != row.annotations[j -\r
791                             1].displayCharacter)))\r
792                     {\r
793                         g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
794                             y + iconOffset + 3);\r
795                     }\r
796                 }\r
797 \r
798                 if (row.hasIcons)\r
799                 {\r
800                     if (!validRes ||\r
801                             (row.annotations[j].secondaryStructure != lastSS[i]))\r
802                     {\r
803                         switch (lastSS[i])\r
804                         {\r
805                         case 'H':\r
806                             g.setColor(HELIX_COLOUR);\r
807                             g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
808                                 x - lastSSX[i], 7, 8, 8);\r
809 \r
810                             break;\r
811 \r
812                         case 'E':\r
813                             g.setColor(SHEET_COLOUR);\r
814                             g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
815                                 x - lastSSX[i] - 4, 7);\r
816                             g.fillPolygon(new int[] { x - 4, x - 4, x },\r
817                                 new int[]\r
818                                 {\r
819                                     y + iconOffset, y + 14 + iconOffset,\r
820                                     y + 8 + iconOffset\r
821                                 }, 3);\r
822 \r
823                             break;\r
824 \r
825 \r
826                         default:\r
827                             g.setColor(Color.gray);\r
828                             g.fillRect(lastSSX[i], y + 6 + iconOffset,\r
829                                 x - lastSSX[i], 2);\r
830 \r
831                             break;\r
832                         }\r
833 \r
834                         if (validRes)\r
835                         {\r
836                             lastSS[i] = row.annotations[j].secondaryStructure;\r
837                         }\r
838                         else\r
839                         {\r
840                             lastSS[i] = ' ';\r
841                         }\r
842 \r
843                         lastSSX[i] = x;\r
844                     }\r
845                 }\r
846             }\r
847 \r
848             x += av.charWidth;\r
849 \r
850             if (row.hasIcons)\r
851             {\r
852                 switch (lastSS[i])\r
853                 {\r
854                 case 'H':\r
855                     g.setColor(HELIX_COLOUR);\r
856                     g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
857                         x - lastSSX[i], 7, 8, 8);\r
858 \r
859                     break;\r
860 \r
861                 case 'E':\r
862                     g.setColor(SHEET_COLOUR);\r
863 \r
864                     if (row.annotations[endRes] !=null\r
865                         && row.annotations[endRes].secondaryStructure != 'E')\r
866                     {\r
867                       g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
868                                  x - lastSSX[i] - 4, 7);\r
869                       g.fillPolygon(new int[]\r
870                                     {x - 4, x - 4, x},\r
871                                     new int[]\r
872                                     {\r
873                                     y + iconOffset, y + 14 + iconOffset,\r
874                                     y + 7 + iconOffset\r
875                       }, 3);\r
876                     }\r
877                     else\r
878                       g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
879                                  x - lastSSX[i], 7);\r
880 \r
881                     break;\r
882 \r
883                 case 'C':\r
884                     break;\r
885 \r
886                 default:\r
887                     g.setColor(Color.gray);\r
888                     g.fillRect(lastSSX[i], y + 6 + iconOffset, x - lastSSX[i], 2);\r
889 \r
890                     break;\r
891                 }\r
892             }\r
893 \r
894             if (row.graph>0)\r
895             {\r
896                 if(row.graph == AlignmentAnnotation.LINE_GRAPH )\r
897                 {\r
898                   if(row.graphGroup>-1 && !graphGroupDrawn[row.graphGroup])\r
899                    {\r
900                      float groupmax=-999999, groupmin=9999999;\r
901                      for(int gg=0; gg<aa.length; gg++)\r
902                      {\r
903                        if(aa[gg].graphGroup!=row.graphGroup)\r
904                          continue;\r
905 \r
906                        if(aa[gg]!=row)\r
907                          aa[gg].visible = false;\r
908 \r
909                        if(aa[gg].graphMax>groupmax)\r
910                          groupmax = aa[gg].graphMax;\r
911                        if(aa[gg].graphMin<groupmin)\r
912                          groupmin = aa[gg].graphMin;\r
913                      }\r
914 \r
915                      for (int gg = 0; gg < aa.length; gg++)\r
916                      {\r
917                        if (aa[gg].graphGroup == row.graphGroup)\r
918                        {\r
919                          drawLineGraph(g, aa[gg], startRes, endRes, y,\r
920                                        groupmin, groupmax,\r
921                                        row.graphHeight);\r
922                        }\r
923                      }\r
924 \r
925                      graphGroupDrawn[ row.graphGroup ] = true;\r
926                    }\r
927                    else\r
928                      drawLineGraph(g, row, startRes, endRes,\r
929                                    y, row.graphMin, row.graphMax, row.graphHeight  );\r
930                 }\r
931                 else if(row.graph == AlignmentAnnotation.BAR_GRAPH )\r
932                    drawBarGraph(g, row, startRes, endRes,\r
933                                 row.graphMin, row.graphMax, y);\r
934             }\r
935 \r
936             if (row.graph>0 && row.hasText)\r
937             {\r
938                 y += av.charHeight;\r
939             }\r
940 \r
941             if (row.graph==0)\r
942             {\r
943                 y += aa[i].height;\r
944             }\r
945         }\r
946     }\r
947 \r
948     public void drawLineGraph(Graphics g, AlignmentAnnotation aa,\r
949                               int sRes, int eRes,\r
950                               int y,\r
951                               float min, float max,\r
952                               int graphHeight)\r
953     {\r
954       if(sRes>aa.annotations.length)\r
955         return;\r
956 \r
957       int x = 0;\r
958 \r
959       //Adjustment for fastpaint to left\r
960       if(eRes<av.endRes)\r
961         eRes++;\r
962 \r
963       if(sRes==0)\r
964       {\r
965         sRes++;\r
966         x+=av.charWidth;\r
967       }\r
968 \r
969       int y1=y, y2=y;\r
970       float range = max - min;\r
971 \r
972       ////Draw origin\r
973       if(min<0)\r
974         y2 = (int)(y - (0-min / range)*graphHeight);\r
975 \r
976       g.setColor(Color.gray);\r
977       g.drawLine(x-av.charWidth,y2,(eRes-sRes+1)*av.charWidth,y2);\r
978 \r
979 \r
980       if(aa.threshold!=null)\r
981       {\r
982           g.setColor(aa.threshold.colour);\r
983           Graphics2D g2 = (Graphics2D)g;\r
984           g2.setStroke(new BasicStroke(1,\r
985                                         BasicStroke.CAP_SQUARE,\r
986                                         BasicStroke.JOIN_ROUND, 3f,\r
987                                         new float[] { 5f, 3f }, 0f));\r
988 \r
989           y2 = (int)(y - ((aa.threshold.value-min) / range)*graphHeight);\r
990           g.drawLine(x-av.charWidth,y2,(eRes-sRes+1)*av.charWidth,y2);\r
991           g2.setStroke(new BasicStroke());\r
992       }\r
993 \r
994       eRes = Math.min(eRes, aa.annotations.length);\r
995       for (int j = sRes; j < eRes; j++)\r
996       {\r
997         if(aa.annotations[j]==null || aa.annotations[j-1]==null)\r
998         {\r
999           x+=av.charWidth;\r
1000           continue;\r
1001         }\r
1002           g.setColor(aa.annotations[j].colour);\r
1003           y1 = y - (int) (((aa.annotations[j-1].value-min) / range) * graphHeight);\r
1004           y2 = y - (int) (((aa.annotations[j].value-min) / range) * graphHeight);\r
1005           g.drawLine(x-av.charWidth/2, y1, x+av.charWidth/2, y2);\r
1006           x += av.charWidth;\r
1007        }\r
1008     }\r
1009 \r
1010     public void drawBarGraph(Graphics g, AlignmentAnnotation aa,\r
1011                              int sRes, int eRes,\r
1012                              float min, float max,\r
1013                              int y)\r
1014     {\r
1015       if(sRes>aa.annotations.length)\r
1016         return;\r
1017 \r
1018       int x=0, y1, y2;\r
1019 \r
1020       float range = max - min;\r
1021 \r
1022       if(aa.threshold!=null)\r
1023       {\r
1024           g.setColor(aa.threshold.colour);\r
1025           Graphics2D g2 = (Graphics2D)g;\r
1026           g2.setStroke(new BasicStroke(1,\r
1027                                         BasicStroke.CAP_SQUARE,\r
1028                                         BasicStroke.JOIN_ROUND, 3f,\r
1029                                         new float[] { 5f, 3f }, 0f));\r
1030 \r
1031           y2 = (int)(y - ((aa.threshold.value-min) / range)*aa.graphHeight);\r
1032           g.drawLine(x-av.charWidth,y2,(eRes-sRes+1)*av.charWidth,y2);\r
1033           g2.setStroke(new BasicStroke());\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 \r
1043       g.drawLine(x,y2,(eRes-sRes+1)*av.charWidth,y2);\r
1044 \r
1045       eRes = Math.min(eRes, aa.annotations.length-1);\r
1046 \r
1047 \r
1048       for (int j = sRes; j < eRes; j++)\r
1049       {\r
1050 \r
1051         if (aa.annotations[j] == null)\r
1052         {\r
1053           x += av.charWidth;\r
1054           continue;\r
1055         }\r
1056 \r
1057           g.setColor(aa.annotations[j].colour);\r
1058           y1 = y - (int) (((aa.annotations[j].value-min) / (range)) * aa.graphHeight);\r
1059 \r
1060           if(y1-y2>0)\r
1061             g.fillRect(x, y2, av.charWidth, y1-y2 );\r
1062           else\r
1063             g.fillRect(x, y1, av.charWidth, y2-y1 );\r
1064 \r
1065           x += av.charWidth;\r
1066       }\r
1067 \r
1068     }\r
1069 \r
1070     // used by overview window\r
1071     public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y, int sRes, int eRes)\r
1072     {\r
1073       g.setColor(Color.white);\r
1074       g.fillRect(0, 0, width, y);\r
1075       g.setColor(new Color(0, 0, 180));\r
1076 \r
1077       int x = 0, height;\r
1078 \r
1079       for (int j = sRes; j < eRes; j++)\r
1080       {\r
1081           g.setColor(aa.annotations[j].colour);\r
1082 \r
1083           height = (int) ((aa.annotations[j].value / aa.graphMax) * y);\r
1084           if(height>y)\r
1085             height = y;\r
1086 \r
1087           g.fillRect(x, y - height, av.charWidth, height);\r
1088           x += av.charWidth;\r
1089       }\r
1090     }\r
1091 \r
1092 }\r