Set PDBViewer
[jalview.git] / src / jalview / gui / SeqCanvas.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 package jalview.gui;\r
20 \r
21 import jalview.datamodel.*;\r
22 \r
23 import java.awt.*;\r
24 import java.awt.image.*;\r
25 \r
26 import javax.swing.*;\r
27 import jalview.schemes.*;\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 SeqCanvas extends JComponent\r
37 {\r
38     FeatureRenderer fr;\r
39     SequenceRenderer sr;\r
40     BufferedImage img;\r
41     Graphics2D gg;\r
42     int imgWidth;\r
43     int imgHeight;\r
44     AlignViewport av;\r
45     boolean displaySearch = false;\r
46     int[] searchResults = null;\r
47     boolean fastPaint = false;\r
48     int LABEL_WEST;\r
49     int LABEL_EAST;\r
50 \r
51     boolean isOverview = false;\r
52 \r
53     /**\r
54      * Creates a new SeqCanvas object.\r
55      *\r
56      * @param av DOCUMENT ME!\r
57      */\r
58     public SeqCanvas(AlignViewport av)\r
59     {\r
60         this.av = av;\r
61         fr = new FeatureRenderer(av);\r
62         sr = new SequenceRenderer(av);\r
63         setLayout(new BorderLayout());\r
64         PaintRefresher.Register(this, av.alignment);\r
65         setBackground(Color.white);\r
66     }\r
67 \r
68     MCview.PDBCanvas pdbViewer;\r
69     public SequenceRenderer getSequenceRenderer()\r
70     {\r
71       return sr;\r
72     }\r
73 \r
74     public FeatureRenderer getFeatureRenderer()\r
75     {\r
76       return fr;\r
77     }\r
78 \r
79     public void setPDBViewer(MCview.PDBCanvas pc)\r
80     {\r
81       pdbViewer = pc;\r
82     }\r
83 \r
84     /**\r
85      * DOCUMENT ME!\r
86      *\r
87      * @param g DOCUMENT ME!\r
88      * @param startx DOCUMENT ME!\r
89      * @param endx DOCUMENT ME!\r
90      * @param ypos DOCUMENT ME!\r
91      */\r
92     void drawNorthScale(Graphics g, int startx, int endx, int ypos)\r
93     {\r
94         int scalestartx = startx - (startx % 10) + 10;\r
95 \r
96         g.setColor(Color.black);\r
97 \r
98         // NORTH SCALE\r
99         for (int i = scalestartx; i < endx; i += 10)\r
100         {\r
101             String string = String.valueOf(i);\r
102             g.drawString(string, (i - startx - 1) * av.charWidth,\r
103                 ypos - (av.charHeight / 2));\r
104 \r
105             g.drawLine(((i - startx - 1) * av.charWidth) + (av.charWidth / 2),\r
106                 (ypos + 2) - (av.charHeight / 2),\r
107                 ((i - startx - 1) * av.charWidth) + (av.charWidth / 2), ypos -\r
108                 2);\r
109         }\r
110     }\r
111 \r
112     /**\r
113      * DOCUMENT ME!\r
114      *\r
115      * @param g DOCUMENT ME!\r
116      * @param startx DOCUMENT ME!\r
117      * @param endx DOCUMENT ME!\r
118      * @param ypos DOCUMENT ME!\r
119      */\r
120     void drawWestScale(Graphics g, int startx, int endx, int ypos)\r
121     {\r
122         FontMetrics fm = getFontMetrics(av.getFont());\r
123         ypos += av.charHeight;\r
124 \r
125         // EAST SCALE\r
126         for (int i = 0; i < av.alignment.getHeight(); i++)\r
127         {\r
128             SequenceI seq = av.alignment.getSequenceAt(i);\r
129             int index = startx;\r
130             int value = -1;\r
131 \r
132             while (index < endx)\r
133             {\r
134                 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))\r
135                 {\r
136                     index++;\r
137 \r
138                     continue;\r
139                 }\r
140 \r
141                 value = av.alignment.getSequenceAt(i).findPosition(index);\r
142 \r
143                 break;\r
144             }\r
145 \r
146             if (value != -1)\r
147             {\r
148                 int x = LABEL_WEST - fm.stringWidth(String.valueOf(value))-av.charWidth/2;\r
149                 g.drawString(value + "", x,\r
150                     (ypos + (i * av.charHeight)) - (av.charHeight / 5));\r
151             }\r
152         }\r
153     }\r
154 \r
155     /**\r
156      * DOCUMENT ME!\r
157      *\r
158      * @param g DOCUMENT ME!\r
159      * @param startx DOCUMENT ME!\r
160      * @param endx DOCUMENT ME!\r
161      * @param ypos DOCUMENT ME!\r
162      */\r
163     void drawEastScale(Graphics g, int startx, int endx, int ypos)\r
164     {\r
165         ypos += av.charHeight;\r
166 \r
167         // EAST SCALE\r
168         for (int i = 0; i < av.alignment.getHeight(); i++)\r
169         {\r
170             SequenceI seq = av.alignment.getSequenceAt(i);\r
171             int index = endx;\r
172             int value = -1;\r
173 \r
174             while (index > startx)\r
175             {\r
176                 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))\r
177                 {\r
178                     index--;\r
179 \r
180                     continue;\r
181                 }\r
182 \r
183                 value = av.alignment.getSequenceAt(i).findPosition(index);\r
184 \r
185                 break;\r
186             }\r
187 \r
188             if (value != -1)\r
189             {\r
190                 g.drawString(String.valueOf(value), av.charWidth/2,\r
191                     (ypos + (i * av.charHeight)) - (av.charHeight / 5));\r
192             }\r
193         }\r
194     }\r
195 \r
196     /**\r
197      * DOCUMENT ME!\r
198      *\r
199      * @param horizontal DOCUMENT ME!\r
200      * @param vertical DOCUMENT ME!\r
201      */\r
202     public void fastPaint(int horizontal, int vertical)\r
203     {\r
204         if (gg == null)\r
205         {\r
206             return;\r
207         }\r
208 \r
209         gg.copyArea(horizontal * av.charWidth,\r
210                     vertical * av.charHeight,\r
211                     imgWidth,\r
212                     imgHeight,\r
213                     -horizontal * av.charWidth,\r
214                     -vertical * av.charHeight);\r
215 \r
216         int sr = av.startRes;\r
217         int er = av.endRes;\r
218         int ss = av.startSeq;\r
219         int es = av.endSeq;\r
220         int transX = 0;\r
221         int transY = 0;\r
222 \r
223         if (horizontal > 0) // scrollbar pulled right, image to the left\r
224         {\r
225             er ++;\r
226             transX = (er - sr - horizontal) * av.charWidth;\r
227             sr = er - horizontal;\r
228         }\r
229         else if (horizontal < 0)\r
230         {\r
231             er = sr - horizontal-1;\r
232         }\r
233         else if (vertical > 0) // scroll down\r
234         {\r
235             ss = es - vertical;\r
236 \r
237             if (ss < av.startSeq)\r
238             { // ie scrolling too fast, more than a page at a time\r
239                 ss = av.startSeq;\r
240             }\r
241             else\r
242             {\r
243                 transY = imgHeight - (vertical * av.charHeight);\r
244             }\r
245         }\r
246         else if (vertical < 0)\r
247         {\r
248             es = ss - vertical;\r
249 \r
250             if (es > av.endSeq)\r
251             {\r
252                 es = av.endSeq;\r
253             }\r
254         }\r
255 \r
256         gg.translate(transX, transY);\r
257         drawPanel(gg, sr, er, ss, es, sr, ss, 0);\r
258         gg.translate(-transX, -transY);\r
259 \r
260         fastPaint = true;\r
261         repaint();\r
262     }\r
263 \r
264     /**\r
265      * Definitions of startx and endx (hopefully):\r
266      * SMJS This is what I'm working towards!\r
267      *   startx is the first residue (starting at 0) to display.\r
268      *   endx   is the last residue to display (starting at 0).\r
269      *   starty is the first sequence to display (starting at 0).\r
270      *   endy   is the last sequence to display (starting at 0).\r
271      * NOTE 1: The av limits are set in setFont in this class and\r
272      * in the adjustment listener in SeqPanel when the scrollbars move.\r
273      */\r
274 \r
275     // Set this to false to force a full panel paint\r
276     public void paintComponent(Graphics g)\r
277     {\r
278         sr.renderGaps(av.renderGaps);\r
279 \r
280         if ((img != null) &&\r
281                 (fastPaint || (getWidth() != g.getClipBounds().width) ||\r
282                 (getHeight() != g.getClipBounds().height)))\r
283         {\r
284             g.drawImage(img, 0, 0, this);\r
285             fastPaint = false;\r
286             return;\r
287         }\r
288 \r
289         // this draws the whole of the alignment\r
290         imgWidth = getWidth();\r
291         imgHeight = getHeight();\r
292 \r
293         imgWidth -= (imgWidth % av.charWidth);\r
294         imgHeight -= (imgHeight % av.charHeight);\r
295 \r
296         if ((imgWidth < 1) || (imgHeight < 1))\r
297         {\r
298             return;\r
299         }\r
300 \r
301 \r
302         img = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);\r
303         gg = (Graphics2D) img.getGraphics();\r
304         gg.setFont(av.getFont());\r
305         gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
306           RenderingHints.VALUE_ANTIALIAS_ON);\r
307 \r
308         gg.setColor(Color.white);\r
309         gg.fillRect(0, 0, imgWidth, imgHeight);\r
310 \r
311 \r
312         if (av.getWrapAlignment())\r
313         {\r
314             drawWrappedPanel(gg, getWidth(), getHeight(), av.startRes);\r
315         }\r
316         else\r
317         {\r
318             drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq,\r
319                 av.startRes, av.startSeq, 0);\r
320         }\r
321 \r
322         g.drawImage(img, 0, 0, this);\r
323 \r
324         if (pdbViewer != null)\r
325         {\r
326           pdbViewer.updateSeqColours();\r
327         }\r
328 \r
329     }\r
330 \r
331     /**\r
332      * DOCUMENT ME!\r
333      *\r
334      * @param cwidth DOCUMENT ME!\r
335      *\r
336      * @return DOCUMENT ME!\r
337      */\r
338     public int getWrappedCanvasWidth(int cwidth)\r
339     {\r
340         FontMetrics fm = getFontMetrics(av.getFont());\r
341 \r
342         LABEL_EAST = 0;\r
343         LABEL_WEST = 0;\r
344 \r
345         if (av.scaleRightWrapped)\r
346         {\r
347             LABEL_EAST = fm.stringWidth(getMask()+"0");\r
348         }\r
349 \r
350         if (av.scaleLeftWrapped)\r
351         {\r
352             LABEL_WEST = fm.stringWidth(getMask());\r
353         }\r
354 \r
355         return (cwidth - LABEL_EAST - LABEL_WEST) / av.charWidth;\r
356     }\r
357 \r
358 \r
359     /**\r
360      * Generates a string of zeroes.\r
361      * @return String\r
362      */\r
363     String getMask()\r
364     {\r
365       String mask = "0";\r
366       for (int i = av.alignment.getWidth(); i > 0; i /= 10)\r
367       {\r
368         mask += "0";\r
369       }\r
370       return mask;\r
371     }\r
372 \r
373     /**\r
374      * DOCUMENT ME!\r
375      *\r
376      * @param g DOCUMENT ME!\r
377      * @param canvasWidth DOCUMENT ME!\r
378      * @param canvasHeight DOCUMENT ME!\r
379      * @param startRes DOCUMENT ME!\r
380      */\r
381     public void drawWrappedPanel(Graphics g, int canvasWidth, int canvasHeight,\r
382         int startRes)\r
383     {\r
384 \r
385         AlignmentI al = av.getAlignment();\r
386 \r
387         FontMetrics fm = getFontMetrics(av.getFont());\r
388 \r
389         int LABEL_EAST = 0;\r
390 \r
391         if (av.scaleRightWrapped)\r
392         {\r
393             LABEL_EAST = fm.stringWidth(getMask()+"0");\r
394         }\r
395 \r
396         int LABEL_WEST = 0;\r
397 \r
398         if (av.scaleLeftWrapped)\r
399         {\r
400             LABEL_WEST = fm.stringWidth(getMask());\r
401         }\r
402 \r
403         int hgap = av.charHeight;\r
404         if(av.scaleAboveWrapped)\r
405           hgap += av.charHeight;\r
406 \r
407         int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / av.charWidth;\r
408         int cHeight = av.getAlignment().getHeight() * av.charHeight;\r
409 \r
410         av.setWrappedWidth(cWidth);\r
411 \r
412         av.endRes = av.startRes + cWidth;\r
413 \r
414 \r
415         int endx = (startRes + cWidth) - 1;\r
416         int ypos = hgap;\r
417 \r
418 \r
419         while ((ypos <= canvasHeight) && (startRes < av.alignment.getWidth()))\r
420         {\r
421             g.setFont(av.getFont());\r
422             g.setColor(Color.black);\r
423 \r
424             if (av.scaleLeftWrapped)\r
425             {\r
426                 drawWestScale(g, startRes, endx, ypos);\r
427             }\r
428 \r
429             if (av.scaleRightWrapped)\r
430             {\r
431                 g.translate(canvasWidth - LABEL_EAST, 0);\r
432                 drawEastScale(g, startRes, endx, ypos);\r
433                 g.translate(-(canvasWidth - LABEL_EAST), 0);\r
434             }\r
435 \r
436             g.translate(LABEL_WEST, 0);\r
437 \r
438             if (av.scaleAboveWrapped)\r
439             {\r
440                 drawNorthScale(g, startRes, endx, ypos);\r
441             }\r
442 \r
443             // When printing we have an extra clipped region,\r
444             // the Printable page which we need to account for here\r
445             Shape clip = g.getClip();\r
446 \r
447             if (clip == null)\r
448             {\r
449                 g.setClip(0, 0, cWidth * av.charWidth, canvasHeight);\r
450             }\r
451             else\r
452             {\r
453                 g.setClip(0, (int) clip.getBounds().getY(),\r
454                     cWidth * av.charWidth, (int) clip.getBounds().getHeight());\r
455             }\r
456 \r
457             if (av.vconsensus!=null && av.alignment.getWidth() >= av.vconsensus.size())\r
458             {\r
459               endx = av.vconsensus.size() - 2;\r
460             }\r
461 \r
462 \r
463             drawPanel(g, startRes, endx, 0, al.getHeight(), startRes, 0, ypos);\r
464 \r
465             if(av.showAnnotation)\r
466             {\r
467               g.translate(0, cHeight + ypos + 3);\r
468               if(annotations==null)\r
469                 annotations = new AnnotationPanel(av);\r
470 \r
471               annotations.drawComponent( (Graphics2D) g, startRes, endx + 1);\r
472               g.translate(0, -cHeight - ypos);\r
473             }\r
474             g.setClip(clip);\r
475             g.translate(-LABEL_WEST, 0);\r
476 \r
477             ypos += cHeight+getAnnotationHeight()+hgap;\r
478             if(av.showAnnotation)\r
479               ypos -= 3;\r
480 \r
481             startRes += cWidth;\r
482             endx = (startRes + cWidth) - 1;\r
483 \r
484             if (endx > al.getWidth())\r
485             {\r
486                 endx = al.getWidth();\r
487             }\r
488         }\r
489     }\r
490 \r
491     AnnotationPanel annotations;\r
492     int getAnnotationHeight()\r
493     {\r
494       if(!av.showAnnotation)\r
495         return 0;\r
496 \r
497       if(annotations==null)\r
498         annotations = new AnnotationPanel(av);\r
499 \r
500       return annotations.adjustPanelHeight();\r
501     }\r
502 \r
503     /**\r
504      * DOCUMENT ME!\r
505      *\r
506      * @param g1 DOCUMENT ME!\r
507      * @param x1 DOCUMENT ME!\r
508      * @param x2 DOCUMENT ME!\r
509      * @param y1 DOCUMENT ME!\r
510      * @param y2 DOCUMENT ME!\r
511      * @param startx DOCUMENT ME!\r
512      * @param starty DOCUMENT ME!\r
513      * @param offset DOCUMENT ME!\r
514      */\r
515 \r
516     float aaRatio = 2f/3f;\r
517     public void increaseAARatio()\r
518     {\r
519       aaRatio += .025;\r
520       if(aaRatio>1)\r
521         aaRatio = 1;\r
522 \r
523       repaint();\r
524     }\r
525 \r
526     public void decreaseAARation()\r
527     {\r
528       aaRatio -= .025;\r
529       if(aaRatio<0)\r
530         aaRatio = 0;\r
531 \r
532       repaint();\r
533     }\r
534 \r
535 \r
536     synchronized public void drawPanel(Graphics g1, int x1, int x2, int y1,\r
537         int y2, int startx, int starty, int offset)\r
538     {\r
539       Graphics2D g = (Graphics2D) g1;\r
540       g.setFont(av.getFont());\r
541 \r
542       SequenceI nextSeq, dna = null;\r
543       int aaHeight = av.charHeight, dnaHeight = av.charHeight;\r
544       Font dnafont = null, aafont = av.getFont();\r
545 \r
546  /*     if (av.getShowTranslation())\r
547       {\r
548         aaHeight = (int) (av.getCharHeight() * aaRatio);\r
549         dnaHeight = (int) (av.getCharHeight() * (1 - aaRatio));\r
550         java.awt.geom.AffineTransform transform = new java.awt.geom.AffineTransform();\r
551         transform.scale(1f / 3f, 1);\r
552         dnafont = new Font(av.getFont().getName(), av.getFont().getStyle(),\r
553                                 dnaHeight);\r
554         dnafont = dnafont.deriveFont(transform);\r
555 \r
556         aafont = new Font(av.getFont().getName(), av.getFont().getStyle(),\r
557                                aaHeight);\r
558         transform = new java.awt.geom.AffineTransform();\r
559         transform.scale(1 / aaRatio, 1);\r
560         aafont = aafont.deriveFont(transform);\r
561       }\r
562 */\r
563 \r
564       ColourSchemeI cs = av.getGlobalColourScheme();\r
565 \r
566         /// First draw the sequences\r
567         /////////////////////////////\r
568         for (int i = y1; i < y2; i++)\r
569         {\r
570             nextSeq = av.alignment.getSequenceAt(i);\r
571             g.setFont(aafont);\r
572          /*   if(av.getShowTranslation())\r
573             {\r
574               dna = nextSeq;\r
575               StringBuffer sb = new StringBuffer();\r
576               for(int r = 0; r<nextSeq.getLength(); r+=3)\r
577               {\r
578                 String codon = nextSeq.getSequence(r, r+3);\r
579                 codon = codon.replace('U', 'T');\r
580                 String res = ResidueProperties.codonTranslate(codon);\r
581                 if(res !=null )\r
582                 {\r
583                   if (res.equals("STOP"))\r
584                     sb.append("X");\r
585                   else\r
586                     sb.append(res);\r
587                 }\r
588               }\r
589               nextSeq = new Sequence("d", sb.toString());\r
590             }*/\r
591 \r
592             sr.drawSequence(g, nextSeq, av.alignment.findAllGroups(nextSeq),\r
593                             x1, x2, (x1 - startx) * av.charWidth,\r
594                             offset + ( (i - starty) * av.charHeight), av.charWidth,\r
595                             aaHeight);\r
596 \r
597          /*   if(av.getShowTranslation())\r
598             {\r
599               av.setGlobalColourScheme(new NucleotideColourScheme());\r
600               g.setFont(dnafont);\r
601               sr.drawSequence(g, dna, null,\r
602                               x1*3, (x2+2) * 3, ( (x1 - startx) * av.charWidth) / 3,\r
603                               offset + ( (i - starty) * av.charHeight) + aaHeight,\r
604                               av.charWidth / 3,\r
605                               dnaHeight);\r
606               av.setGlobalColourScheme(cs);\r
607             }*/\r
608 \r
609             if (av.showSequenceFeatures)\r
610             {\r
611                 fr.drawSequence(g, nextSeq, x1, x2,\r
612                     (x1 - startx) * av.charWidth,\r
613                     offset + ((i - starty) * av.charHeight), av.charWidth,\r
614                     av.charHeight);\r
615             }\r
616         }\r
617 \r
618         //\r
619         /////////////////////////////////////\r
620         // Now outline any areas if necessary\r
621         /////////////////////////////////////\r
622         SequenceGroup group = av.getSelectionGroup();\r
623 \r
624         int sx = -1;\r
625         int sy = -1;\r
626         int ex = -1;\r
627         int groupIndex = -1;\r
628 \r
629         if ((group == null) && (av.alignment.getGroups().size() > 0))\r
630         {\r
631             group = (SequenceGroup) av.alignment.getGroups().elementAt(0);\r
632             groupIndex = 0;\r
633         }\r
634 \r
635         if (group != null && !isOverview)\r
636         {\r
637             do\r
638             {\r
639                 int oldY = -1;\r
640                 int i = 0;\r
641                 boolean inGroup = false;\r
642                 int top = -1;\r
643                 int bottom = -1;\r
644 \r
645                 for (i = y1; i < y2; i++)\r
646                 {\r
647                     sx = (group.getStartRes() - startx) * av.charWidth;\r
648                     sy = offset + ((i - starty) * av.charHeight);\r
649                     ex = (((group.getEndRes() + 1) - group.getStartRes()) * av.charWidth) -\r
650                         1;\r
651 \r
652                     if(sx+ex<0 || sx>imgWidth)\r
653                     {\r
654                       continue;\r
655                     }\r
656 \r
657                     if ( (sx <= (x2-x1)*av.charWidth) &&\r
658                             group.sequences.contains(av.alignment.getSequenceAt(\r
659                                     i)))\r
660                     {\r
661                         if ((bottom == -1) &&\r
662                                 !group.sequences.contains(\r
663                                     av.alignment.getSequenceAt(i + 1)))\r
664                         {\r
665                             bottom = sy + av.charHeight;\r
666                         }\r
667 \r
668                         if (!inGroup)\r
669                         {\r
670                             if (((top == -1) && (i == 0)) ||\r
671                                     !group.sequences.contains(\r
672                                         av.alignment.getSequenceAt(i - 1)))\r
673                             {\r
674                                 top = sy;\r
675                             }\r
676 \r
677                             oldY = sy;\r
678                             inGroup = true;\r
679 \r
680                             if (group == av.getSelectionGroup())\r
681                             {\r
682                                 g.setStroke(new BasicStroke(1,\r
683                                         BasicStroke.CAP_BUTT,\r
684                                         BasicStroke.JOIN_ROUND, 3f,\r
685                                         new float[] { 5f, 3f }, 0f));\r
686                                 g.setColor(Color.RED);\r
687                             }\r
688                             else\r
689                             {\r
690                                 g.setStroke(new BasicStroke());\r
691                                 g.setColor(group.getOutlineColour());\r
692                             }\r
693                         }\r
694                     }\r
695                     else\r
696                     {\r
697                       if (inGroup)\r
698                       {\r
699                         if (sx >= 0 && sx < imgWidth)\r
700                           g.drawLine(sx, oldY, sx, sy);\r
701 \r
702                         if (sx + ex < imgWidth)\r
703                           g.drawLine(sx + ex, oldY, sx + ex, sy);\r
704 \r
705                         if (sx < 0)\r
706                         {\r
707                           ex += sx;\r
708                           sx = 0;\r
709                         }\r
710 \r
711                         if (sx + ex > imgWidth)\r
712                           ex = imgWidth;\r
713 \r
714                         else if (sx + ex >= (x2 - x1 + 1) * av.charWidth)\r
715                           ex = (x2 - x1 + 1) * av.charWidth;\r
716 \r
717                         if (top != -1)\r
718                         {\r
719                           g.drawLine(sx, top, sx + ex, top);\r
720                           top = -1;\r
721                         }\r
722 \r
723                         if (bottom != -1)\r
724                         {\r
725                           g.drawLine(sx, bottom, sx + ex, bottom);\r
726                           bottom = -1;\r
727                         }\r
728 \r
729                         inGroup = false;\r
730                         }\r
731                     }\r
732                 }\r
733 \r
734                 if (inGroup)\r
735                 {\r
736                   sy = offset + ( (i - starty) * av.charHeight);\r
737                   if (sx >= 0 && sx < imgWidth)\r
738                     g.drawLine(sx, oldY, sx, sy);\r
739 \r
740                   if (sx + ex < imgWidth)\r
741                     g.drawLine(sx + ex, oldY, sx + ex, sy);\r
742 \r
743                   if (sx < 0)\r
744                   {\r
745                     ex += sx;\r
746                     sx = 0;\r
747                   }\r
748 \r
749                   if (sx + ex > imgWidth)\r
750                     ex = imgWidth;\r
751                   else if (sx + ex >= (x2 - x1 + 1) * av.charWidth)\r
752                     ex = (x2 - x1 + 1) * av.charWidth;\r
753 \r
754                   if (top != -1)\r
755                   {\r
756                     g.drawLine(sx, top, sx + ex, top);\r
757                     top = -1;\r
758                   }\r
759 \r
760                   if (bottom != -1)\r
761                   {\r
762                     g.drawLine(sx, bottom - 1, sx + ex, bottom - 1);\r
763                     bottom = -1;\r
764                   }\r
765 \r
766                     inGroup = false;\r
767                 }\r
768 \r
769                 groupIndex++;\r
770 \r
771                 if (groupIndex >= av.alignment.getGroups().size())\r
772                 {\r
773                     break;\r
774                 }\r
775 \r
776                 group = (SequenceGroup) av.alignment.getGroups().elementAt(groupIndex);\r
777             }\r
778             while (groupIndex < av.alignment.getGroups().size());\r
779         }\r
780 \r
781         /// Highlight search Results once all sequences have been drawn\r
782         //////////////////////////////////////////////////////////\r
783         if (displaySearch)\r
784         {\r
785             for (int r = 0; r < searchResults.length; r += 3)\r
786             {\r
787                 int searchSeq = searchResults[r];\r
788 \r
789                 if ((searchSeq >= y1) && (searchSeq < y2))\r
790                 {\r
791                     SequenceI seq = av.getAlignment().getSequenceAt(searchSeq);\r
792 \r
793                     int searchStart = seq.findIndex(searchResults[r + 1]) - 1;\r
794                     int searchEnd = seq.findIndex(searchResults[r + 2]) - 1;\r
795 \r
796                     SequenceRenderer ssr = (SequenceRenderer) sr;\r
797 \r
798                     if (searchStart < x1)\r
799                     {\r
800                         searchStart = x1;\r
801                     }\r
802 \r
803                     if (searchEnd > x2)\r
804                     {\r
805                         searchEnd = x2;\r
806                     }\r
807 \r
808                     ssr.drawHighlightedText(seq, searchStart, searchEnd,\r
809                         (searchStart - startx) * av.charWidth,\r
810                         offset + ((searchSeq - starty) * av.charHeight),\r
811                         av.charWidth, av.charHeight);\r
812                 }\r
813             }\r
814         }\r
815     }\r
816 \r
817     /**\r
818      * DOCUMENT ME!\r
819      *\r
820      * @param results DOCUMENT ME!\r
821      */\r
822     public void highlightSearchResults(int[] results)\r
823     {\r
824         // results are in the order sequence, startRes, endRes\r
825         if (results == null)\r
826         {\r
827             displaySearch = false;\r
828         }\r
829         else\r
830         {\r
831             displaySearch = true;\r
832         }\r
833 \r
834         searchResults = results;\r
835 \r
836         repaint();\r
837     }\r
838 }\r