c9fa597987f80ad288aec7172c47950d925ae829
[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 != null\r
826             && (row.annotations[column].displayCharacter.length() > 0))\r
827         {\r
828 \r
829           int charOffset = (av.charWidth -\r
830                             fm.charWidth(row.annotations[column].\r
831                                          displayCharacter.charAt(\r
832                                              0))) / 2;\r
833 \r
834           if (row.annotations[column].colour == null)\r
835             g.setColor(Color.black);\r
836           else\r
837             g.setColor(row.annotations[column].colour);\r
838 \r
839           if (column == 0 || row.graph > 0)\r
840           {\r
841             g.drawString(row.annotations[column].displayCharacter,\r
842                          (x * av.charWidth) + charOffset,\r
843                          y + iconOffset);\r
844           }\r
845           else if (\r
846               row.annotations[column - 1] == null\r
847               || (!row.annotations[column].displayCharacter.equals(\r
848                   row.annotations[column - 1].displayCharacter)\r
849                   ||\r
850                   (row.annotations[column].displayCharacter.length() < 2 &&\r
851                    row.annotations[column].secondaryStructure == ' ')))\r
852           {\r
853             g.drawString(row.annotations[column].displayCharacter,\r
854                          x * av.charWidth + charOffset,\r
855                          y + iconOffset);\r
856           }\r
857         }\r
858 \r
859         if (row.hasIcons)\r
860         {\r
861           if (!validRes ||\r
862               (row.annotations[column].secondaryStructure != lastSS))\r
863           {\r
864             switch (lastSS)\r
865             {\r
866               case 'H':\r
867                 g.setColor(HELIX_COLOUR);\r
868                 if (MAC)\r
869                 {\r
870                   //Off by 1 offset when drawing rects and ovals\r
871                   //to offscreen image on the MAC\r
872                   g.fillRoundRect(lastSSX, y + 4 + iconOffset,\r
873                                   (x * av.charWidth) - lastSSX, 7, 8, 8);\r
874                   break;\r
875                 }\r
876 \r
877                 int sCol = (lastSSX / av.charWidth) + startRes;\r
878                 int x1 = lastSSX;\r
879                 int x2 = (x * av.charWidth);\r
880 \r
881                 if (sCol == 0 ||\r
882                     row.annotations[sCol - 1] == null ||\r
883                     row.annotations[sCol - 1].secondaryStructure != 'H')\r
884                 {\r
885                   g.fillArc(lastSSX, y + 4 + iconOffset, av.charWidth, 8, 90,\r
886                             180);\r
887                   x1 += av.charWidth / 2;\r
888                 }\r
889 \r
890                 if (row.annotations[column] == null ||\r
891                     row.annotations[column].secondaryStructure != 'H')\r
892                 {\r
893                   g.fillArc( (x * av.charWidth) - av.charWidth,\r
894                             y + 4 + iconOffset, av.charWidth, 8, 270, 180);\r
895                   x2 -= av.charWidth / 2;\r
896                 }\r
897 \r
898                 g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);\r
899                 break;\r
900 \r
901               case 'E':\r
902                 g.setColor(SHEET_COLOUR);\r
903                 g.fillRect(lastSSX, y + 4 + iconOffset,\r
904                            (x * av.charWidth) - lastSSX - 4, 7);\r
905                 g.fillPolygon(new int[]\r
906                               { (x * av.charWidth) - 4,\r
907                               (x * av.charWidth) - 4,\r
908                               (x * av.charWidth)},\r
909                               new int[]\r
910                               {\r
911                               y + iconOffset, y + 14 + iconOffset,\r
912                               y + 8 + iconOffset\r
913                 }, 3);\r
914 \r
915                 break;\r
916 \r
917               default:\r
918                 g.setColor(Color.gray);\r
919                 g.fillRect(lastSSX, y + 6 + iconOffset,\r
920                            (x * av.charWidth) - lastSSX, 2);\r
921 \r
922                 break;\r
923             }\r
924 \r
925             if (validRes)\r
926             {\r
927               lastSS = row.annotations[column].secondaryStructure;\r
928             }\r
929             else\r
930             {\r
931               lastSS = ' ';\r
932             }\r
933 \r
934             lastSSX = (x * av.charWidth);\r
935           }\r
936         }\r
937 \r
938         column++;\r
939         x++;\r
940       }\r
941 \r
942       if (column >= row.annotations.length)\r
943       {\r
944         column = row.annotations.length - 1;\r
945       }\r
946 \r
947       //  x ++;\r
948 \r
949       if (row.hasIcons)\r
950       {\r
951         switch (lastSS)\r
952         {\r
953           case 'H':\r
954             g.setColor(HELIX_COLOUR);\r
955             if (MAC)\r
956             {\r
957               //Off by 1 offset when drawing rects and ovals\r
958               //to offscreen image on the MAC\r
959               g.fillRoundRect(lastSSX, y + 4 + iconOffset,\r
960                               (x * av.charWidth) - lastSSX, 7, 8, 8);\r
961               break;\r
962             }\r
963 \r
964             int sCol = (lastSSX / av.charWidth) + startRes;\r
965             int x1 = lastSSX;\r
966             int x2 = (x * av.charWidth);\r
967 \r
968             if (sCol == 0 ||\r
969                 row.annotations[sCol - 1] == null ||\r
970                 row.annotations[sCol - 1].secondaryStructure != 'H')\r
971             {\r
972               g.fillArc(lastSSX, y + 4 + iconOffset, av.charWidth, 8, 90, 180);\r
973               x1 += av.charWidth / 2;\r
974             }\r
975 \r
976             if (row.annotations[column] == null ||\r
977                 row.annotations[column].secondaryStructure != 'H')\r
978             {\r
979               g.fillArc( (x * av.charWidth) - av.charWidth,\r
980                         y + 4 + iconOffset, av.charWidth, 8, 270,\r
981                         180);\r
982               x2 -= av.charWidth / 2;\r
983             }\r
984 \r
985             g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);\r
986 \r
987             break;\r
988 \r
989           case 'E':\r
990             g.setColor(SHEET_COLOUR);\r
991 \r
992             if (row.annotations[endRes] == null\r
993                 || row.annotations[endRes].secondaryStructure != 'E')\r
994             {\r
995               g.fillRect(lastSSX, y + 4 + iconOffset,\r
996                          (x * av.charWidth) - lastSSX - 4, 7);\r
997               g.fillPolygon(new int[]\r
998                             { (x * av.charWidth) - 4,\r
999                             (x * av.charWidth) - 4,\r
1000                             (x * av.charWidth)},\r
1001                             new int[]\r
1002                             {\r
1003                             y + iconOffset, y + 14 + iconOffset,\r
1004                             y + 7 + iconOffset\r
1005               }, 3);\r
1006             }\r
1007             else\r
1008             {\r
1009               g.fillRect(lastSSX, y + 4 + iconOffset,\r
1010                          (x + 1) * av.charWidth - lastSSX, 7);\r
1011             }\r
1012             break;\r
1013 \r
1014           default:\r
1015             g.setColor(Color.gray);\r
1016             g.fillRect(lastSSX, y + 6 + iconOffset,\r
1017                        (x * av.charWidth) - lastSSX, 2);\r
1018 \r
1019             break;\r
1020         }\r
1021       }\r
1022 \r
1023       if (row.graph > 0 && row.graphHeight > 0)\r
1024       {\r
1025         if (row.graph == AlignmentAnnotation.LINE_GRAPH)\r
1026         {\r
1027           if (row.graphGroup > -1 && !graphGroupDrawn[row.graphGroup])\r
1028           {\r
1029             float groupmax = -999999, groupmin = 9999999;\r
1030             for (int gg = 0; gg < aa.length; gg++)\r
1031             {\r
1032               if (aa[gg].graphGroup != row.graphGroup)\r
1033               {\r
1034                 continue;\r
1035               }\r
1036 \r
1037               if (aa[gg] != row)\r
1038               {\r
1039                 aa[gg].visible = false;\r
1040               }\r
1041 \r
1042               if (aa[gg].graphMax > groupmax)\r
1043               {\r
1044                 groupmax = aa[gg].graphMax;\r
1045               }\r
1046               if (aa[gg].graphMin < groupmin)\r
1047               {\r
1048                 groupmin = aa[gg].graphMin;\r
1049               }\r
1050             }\r
1051 \r
1052             for (int gg = 0; gg < aa.length; gg++)\r
1053             {\r
1054               if (aa[gg].graphGroup == row.graphGroup)\r
1055               {\r
1056                 drawLineGraph(g, aa[gg], startRes, endRes, y,\r
1057                               groupmin, groupmax,\r
1058                               row.graphHeight);\r
1059               }\r
1060             }\r
1061 \r
1062             graphGroupDrawn[row.graphGroup] = true;\r
1063           }\r
1064           else\r
1065           {\r
1066             drawLineGraph(g, row, startRes, endRes,\r
1067                           y, row.graphMin, row.graphMax, row.graphHeight);\r
1068           }\r
1069         }\r
1070         else if (row.graph == AlignmentAnnotation.BAR_GRAPH)\r
1071         {\r
1072           drawBarGraph(g, row, startRes, endRes,\r
1073                        row.graphMin, row.graphMax, y);\r
1074         }\r
1075       }\r
1076 \r
1077       if (row.graph > 0 && row.hasText)\r
1078       {\r
1079         y += av.charHeight;\r
1080       }\r
1081 \r
1082       if (row.graph == 0)\r
1083       {\r
1084         y += aa[i].height;\r
1085       }\r
1086     }\r
1087   }\r
1088 \r
1089   public void drawLineGraph(Graphics g, AlignmentAnnotation aa,\r
1090                             int sRes, int eRes,\r
1091                             int y,\r
1092                             float min, float max,\r
1093                             int graphHeight)\r
1094   {\r
1095     if (sRes > aa.annotations.length)\r
1096     {\r
1097       return;\r
1098     }\r
1099 \r
1100     int x = 0;\r
1101 \r
1102     //Adjustment for fastpaint to left\r
1103     if (eRes < av.endRes)\r
1104     {\r
1105       eRes++;\r
1106     }\r
1107 \r
1108     eRes = Math.min(eRes, aa.annotations.length);\r
1109 \r
1110     if (sRes == 0)\r
1111     {\r
1112       x++;\r
1113     }\r
1114 \r
1115     int y1 = y, y2 = y;\r
1116     float range = max - min;\r
1117 \r
1118     ////Draw origin\r
1119     if (min < 0)\r
1120     {\r
1121       y2 = y - (int) ( (0 - min / range) * graphHeight);\r
1122     }\r
1123 \r
1124     g.setColor(Color.gray);\r
1125     g.drawLine(x - av.charWidth, y2, (eRes - sRes + 1) * av.charWidth, y2);\r
1126 \r
1127     eRes = Math.min(eRes, aa.annotations.length);\r
1128 \r
1129     int column;\r
1130     int aaMax = aa.annotations.length - 1;\r
1131 \r
1132     while (x < eRes - sRes)\r
1133     {\r
1134       column = sRes + x;\r
1135       if (av.hasHiddenColumns)\r
1136       {\r
1137         column = av.getColumnSelection().adjustForHiddenColumns(column);\r
1138       }\r
1139 \r
1140       if (column > aaMax)\r
1141       {\r
1142         break;\r
1143       }\r
1144 \r
1145       if (aa.annotations[column] == null || aa.annotations[column - 1] == null)\r
1146       {\r
1147         x++;\r
1148         continue;\r
1149       }\r
1150 \r
1151       if (aa.annotations[column].colour == null)\r
1152         g.setColor(Color.black);\r
1153       else\r
1154         g.setColor(aa.annotations[column].colour);\r
1155 \r
1156       y1 = y -\r
1157           (int) ( ( (aa.annotations[column - 1].value - min) / range) * graphHeight);\r
1158       y2 = y -\r
1159           (int) ( ( (aa.annotations[column].value - min) / range) * graphHeight);\r
1160 \r
1161       g.drawLine(x * av.charWidth - av.charWidth / 2, y1,\r
1162                  x * av.charWidth + av.charWidth / 2, y2);\r
1163       x++;\r
1164     }\r
1165 \r
1166     if (aa.threshold != null)\r
1167     {\r
1168       g.setColor(aa.threshold.colour);\r
1169       Graphics2D g2 = (Graphics2D) g;\r
1170       g2.setStroke(new BasicStroke(1,\r
1171                                    BasicStroke.CAP_SQUARE,\r
1172                                    BasicStroke.JOIN_ROUND, 3f,\r
1173                                    new float[]\r
1174                                    {5f, 3f}, 0f));\r
1175 \r
1176       y2 = (int) (y - ( (aa.threshold.value - min) / range) * graphHeight);\r
1177       g.drawLine(0, y2, (eRes - sRes) * av.charWidth, y2);\r
1178       g2.setStroke(new BasicStroke());\r
1179     }\r
1180   }\r
1181 \r
1182   public void drawBarGraph(Graphics g, AlignmentAnnotation aa,\r
1183                            int sRes, int eRes,\r
1184                            float min, float max,\r
1185                            int y)\r
1186   {\r
1187     if (sRes > aa.annotations.length)\r
1188     {\r
1189       return;\r
1190     }\r
1191 \r
1192     eRes = Math.min(eRes, aa.annotations.length);\r
1193 \r
1194     int x = 0, y1 = y, y2 = y;\r
1195 \r
1196     float range = max - min;\r
1197 \r
1198     if (min < 0)\r
1199     {\r
1200       y2 = y - (int) ( (0 - min / (range)) * aa.graphHeight);\r
1201     }\r
1202 \r
1203     g.setColor(Color.gray);\r
1204 \r
1205     g.drawLine(x, y2, (eRes - sRes) * av.charWidth, y2);\r
1206 \r
1207     int column;\r
1208     int aaMax = aa.annotations.length - 1;\r
1209 \r
1210     while (x < eRes - sRes)\r
1211     {\r
1212       column = sRes + x;\r
1213       if (av.hasHiddenColumns)\r
1214       {\r
1215         column = av.getColumnSelection().adjustForHiddenColumns(column);\r
1216       }\r
1217 \r
1218       if (column > aaMax)\r
1219       {\r
1220         break;\r
1221       }\r
1222 \r
1223       if (aa.annotations[column] == null)\r
1224       {\r
1225         x++;\r
1226         continue;\r
1227       }\r
1228 \r
1229       if (aa.annotations[column].colour == null)\r
1230         g.setColor(Color.black);\r
1231       else\r
1232         g.setColor(aa.annotations[column].colour);\r
1233 \r
1234       y1 = y -\r
1235           (int) ( ( (aa.annotations[column].value - min) / (range)) * aa.graphHeight);\r
1236 \r
1237       if (y1 - y2 > 0)\r
1238       {\r
1239         g.fillRect(x * av.charWidth, y2, av.charWidth, y1 - y2);\r
1240       }\r
1241       else\r
1242       {\r
1243         g.fillRect(x * av.charWidth, y1, av.charWidth, y2 - y1);\r
1244       }\r
1245 \r
1246       x++;\r
1247 \r
1248     }\r
1249     if (aa.threshold != null)\r
1250     {\r
1251       g.setColor(aa.threshold.colour);\r
1252       Graphics2D g2 = (Graphics2D) g;\r
1253       g2.setStroke(new BasicStroke(1,\r
1254                                    BasicStroke.CAP_SQUARE,\r
1255                                    BasicStroke.JOIN_ROUND, 3f,\r
1256                                    new float[]\r
1257                                    {5f, 3f}, 0f));\r
1258 \r
1259       y2 = (int) (y - ( (aa.threshold.value - min) / range) * aa.graphHeight);\r
1260       g.drawLine(0, y2, (eRes - sRes) * av.charWidth, y2);\r
1261       g2.setStroke(new BasicStroke());\r
1262     }\r
1263   }\r
1264 \r
1265   // used by overview window\r
1266   public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y,\r
1267                         int sRes, int eRes)\r
1268   {\r
1269     eRes = Math.min(eRes, aa.annotations.length);\r
1270     g.setColor(Color.white);\r
1271     g.fillRect(0, 0, width, y);\r
1272     g.setColor(new Color(0, 0, 180));\r
1273 \r
1274     int x = 0, height;\r
1275 \r
1276     for (int j = sRes; j < eRes; j++)\r
1277     {\r
1278       if (aa.annotations[j] != null)\r
1279       {\r
1280         if (aa.annotations[j].colour == null)\r
1281           g.setColor(Color.black);\r
1282         else\r
1283           g.setColor(aa.annotations[j].colour);\r
1284 \r
1285         height = (int) ( (aa.annotations[j].value / aa.graphMax) * y);\r
1286         if (height > y)\r
1287         {\r
1288           height = y;\r
1289         }\r
1290 \r
1291         g.fillRect(x, y - height, av.charWidth, height);\r
1292       }\r
1293       x += av.charWidth;\r
1294     }\r
1295   }\r
1296 \r
1297 }\r