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