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