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