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