merge from 2_4_Release branch
[jalview.git] / src / jalview / gui / IdCanvas.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3  * Copyright (C) 2008 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 java.awt.*;
22 import java.awt.image.*;
23 import javax.swing.*;
24
25 import jalview.datamodel.*;
26
27 /**
28  * DOCUMENT ME!
29  * 
30  * @author $author$
31  * @version $Revision$
32  */
33 public class IdCanvas extends JPanel
34 {
35   protected AlignViewport av;
36
37   protected boolean showScores = true;
38
39   protected int maxIdLength = -1;
40
41   protected String maxIdStr = null;
42
43   BufferedImage image;
44
45   Graphics2D gg;
46
47   int imgHeight = 0;
48
49   boolean fastPaint = false;
50
51   java.util.Vector searchResults;
52
53   FontMetrics fm;
54
55   AnnotationLabels labels = null;
56
57   AnnotationPanel ap;
58
59   Font idfont;
60
61   /**
62    * Creates a new IdCanvas object.
63    * 
64    * @param av
65    *                DOCUMENT ME!
66    */
67   public IdCanvas(AlignViewport av)
68   {
69     setLayout(new BorderLayout());
70     this.av = av;
71     PaintRefresher.Register(this, av.getSequenceSetId());
72   }
73
74   /**
75    * DOCUMENT ME!
76    * 
77    * @param gg
78    *                DOCUMENT ME!
79    * @param s
80    *                DOCUMENT ME!
81    * @param i
82    *                DOCUMENT ME!
83    * @param starty
84    *                DOCUMENT ME!
85    * @param ypos
86    *                DOCUMENT ME!
87    */
88   public void drawIdString(Graphics2D gg, SequenceI s, int i, int starty,
89           int ypos)
90   {
91     int xPos = 0;
92     int panelWidth = getWidth();
93     int charHeight = av.charHeight;
94
95     if ((searchResults != null) && searchResults.contains(s))
96     {
97       gg.setColor(Color.black);
98       gg.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(),
99               charHeight);
100       gg.setColor(Color.white);
101     }
102     else if ((av.getSelectionGroup() != null)
103             && av.getSelectionGroup().getSequences(null).contains(s))
104     {
105       gg.setColor(Color.lightGray);
106       gg.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(),
107               charHeight);
108       gg.setColor(Color.white);
109     }
110     else
111     {
112       gg.setColor(av.getSequenceColour(s));
113       gg.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(),
114               charHeight);
115       gg.setColor(Color.black);
116     }
117
118     if (av.rightAlignIds)
119     {
120       xPos = panelWidth
121               - fm.stringWidth(s.getDisplayId(av.getShowJVSuffix())) - 4;
122     }
123
124     gg.drawString(s.getDisplayId(av.getShowJVSuffix()), xPos,
125             (((i - starty + 1) * charHeight) + ypos) - (charHeight / 5));
126
127     if (av.hasHiddenRows && av.showHiddenMarkers)
128     {
129       drawMarker(i, starty, ypos);
130     }
131
132   }
133
134   /**
135    * DOCUMENT ME!
136    * 
137    * @param vertical
138    *                DOCUMENT ME!
139    */
140   public void fastPaint(int vertical)
141   {
142     if (gg == null)
143     {
144       repaint();
145
146       return;
147     }
148
149     gg.copyArea(0, 0, getWidth(), imgHeight, 0, -vertical * av.charHeight);
150
151     int ss = av.startSeq;
152     int es = av.endSeq;
153     int transY = 0;
154
155     if (vertical > 0) // scroll down
156     {
157       ss = es - vertical;
158
159       if (ss < av.startSeq)
160       { // ie scrolling too fast, more than a page at a time
161         ss = av.startSeq;
162       }
163       else
164       {
165         transY = imgHeight - (vertical * av.charHeight);
166       }
167     }
168     else if (vertical < 0)
169     {
170       es = ss - vertical;
171
172       if (es > av.endSeq)
173       {
174         es = av.endSeq;
175       }
176     }
177
178     gg.translate(0, transY);
179
180     drawIds(ss, es);
181
182     gg.translate(0, -transY);
183
184     fastPaint = true;
185     repaint();
186   }
187
188   /**
189    * DOCUMENT ME!
190    * 
191    * @param g
192    *                DOCUMENT ME!
193    */
194   public void paintComponent(Graphics g)
195   {
196     g.setColor(Color.white);
197     g.fillRect(0, 0, getWidth(), getHeight());
198
199     if (fastPaint)
200     {
201       fastPaint = false;
202       g.drawImage(image, 0, 0, this);
203
204       return;
205     }
206
207     int oldHeight = imgHeight;
208
209     imgHeight = getHeight();
210     imgHeight -= (imgHeight % av.charHeight);
211
212     if (imgHeight < 1)
213     {
214       return;
215     }
216
217     if (oldHeight != imgHeight || image.getWidth(this) != getWidth())
218     {
219       image = new BufferedImage(getWidth(), imgHeight,
220               BufferedImage.TYPE_INT_RGB);
221     }
222
223     gg = (Graphics2D) image.getGraphics();
224
225     // Fill in the background
226     gg.setColor(Color.white);
227     gg.fillRect(0, 0, getWidth(), imgHeight);
228
229     drawIds(av.getStartSeq(), av.endSeq);
230
231     g.drawImage(image, 0, 0, this);
232   }
233
234   /**
235    * DOCUMENT ME!
236    * 
237    * @param starty
238    *                DOCUMENT ME!
239    * @param endy
240    *                DOCUMENT ME!
241    */
242   void drawIds(int starty, int endy)
243   {
244     if (av.seqNameItalics)
245     {
246       idfont = new Font(av.getFont().getName(), Font.ITALIC, av.getFont()
247               .getSize());
248     }
249     else
250     {
251       idfont = av.getFont();
252     }
253
254     gg.setFont(idfont);
255     fm = gg.getFontMetrics();
256
257     if (av.antiAlias)
258     {
259       gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
260               RenderingHints.VALUE_ANTIALIAS_ON);
261     }
262
263     Color currentColor = Color.white;
264     Color currentTextColor = Color.black;
265
266     if (av.getWrapAlignment())
267     {
268       int maxwidth = av.alignment.getWidth();
269       int alheight = av.alignment.getHeight();
270
271       if (av.hasHiddenColumns)
272       {
273         maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
274       }
275
276       int annotationHeight = 0;
277
278       if (av.showAnnotation)
279       {
280         if (ap == null)
281         {
282           ap = new AnnotationPanel(av);
283         }
284
285         annotationHeight = ap.adjustPanelHeight();
286         if (labels == null)
287         {
288           labels = new AnnotationLabels(av);
289         }
290       }
291
292       int hgap = av.charHeight;
293       if (av.scaleAboveWrapped)
294       {
295         hgap += av.charHeight;
296       }
297
298       int cHeight = alheight * av.charHeight + hgap + annotationHeight;
299
300       int rowSize = av.getEndRes() - av.getStartRes();
301
302       // Draw the rest of the panels
303       for (int ypos = hgap, row = av.startRes; (ypos <= getHeight())
304               && (row < maxwidth); ypos += cHeight, row += rowSize)
305       {
306         for (int i = starty; i < alheight; i++)
307         {
308           SequenceI s = av.alignment.getSequenceAt(i);
309           if (av.hasHiddenRows)
310           {
311             setHiddenFont(s);
312           }
313           else
314           {
315             gg.setFont(idfont);
316           }
317
318           drawIdString(gg, s, i, 0, ypos);
319         }
320
321         if (labels != null && av.showAnnotation)
322         {
323           gg.translate(0, ypos + (alheight * av.charHeight));
324           labels.drawComponent(gg, getWidth());
325           gg.translate(0, -ypos - (alheight * av.charHeight));
326         }
327       }
328     }
329     else
330     {
331       // No need to hang on to labels if we're not wrapped
332       labels = null;
333
334       // Now draw the id strings
335       int panelWidth = getWidth();
336       int xPos = 0;
337
338       SequenceI sequence;
339       // Now draw the id strings
340       for (int i = starty; i < endy; i++)
341       {
342         sequence = av.alignment.getSequenceAt(i);
343
344         if (sequence == null)
345         {
346           continue;
347         }
348
349         if (av.hasHiddenRows)
350         {
351           setHiddenFont(sequence);
352         }
353
354         // Selected sequence colours
355         if ((searchResults != null) && searchResults.contains(sequence))
356         {
357           currentColor = Color.black;
358           currentTextColor = Color.white;
359         }
360         else if ((av.getSelectionGroup() != null)
361                 && av.getSelectionGroup().getSequences(null).contains(
362                         sequence))
363         {
364           currentColor = Color.lightGray;
365           currentTextColor = Color.black;
366         }
367         else
368         {
369           currentColor = av.getSequenceColour(sequence);
370           currentTextColor = Color.black;
371         }
372
373         gg.setColor(currentColor);
374
375         gg.fillRect(0, (i - starty) * av.charHeight, getWidth(),
376                 av.charHeight);
377
378         gg.setColor(currentTextColor);
379
380         String string = sequence.getDisplayId(av.getShowJVSuffix());
381
382         if (av.rightAlignIds)
383         {
384           xPos = panelWidth - fm.stringWidth(string) - 4;
385         }
386
387         gg.drawString(string, xPos,
388                 (((i - starty) * av.charHeight) + av.charHeight)
389                         - (av.charHeight / 5));
390
391         if (av.hasHiddenRows && av.showHiddenMarkers)
392         {
393           drawMarker(i, starty, 0);
394         }
395
396       }
397
398     }
399   }
400
401   void drawMarker(int i, int starty, int yoffset)
402   {
403
404     SequenceI[] hseqs = av.alignment.getHiddenSequences().hiddenSequences;
405     // Use this method here instead of calling hiddenSeq adjust
406     // 3 times.
407     int hSize = hseqs.length;
408
409     int hiddenIndex = i;
410     int lastIndex = i - 1;
411     int nextIndex = i + 1;
412
413     for (int j = 0; j < hSize; j++)
414     {
415       if (hseqs[j] != null)
416       {
417         if (j - 1 < hiddenIndex)
418         {
419           hiddenIndex++;
420         }
421         if (j - 1 < lastIndex)
422         {
423           lastIndex++;
424         }
425         if (j - 1 < nextIndex)
426         {
427           nextIndex++;
428         }
429       }
430     }
431
432     boolean below = (hiddenIndex > lastIndex + 1);
433     boolean above = (nextIndex > hiddenIndex + 1);
434
435     gg.setColor(Color.blue);
436     if (below)
437     {
438       gg.fillPolygon(
439               new int[]
440               { getWidth() - av.charHeight, getWidth() - av.charHeight,
441                   getWidth() }, new int[]
442               {
443                   (i - starty) * av.charHeight + yoffset,
444                   (i - starty) * av.charHeight + yoffset + av.charHeight
445                           / 4, (i - starty) * av.charHeight + yoffset }, 3);
446     }
447     if (above)
448     {
449       gg.fillPolygon(
450               new int[]
451               { getWidth() - av.charHeight, getWidth() - av.charHeight,
452                   getWidth() }, new int[]
453               {
454                   (i - starty + 1) * av.charHeight + yoffset,
455                   (i - starty + 1) * av.charHeight + yoffset
456                           - av.charHeight / 4,
457                   (i - starty + 1) * av.charHeight + yoffset }, 3);
458
459     }
460   }
461
462   void setHiddenFont(SequenceI seq)
463   {
464     Font bold = new Font(av.getFont().getName(), Font.BOLD, av.getFont()
465             .getSize());
466
467     if (av.hiddenRepSequences != null
468             && av.hiddenRepSequences.containsKey(seq))
469     {
470       gg.setFont(bold);
471     }
472     else
473     {
474       gg.setFont(idfont);
475     }
476   }
477
478   /**
479    * DOCUMENT ME!
480    * 
481    * @param found
482    *                DOCUMENT ME!
483    */
484   public void setHighlighted(java.util.Vector found)
485   {
486     searchResults = found;
487     repaint();
488   }
489 }