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