ensure lastSeq is refreshed if new feature added
[jalview.git] / src / jalview / gui / AnnotationPanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2006 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     BufferedImage fadedImage;\r
53     Graphics2D gg;\r
54     FontMetrics fm;\r
55     int imgWidth = 0;\r
56     boolean fastPaint = false;\r
57 \r
58     //Used For mouse Dragging and resizing graphs\r
59     int graphStretch = -1;\r
60     int graphStretchY = -1;\r
61     int min; //used by mouseDragged to see if user\r
62     int max; //used by mouseDragged to see if user\r
63     boolean mouseDragging = false;\r
64 \r
65     boolean MAC = false;\r
66 \r
67     /**\r
68      * Creates a new AnnotationPanel object.\r
69      *\r
70      * @param ap DOCUMENT ME!\r
71      */\r
72     public AnnotationPanel(AlignmentPanel ap)\r
73     {\r
74 \r
75     if(System.getProperty("os.name").startsWith("Mac"))\r
76       MAC = true;\r
77 \r
78         ToolTipManager.sharedInstance().registerComponent(this);\r
79         ToolTipManager.sharedInstance().setInitialDelay(0);\r
80         ToolTipManager.sharedInstance().setDismissDelay(10000);\r
81         this.ap = ap;\r
82         av = ap.av;\r
83         this.setLayout(null);\r
84         addMouseListener(this);\r
85         addMouseMotionListener(this);\r
86         ap.annotationScroller.getVerticalScrollBar().addAdjustmentListener(this);\r
87     }\r
88 \r
89     public AnnotationPanel(AlignViewport av)\r
90     {\r
91       this.av = av;\r
92     }\r
93 \r
94 \r
95     /**\r
96      * DOCUMENT ME!\r
97      *\r
98      * @param evt DOCUMENT ME!\r
99      */\r
100     public void adjustmentValueChanged(AdjustmentEvent evt)\r
101     {\r
102         ap.alabels.setScrollOffset(-evt.getValue());\r
103     }\r
104 \r
105     /**\r
106      * DOCUMENT ME!\r
107      */\r
108     public int adjustPanelHeight()\r
109     {\r
110         // setHeight of panels\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 \r
282 \r
283         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
284         if(aa==null)\r
285           return;\r
286 \r
287 \r
288         int height = 0;\r
289         activeRow = -1;\r
290 \r
291 \r
292         for (int i = 0; i < aa.length; i++)\r
293         {\r
294             if (aa[i].visible)\r
295             {\r
296               height += aa[i].height;\r
297             }\r
298 \r
299             if (evt.getY() < height)\r
300             {\r
301                 if (aa[i].editable)\r
302                 {\r
303                     activeRow = i;\r
304                 }\r
305                 else if(aa[i].graph>0)\r
306                 {\r
307                     //Stretch Graph\r
308                     graphStretch = i;\r
309                     graphStretchY = evt.getY();\r
310                 }\r
311 \r
312                 break;\r
313             }\r
314         }\r
315 \r
316 \r
317         if (SwingUtilities.isRightMouseButton(evt) && activeRow!=-1)\r
318         {\r
319             if (av.getColumnSelection() == null)\r
320             {\r
321                 return;\r
322             }\r
323 \r
324             JPopupMenu pop = new JPopupMenu("Structure type");\r
325             JMenuItem item = new JMenuItem(HELIX);\r
326             item.addActionListener(this);\r
327             pop.add(item);\r
328             item = new JMenuItem(SHEET);\r
329             item.addActionListener(this);\r
330             pop.add(item);\r
331             item = new JMenuItem(LABEL);\r
332             item.addActionListener(this);\r
333             pop.add(item);\r
334             item = new JMenuItem(COLOUR);\r
335             item.addActionListener(this);\r
336             pop.add(item);\r
337             item = new JMenuItem(REMOVE);\r
338             item.addActionListener(this);\r
339             pop.add(item);\r
340             pop.show(this, evt.getX(), evt.getY());\r
341 \r
342             return;\r
343         }\r
344 \r
345         if (aa == null)\r
346         {\r
347             return;\r
348         }\r
349 \r
350         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
351 \r
352         min = res;\r
353         max = res;\r
354 \r
355         if (av.getColumnSelection().contains(res))\r
356           av.getColumnSelection().removeElement(res);\r
357         else\r
358         {\r
359             av.getColumnSelection().addElement(res);\r
360             SequenceGroup sg = new SequenceGroup();\r
361 \r
362             for (int i = 0; i < av.alignment.getSequences().size(); i++)\r
363             {\r
364                 sg.addSequence(av.alignment.getSequenceAt(i), false);\r
365             }\r
366 \r
367             sg.setStartRes(res);\r
368             sg.setEndRes(res);\r
369             av.setSelectionGroup(sg);\r
370         }\r
371 \r
372         ap.repaint();\r
373 \r
374     }\r
375 \r
376     /**\r
377      * DOCUMENT ME!\r
378      *\r
379      * @param evt DOCUMENT ME!\r
380      */\r
381     public void mouseReleased(MouseEvent evt)\r
382     {\r
383       graphStretch = -1;\r
384       graphStretchY = -1;\r
385       mouseDragging = false;\r
386     }\r
387 \r
388     /**\r
389      * DOCUMENT ME!\r
390      *\r
391      * @param evt DOCUMENT ME!\r
392      */\r
393     public void mouseEntered(MouseEvent evt)\r
394     {\r
395       if(mouseDragging)\r
396         ap.seqPanel.scrollCanvas(null);\r
397     }\r
398 \r
399     /**\r
400      * DOCUMENT ME!\r
401      *\r
402      * @param evt DOCUMENT ME!\r
403      */\r
404     public void mouseExited(MouseEvent evt)\r
405     {\r
406       if(mouseDragging)\r
407         ap.seqPanel.scrollCanvas(evt);\r
408     }\r
409 \r
410 \r
411     /**\r
412      * DOCUMENT ME!\r
413      *\r
414      * @param evt DOCUMENT ME!\r
415      */\r
416     public void mouseDragged(MouseEvent evt)\r
417     {\r
418       if(graphStretch>-1)\r
419       {\r
420         av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight += graphStretchY - evt.getY();\r
421         if(av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight <0)\r
422           av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight = 0;\r
423         graphStretchY = evt.getY();\r
424         adjustPanelHeight();\r
425         ap.repaint();\r
426       }\r
427       else\r
428       {\r
429         mouseDragging = true;\r
430 \r
431         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
432 \r
433         SequenceGroup sg = av.getSelectionGroup();\r
434 \r
435         if (res < min)\r
436         {\r
437             min = res;\r
438         }\r
439 \r
440         if (res > max)\r
441         {\r
442             max = res;\r
443         }\r
444 \r
445         if (sg != null)\r
446         {\r
447             if (!av.getColumnSelection().contains(res))\r
448             {\r
449                 av.getColumnSelection().addElement(res);\r
450             }\r
451 \r
452             if (res > sg.getStartRes())\r
453             {\r
454                 sg.setEndRes(res);\r
455             }\r
456             else if (res < sg.getStartRes())\r
457             {\r
458                 sg.setStartRes(res);\r
459             }\r
460 \r
461             for (int i = min; i <= max; i++)\r
462             {\r
463                 if ((i < sg.getStartRes()) || (i > sg.getEndRes()))\r
464                 {\r
465                     av.getColumnSelection().removeElement(i);\r
466                 }\r
467                 else\r
468                 {\r
469                     av.getColumnSelection().addElement(i);\r
470                 }\r
471             }\r
472 \r
473             ap.repaint();\r
474         }\r
475 \r
476       }\r
477     }\r
478 \r
479     /**\r
480      * DOCUMENT ME!\r
481      *\r
482      * @param evt DOCUMENT ME!\r
483      */\r
484     public void mouseMoved(MouseEvent evt)\r
485     {\r
486         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
487 \r
488         if (aa == null)\r
489         {\r
490             return;\r
491         }\r
492 \r
493         int row = -1;\r
494         int height = 0;\r
495 \r
496         for (int i = 0; i < aa.length; i++)\r
497         {\r
498             if (aa[i].visible)\r
499             {\r
500                 height += aa[i].height;\r
501             }\r
502 \r
503             if (evt.getY() < height)\r
504             {\r
505                 row = i;\r
506 \r
507                 break;\r
508             }\r
509         }\r
510 \r
511         if(row==-1)\r
512           return;\r
513 \r
514         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
515 \r
516         if(av.hasHiddenColumns)\r
517           res = av.getColumnSelection().adjustForHiddenColumns(res);\r
518 \r
519         if ( aa[row].annotations!=null\r
520              && row > -1\r
521              && res < (int) aa[row].annotations.length)\r
522         {\r
523             if(aa[row].graphGroup>-1)\r
524             {\r
525               StringBuffer tip = new StringBuffer("<html>");\r
526               for (int gg = 0; gg < aa.length; gg++)\r
527               {\r
528                 if (aa[gg].graphGroup == aa[row].graphGroup && aa[gg].annotations[res]!=null)\r
529                   tip.append(aa[gg].label+" "+aa[gg].annotations[res].description+"<br>" );\r
530               }\r
531               if(tip.length()!=6)\r
532               {\r
533                 tip.setLength(tip.length() - 4);\r
534                 this.setToolTipText(tip.toString() + "</html>");\r
535               }\r
536             }\r
537             else if(aa[row].annotations[res] != null)\r
538               this.setToolTipText(aa[row].annotations[res].description);\r
539 \r
540             if(aa[row].annotations[res]!=null)\r
541             {\r
542               StringBuffer text = new StringBuffer("Sequence position " +\r
543                                                    (res + 1) + "  " +\r
544                                                    aa[row].annotations[res].description);\r
545 \r
546               ap.alignFrame.statusBar.setText(text.toString());\r
547             }\r
548         }\r
549     }\r
550 \r
551     /**\r
552      * DOCUMENT ME!\r
553      *\r
554      * @param evt DOCUMENT ME!\r
555      */\r
556     public void mouseClicked(MouseEvent evt)\r
557     {\r
558     }\r
559 \r
560     /**\r
561      * DOCUMENT ME!\r
562      *\r
563      * @param g DOCUMENT ME!\r
564      */\r
565     public void paintComponent(Graphics g)\r
566     {\r
567       g.setColor(Color.white);\r
568       g.fillRect(0, 0, getWidth(), getHeight());\r
569 \r
570       if(image!=null)\r
571       {if (fastPaint\r
572             || (getVisibleRect().width != g.getClipBounds().width)\r
573             || (getVisibleRect().height != g.getClipBounds().height))\r
574         {\r
575           g.drawImage(image, 0, 0, this);\r
576           fastPaint = false;\r
577           return;\r
578         }\r
579       }\r
580       imgWidth = (av.endRes - av.startRes + 1) * av.charWidth;\r
581 \r
582       if (image == null || imgWidth != image.getWidth()\r
583           || image.getHeight(this) != getHeight())\r
584       {\r
585         image = new BufferedImage(imgWidth, ap.annotationPanel.getHeight(),\r
586                                   BufferedImage.TYPE_INT_RGB);\r
587         gg = (Graphics2D) image.getGraphics();\r
588 \r
589         if(av.antiAlias)\r
590         gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
591                             RenderingHints.VALUE_ANTIALIAS_ON);\r
592 \r
593         gg.setFont(av.getFont());\r
594         fm = gg.getFontMetrics();\r
595         gg.setColor(Color.white);\r
596         gg.fillRect(0, 0, imgWidth, image.getHeight());\r
597       }\r
598 \r
599 \r
600       drawComponent(gg, av.startRes, av.endRes + 1);\r
601       g.drawImage(image, 0, 0, this);\r
602     }\r
603 \r
604     /**\r
605      * DOCUMENT ME!\r
606      *\r
607      * @param horizontal DOCUMENT ME!\r
608      */\r
609     public void fastPaint(int horizontal)\r
610     {\r
611         if ((horizontal == 0)\r
612             || gg==null\r
613             || av.alignment.getAlignmentAnnotation()==null\r
614             || av.alignment.getAlignmentAnnotation().length < 1\r
615             || av.updatingConsensus\r
616             || av.updatingConservation)\r
617         {\r
618             repaint();\r
619             return;\r
620         }\r
621 \r
622         gg.copyArea(0, 0, imgWidth, getHeight(), -horizontal * av.charWidth, 0);\r
623 \r
624         int sr = av.startRes;\r
625         int er = av.endRes + 1;\r
626         int transX = 0;\r
627 \r
628         if (horizontal > 0) // scrollbar pulled right, image to the left\r
629         {\r
630             transX = (er - sr - horizontal) * av.charWidth;\r
631             sr = er - horizontal;\r
632         }\r
633         else if (horizontal < 0)\r
634         {\r
635             er = sr - horizontal;\r
636         }\r
637 \r
638         gg.translate(transX, 0);\r
639 \r
640         drawComponent(gg, sr, er);\r
641 \r
642         gg.translate(-transX, 0);\r
643 \r
644         fastPaint = true;\r
645 \r
646         repaint();\r
647 \r
648     }\r
649 \r
650     /**\r
651      * DOCUMENT ME!\r
652      *\r
653      * @param g DOCUMENT ME!\r
654      * @param startRes DOCUMENT ME!\r
655      * @param endRes DOCUMENT ME!\r
656      */\r
657     public void drawComponent(Graphics g, int startRes, int endRes)\r
658     {\r
659       if(av.updatingConsensus || av.updatingConservation)\r
660       {\r
661         if(image==null)\r
662          {\r
663            return;\r
664          }\r
665         //We'll keep a record of the old image,\r
666         //and draw a faded image until the calculation\r
667         //has completed\r
668         if(fadedImage==null\r
669            || fadedImage.getWidth()!=imgWidth\r
670         || fadedImage.getHeight()!=image.getHeight())\r
671         {\r
672           fadedImage = new BufferedImage(\r
673               imgWidth, image.getHeight(),\r
674               BufferedImage.TYPE_INT_RGB);\r
675 \r
676           Graphics2D fadedG = (Graphics2D) fadedImage.getGraphics();\r
677 \r
678           fadedG.setColor(Color.white);\r
679         fadedG.fillRect(0, 0, imgWidth, image.getHeight());\r
680 \r
681           fadedG.setComposite(\r
682               AlphaComposite.getInstance(\r
683                   AlphaComposite.SRC_OVER, .3f));\r
684           fadedG.drawImage(image, 0, 0, this);\r
685 \r
686         }\r
687 \r
688       }\r
689       else\r
690         fadedImage = null;\r
691 \r
692 \r
693       g.setColor(Color.white);\r
694       g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getHeight());\r
695 \r
696       g.setFont(av.getFont());\r
697       if (fm == null)\r
698         fm = g.getFontMetrics();\r
699 \r
700 \r
701 \r
702 \r
703         if ( (av.alignment.getAlignmentAnnotation() == null) ||\r
704                 (av.alignment.getAlignmentAnnotation().length < 1))\r
705         {\r
706             g.setColor(Color.white);\r
707             g.fillRect(0, 0, getWidth(), getHeight());\r
708             g.setColor(Color.black);\r
709             if(av.validCharWidth)\r
710               g.drawString("Alignment has no annotations", 20, 15);\r
711 \r
712             return;\r
713         }\r
714 \r
715 \r
716         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
717 \r
718         int x = 0, y = 0;\r
719         int column=0;\r
720         char lastSS;\r
721         int lastSSX;\r
722         int iconOffset = av.charHeight / 2;\r
723         boolean validRes = false;\r
724 \r
725         boolean [] graphGroupDrawn = new boolean[aa.length];\r
726 \r
727 \r
728         //\u03B2 \u03B1\r
729         for (int i = 0; i < aa.length; i++)\r
730         {\r
731             AlignmentAnnotation row = aa[i];\r
732 \r
733             if (!row.visible)\r
734             {\r
735                 continue;\r
736             }\r
737 \r
738 \r
739             lastSS = ' ';\r
740             lastSSX = 0;\r
741 \r
742             if (row.graph>0)\r
743             {\r
744                 if(row.graphGroup>-1 && graphGroupDrawn[ row.graphGroup ] )\r
745                   continue;\r
746 \r
747                 // this is so that we draw the characters below the graph\r
748                 y += row.height;\r
749 \r
750                 if (row.hasText)\r
751                 {\r
752                     y -= av.charHeight;\r
753                 }\r
754             }\r
755 \r
756             if (av.updatingConsensus && aa[i].label.equals("Consensus"))\r
757             {\r
758               y += av.charHeight;\r
759 \r
760               g.drawImage(fadedImage,\r
761               0,y-row.height,imgWidth, y,\r
762               0,y-row.height,imgWidth, y, this);\r
763               g.setColor(Color.black);\r
764              // g.drawString("Calculating Consensus....",20, y-row.height/2);\r
765 \r
766               continue;\r
767             }\r
768             else if (av.updatingConservation && aa[i].label.equals("Conservation"))\r
769             {\r
770 \r
771               y += av.charHeight;\r
772               g.drawImage(fadedImage,\r
773                           0, y - row.height, imgWidth, y,\r
774                           0, y - row.height, imgWidth, y, this);\r
775 \r
776               g.setColor(Color.black);\r
777             //  g.drawString("Calculating Conservation.....",20, y-row.height/2);\r
778 \r
779               continue;\r
780             }\r
781             else if (av.updatingConservation && aa[i].label.equals("Quality"))\r
782             {\r
783 \r
784               y += av.charHeight;\r
785               g.drawImage(fadedImage,\r
786                           0, y - row.height, imgWidth, y,\r
787                           0, y - row.height, imgWidth, y, this);\r
788               g.setColor(Color.black);\r
789              /// g.drawString("Calculating Quality....",20, y-row.height/2);\r
790 \r
791               continue;\r
792             }\r
793 \r
794 \r
795             if (row.hasText)\r
796             {\r
797                 iconOffset = av.charHeight / 2 + 4;\r
798             }\r
799             else\r
800             {\r
801                 iconOffset = 0;\r
802             }\r
803 \r
804             x = 0;\r
805             while (x < endRes-startRes)\r
806             {\r
807               if (av.hasHiddenColumns)\r
808               {\r
809                 column = av.getColumnSelection().adjustForHiddenColumns(startRes+x);\r
810                 if (column > row.annotations.length-1)\r
811                 {\r
812                   break;\r
813                 }\r
814               }\r
815               else\r
816                 column = startRes+x;\r
817 \r
818 \r
819                 if ((row.annotations.length <= column) ||\r
820                         (row.annotations[column] == null))\r
821                 {\r
822                     validRes = false;\r
823                 }\r
824                 else\r
825                 {\r
826                     validRes = true;\r
827                 }\r
828 \r
829 \r
830                 if (activeRow == i)\r
831                 {\r
832                     g.setColor(Color.red);\r
833 \r
834                     if (av.getColumnSelection() != null)\r
835                     {\r
836                         for (int n = 0; n < av.getColumnSelection().size(); n++)\r
837                         {\r
838                             int v = av.getColumnSelection().columnAt(n);\r
839 \r
840                             if (v == column)\r
841                             {\r
842                                 g.fillRect(x * av.charWidth, y,\r
843                                     av.charWidth, av.charHeight);\r
844                             }\r
845                         }\r
846                     }\r
847                 }\r
848 \r
849                 if (av.validCharWidth && validRes &&\r
850                         (row.annotations[column].displayCharacter.length() > 0))\r
851                 {\r
852 \r
853                     int charOffset = (av.charWidth -\r
854                         fm.charWidth(row.annotations[column].displayCharacter.charAt(\r
855                                 0))) / 2;\r
856                     g.setColor(row.annotations[column].colour);\r
857 \r
858                     if (column == 0 || row.graph>0)\r
859                     {\r
860                         g.drawString(row.annotations[column].displayCharacter,\r
861                                      (x*av.charWidth)+charOffset,\r
862                             y + iconOffset );\r
863                     }\r
864                     else if (\r
865                         row.annotations[column - 1] == null\r
866                         ||(!row.annotations[column].displayCharacter.equals(\r
867                             row.annotations[column - 1].displayCharacter)\r
868                         ||\r
869                   (row.annotations[column].displayCharacter.length() <2 &&\r
870                    row.annotations[column].secondaryStructure==' ')))\r
871                     {\r
872                         g.drawString(row.annotations[column].displayCharacter,\r
873                                      x*av.charWidth+charOffset,\r
874                                      y + iconOffset );\r
875                     }\r
876                 }\r
877 \r
878                 if (row.hasIcons)\r
879                 {\r
880                     if (!validRes ||\r
881                             (row.annotations[column].secondaryStructure != lastSS))\r
882                     {\r
883                         switch (lastSS)\r
884                         {\r
885                         case 'H':\r
886                           g.setColor(HELIX_COLOUR);\r
887                           if (MAC)\r
888                           {\r
889                             //Off by 1 offset when drawing rects and ovals\r
890                             //to offscreen image on the MAC\r
891                             g.fillRoundRect(lastSSX, y + 4 + iconOffset,\r
892                                             (x*av.charWidth) - lastSSX, 7, 8, 8);\r
893                             break;\r
894                           }\r
895 \r
896                           int sCol = (lastSSX / av.charWidth) + startRes;\r
897                           int x1 = lastSSX;\r
898                           int x2 = (x*av.charWidth);\r
899 \r
900                          if(sCol==0 ||\r
901                             row.annotations[sCol-1]==null ||\r
902                             row.annotations[sCol-1].secondaryStructure!='H')\r
903                          {\r
904                            g.fillArc(lastSSX, y+4+iconOffset, av.charWidth, 8, 90,180) ;\r
905                            x1 += av.charWidth/2;\r
906                          }\r
907 \r
908                           if(row.annotations[column]==null ||\r
909                              row.annotations[column].secondaryStructure!='H')\r
910                           {\r
911                             g.fillArc((x*av.charWidth)-av.charWidth,\r
912                                       y+4+iconOffset, av.charWidth, 8, 270,180);\r
913                             x2 -= av.charWidth/2;\r
914                           }\r
915 \r
916                           g.fillRect(x1, y+4+iconOffset, x2-x1, 8);\r
917                               break;\r
918 \r
919                         case 'E':\r
920                             g.setColor(SHEET_COLOUR);\r
921                             g.fillRect(lastSSX, y + 4 + iconOffset,\r
922                                 (x*av.charWidth) - lastSSX - 4, 7);\r
923                             g.fillPolygon(new int[] { (x*av.charWidth) - 4,\r
924                                           (x*av.charWidth) - 4,\r
925                                           (x*av.charWidth) },\r
926                                 new int[]\r
927                                 {\r
928                                     y + iconOffset, y + 14 + iconOffset,\r
929                                     y + 8 + iconOffset\r
930                                 }, 3);\r
931 \r
932                             break;\r
933 \r
934 \r
935                         default:\r
936                             g.setColor(Color.gray);\r
937                             g.fillRect(lastSSX, y + 6 + iconOffset,\r
938                                 (x*av.charWidth) - lastSSX, 2);\r
939 \r
940                             break;\r
941                         }\r
942 \r
943                         if (validRes)\r
944                         {\r
945                             lastSS = row.annotations[column].secondaryStructure;\r
946                         }\r
947                         else\r
948                         {\r
949                             lastSS = ' ';\r
950                         }\r
951 \r
952                         lastSSX = (x*av.charWidth);\r
953                     }\r
954                 }\r
955 \r
956 \r
957             column++;\r
958             x++;\r
959             }\r
960 \r
961             if(column>=row.annotations.length)\r
962                 column = row.annotations.length-1;\r
963 \r
964           //  x ++;\r
965 \r
966             if (row.hasIcons)\r
967             {\r
968               switch (lastSS)\r
969               {\r
970                 case 'H':\r
971                   g.setColor(HELIX_COLOUR);\r
972                   if (MAC)\r
973                   {\r
974                     //Off by 1 offset when drawing rects and ovals\r
975                     //to offscreen image on the MAC\r
976                     g.fillRoundRect(lastSSX, y + 4 + iconOffset,\r
977                                     (x*av.charWidth) - lastSSX, 7, 8, 8);\r
978                     break;\r
979                   }\r
980 \r
981                   int sCol = (lastSSX / av.charWidth) + startRes;\r
982                   int x1 = lastSSX;\r
983                   int x2 = (x*av.charWidth);\r
984 \r
985                   if (sCol == 0 ||\r
986                       row.annotations[sCol - 1] == null ||\r
987                       row.annotations[sCol - 1].secondaryStructure != 'H')\r
988                   {\r
989                     g.fillArc(lastSSX, y + 4 + iconOffset, av.charWidth, 8, 90, 180);\r
990                     x1 += av.charWidth / 2;\r
991                   }\r
992 \r
993                   if (row.annotations[column] == null ||\r
994                       row.annotations[column].secondaryStructure != 'H')\r
995                   {\r
996                     g.fillArc((x*av.charWidth) - av.charWidth,\r
997                               y + 4 + iconOffset, av.charWidth, 8, 270,\r
998                               180);\r
999                     x2 -= av.charWidth / 2;\r
1000                   }\r
1001 \r
1002                   g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);\r
1003 \r
1004                   break;\r
1005 \r
1006                 case 'E':\r
1007                   g.setColor(SHEET_COLOUR);\r
1008 \r
1009                   if (row.annotations[endRes] == null\r
1010                       || row.annotations[endRes].secondaryStructure != 'E')\r
1011                   {\r
1012                     g.fillRect(lastSSX, y + 4 + iconOffset,\r
1013                                (x*av.charWidth) - lastSSX - 4, 7);\r
1014                     g.fillPolygon(new int[]\r
1015                                   {(x*av.charWidth) - 4,\r
1016                                   (x*av.charWidth) - 4,\r
1017                                  (x*av.charWidth)},\r
1018                                   new int[]\r
1019                                   {\r
1020                                   y + iconOffset, y + 14 + iconOffset,\r
1021                                   y + 7 + iconOffset\r
1022                     }, 3);\r
1023                   }\r
1024                   else\r
1025                    {\r
1026                      g.fillRect(lastSSX, y + 4 + iconOffset,\r
1027                                 (x+1) * av.charWidth - lastSSX, 7);\r
1028                    }\r
1029                   break;\r
1030 \r
1031                 default:\r
1032                   g.setColor(Color.gray);\r
1033                   if(!av.wrapAlignment || endRes==av.endRes)\r
1034                   g.fillRect(lastSSX, y + 6 + iconOffset,\r
1035                              (x*av.charWidth) - lastSSX, 2);\r
1036 \r
1037                   break;\r
1038               }\r
1039           }\r
1040 \r
1041             if (row.graph>0 && row.graphHeight>0)\r
1042             {\r
1043                 if(row.graph == AlignmentAnnotation.LINE_GRAPH )\r
1044                 {\r
1045                   if(row.graphGroup>-1 && !graphGroupDrawn[row.graphGroup])\r
1046                    {\r
1047                      float groupmax=-999999, groupmin=9999999;\r
1048                      for(int gg=0; gg<aa.length; gg++)\r
1049                      {\r
1050                        if(aa[gg].graphGroup!=row.graphGroup)\r
1051                          continue;\r
1052 \r
1053                        if(aa[gg]!=row)\r
1054                          aa[gg].visible = false;\r
1055 \r
1056                        if(aa[gg].graphMax>groupmax)\r
1057                          groupmax = aa[gg].graphMax;\r
1058                        if(aa[gg].graphMin<groupmin)\r
1059                          groupmin = aa[gg].graphMin;\r
1060                      }\r
1061 \r
1062                      for (int gg = 0; gg < aa.length; gg++)\r
1063                      {\r
1064                        if (aa[gg].graphGroup == row.graphGroup)\r
1065                        {\r
1066                          drawLineGraph(g, aa[gg], startRes, endRes, y,\r
1067                                        groupmin, groupmax,\r
1068                                        row.graphHeight);\r
1069                        }\r
1070                      }\r
1071 \r
1072                      graphGroupDrawn[ row.graphGroup ] = true;\r
1073                    }\r
1074                    else\r
1075                      drawLineGraph(g, row, startRes, endRes,\r
1076                                    y, row.graphMin, row.graphMax, row.graphHeight  );\r
1077                 }\r
1078                 else if(row.graph == AlignmentAnnotation.BAR_GRAPH )\r
1079                    drawBarGraph(g, row, startRes, endRes,\r
1080                                 row.graphMin, row.graphMax, y);\r
1081             }\r
1082 \r
1083             if (row.graph>0 && row.hasText)\r
1084             {\r
1085                 y += av.charHeight;\r
1086             }\r
1087 \r
1088             if (row.graph==0)\r
1089             {\r
1090                 y += aa[i].height;\r
1091             }\r
1092         }\r
1093     }\r
1094 \r
1095     public void drawLineGraph(Graphics g, AlignmentAnnotation aa,\r
1096                               int sRes, int eRes,\r
1097                               int y,\r
1098                               float min, float max,\r
1099                               int graphHeight)\r
1100     {\r
1101       if(sRes>aa.annotations.length)\r
1102         return;\r
1103 \r
1104 \r
1105       int x = 0;\r
1106 \r
1107       //Adjustment for fastpaint to left\r
1108       if(eRes<av.endRes)\r
1109         eRes++;\r
1110 \r
1111       eRes = Math.min(eRes, aa.annotations.length);\r
1112 \r
1113       if(sRes==0)\r
1114       {\r
1115         x++;\r
1116       }\r
1117 \r
1118       int y1=y, y2=y;\r
1119       float range = max - min;\r
1120 \r
1121       ////Draw origin\r
1122       if(min<0)\r
1123         y2 = y - (int)((0-min / range)*graphHeight);\r
1124 \r
1125       g.setColor(Color.gray);\r
1126       g.drawLine(x-av.charWidth,y2,(eRes-sRes+1)*av.charWidth,y2);\r
1127 \r
1128       eRes = Math.min(eRes, aa.annotations.length);\r
1129 \r
1130       int column;\r
1131       int aaMax = aa.annotations.length-1;\r
1132 \r
1133       while( x < eRes - sRes )\r
1134       {\r
1135         column = sRes + x;\r
1136         if(av.hasHiddenColumns)\r
1137         {\r
1138           column = av.getColumnSelection().adjustForHiddenColumns(column);\r
1139         }\r
1140 \r
1141         if (column > aaMax)\r
1142         {\r
1143           break;\r
1144         }\r
1145 \r
1146         if(aa.annotations[column]==null || aa.annotations[column-1]==null)\r
1147         {\r
1148           x++;\r
1149           continue;\r
1150         }\r
1151 \r
1152 \r
1153           g.setColor(aa.annotations[column].colour);\r
1154           y1 = y - (int) (((aa.annotations[column-1].value-min) / range) * graphHeight);\r
1155           y2 = y - (int) (((aa.annotations[column].value-min) / range) * graphHeight);\r
1156 \r
1157           g.drawLine(x*av.charWidth-av.charWidth/2, y1, x*av.charWidth+av.charWidth/2, y2);\r
1158           x ++;\r
1159        }\r
1160 \r
1161        if(aa.threshold!=null)\r
1162        {\r
1163            g.setColor(aa.threshold.colour);\r
1164            Graphics2D g2 = (Graphics2D)g;\r
1165            g2.setStroke(new BasicStroke(1,\r
1166                                          BasicStroke.CAP_SQUARE,\r
1167                                          BasicStroke.JOIN_ROUND, 3f,\r
1168                                          new float[] { 5f, 3f }, 0f));\r
1169 \r
1170            y2 = (int)(y - ((aa.threshold.value-min) / range)*graphHeight);\r
1171            g.drawLine(0,y2,(eRes-sRes)*av.charWidth,y2);\r
1172            g2.setStroke(new BasicStroke());\r
1173       }\r
1174     }\r
1175 \r
1176     public void drawBarGraph(Graphics g, AlignmentAnnotation aa,\r
1177                              int sRes, int eRes,\r
1178                              float min, float max,\r
1179                              int y)\r
1180     {\r
1181       if(sRes>aa.annotations.length)\r
1182         return;\r
1183 \r
1184       eRes = Math.min(eRes, aa.annotations.length);\r
1185 \r
1186       int x=0, y1=y, y2=y;\r
1187 \r
1188       float range = max - min;\r
1189 \r
1190       if(min<0)\r
1191         y2 = y - (int)((0-min / (range))*aa.graphHeight);\r
1192 \r
1193       g.setColor(Color.gray);\r
1194 \r
1195       g.drawLine(x,y2,(eRes-sRes)*av.charWidth,y2);\r
1196 \r
1197       int column;\r
1198       int aaMax = aa.annotations.length-1;\r
1199 \r
1200       while( x < eRes-sRes )\r
1201       {\r
1202         column = sRes + x;\r
1203         if(av.hasHiddenColumns)\r
1204         {\r
1205           column = av.getColumnSelection().adjustForHiddenColumns(column);\r
1206         }\r
1207 \r
1208         if(column > aaMax)\r
1209         {\r
1210             break;\r
1211         }\r
1212 \r
1213         if (aa.annotations[column] == null)\r
1214         {\r
1215           x ++;\r
1216           continue;\r
1217         }\r
1218 \r
1219           g.setColor(aa.annotations[column].colour);\r
1220           y1 = y - (int) (((aa.annotations[column].value-min) / (range)) * aa.graphHeight);\r
1221 \r
1222           if(y1-y2>0)\r
1223             g.fillRect(x*av.charWidth, y2, av.charWidth, y1-y2 );\r
1224           else\r
1225             g.fillRect(x*av.charWidth, y1, av.charWidth, y2-y1 );\r
1226 \r
1227           x ++ ;\r
1228 \r
1229       }\r
1230       if(aa.threshold!=null)\r
1231       {\r
1232           g.setColor(aa.threshold.colour);\r
1233           Graphics2D g2 = (Graphics2D)g;\r
1234           g2.setStroke(new BasicStroke(1,\r
1235                                         BasicStroke.CAP_SQUARE,\r
1236                                         BasicStroke.JOIN_ROUND, 3f,\r
1237                                         new float[] { 5f, 3f }, 0f));\r
1238 \r
1239           y2 = (int)(y - ((aa.threshold.value-min) / range)*aa.graphHeight);\r
1240           g.drawLine(0,y2,(eRes-sRes)*av.charWidth,y2);\r
1241           g2.setStroke(new BasicStroke());\r
1242       }\r
1243     }\r
1244 \r
1245     // used by overview window\r
1246     public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y, int sRes, int eRes)\r
1247     {\r
1248       eRes = Math.min(eRes, aa.annotations.length);\r
1249       g.setColor(Color.white);\r
1250       g.fillRect(0, 0, width, y);\r
1251       g.setColor(new Color(0, 0, 180));\r
1252 \r
1253       int x = 0, height;\r
1254 \r
1255       for (int j = sRes; j < eRes; j++)\r
1256       {\r
1257         if (aa.annotations[j] != null)\r
1258         {\r
1259           g.setColor(aa.annotations[j].colour);\r
1260 \r
1261           height = (int) ( (aa.annotations[j].value / aa.graphMax) * y);\r
1262           if (height > y)\r
1263             height = y;\r
1264 \r
1265           g.fillRect(x, y - height, av.charWidth, height);\r
1266         }\r
1267           x += av.charWidth;\r
1268       }\r
1269     }\r
1270 \r
1271 }\r