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