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