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