JAL-1620 version bump and release notes
[jalview.git] / src / jalview / gui / IdCanvas.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
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   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.charHeight;
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.rightAlignIds)
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.showHiddenMarkers)
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, -vertical * av.charHeight);
154
155     int ss = av.startSeq;
156     int es = av.endSeq;
157     int transY = 0;
158
159     if (vertical > 0) // scroll down
160     {
161       ss = es - vertical;
162
163       if (ss < av.startSeq)
164       { // ie scrolling too fast, more than a page at a time
165         ss = av.startSeq;
166       }
167       else
168       {
169         transY = imgHeight - (vertical * av.charHeight);
170       }
171     }
172     else if (vertical < 0)
173     {
174       es = ss - vertical;
175
176       if (es > av.endSeq)
177       {
178         es = av.endSeq;
179       }
180     }
181
182     gg.translate(0, transY);
183
184     drawIds(ss, es);
185
186     gg.translate(0, -transY);
187
188     fastPaint = true;
189     repaint();
190   }
191
192   /**
193    * DOCUMENT ME!
194    * 
195    * @param g
196    *          DOCUMENT ME!
197    */
198   public void paintComponent(Graphics g)
199   {
200     g.setColor(Color.white);
201     g.fillRect(0, 0, getWidth(), getHeight());
202
203     if (fastPaint)
204     {
205       fastPaint = false;
206       g.drawImage(image, 0, 0, this);
207
208       return;
209     }
210
211     int oldHeight = imgHeight;
212
213     imgHeight = getHeight();
214     imgHeight -= (imgHeight % av.charHeight);
215
216     if (imgHeight < 1)
217     {
218       return;
219     }
220
221     if (oldHeight != imgHeight || image.getWidth(this) != getWidth())
222     {
223       image = new BufferedImage(getWidth(), imgHeight,
224               BufferedImage.TYPE_INT_RGB);
225     }
226
227     gg = (Graphics2D) image.getGraphics();
228
229     // Fill in the background
230     gg.setColor(Color.white);
231     gg.fillRect(0, 0, getWidth(), imgHeight);
232
233     drawIds(av.getStartSeq(), av.endSeq);
234
235     g.drawImage(image, 0, 0, this);
236   }
237
238   /**
239    * DOCUMENT ME!
240    * 
241    * @param starty
242    *          DOCUMENT ME!
243    * @param endy
244    *          DOCUMENT ME!
245    */
246   void drawIds(int starty, int endy)
247   {
248     if (av.seqNameItalics)
249     {
250       idfont = new Font(av.getFont().getName(), Font.ITALIC, av.getFont()
251               .getSize());
252     }
253     else
254     {
255       idfont = av.getFont();
256     }
257
258     gg.setFont(idfont);
259     fm = gg.getFontMetrics();
260
261     if (av.antiAlias)
262     {
263       gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
264               RenderingHints.VALUE_ANTIALIAS_ON);
265     }
266
267     Color currentColor = Color.white;
268     Color currentTextColor = Color.black;
269
270     if (av.getWrapAlignment())
271     {
272       int maxwidth = av.getAlignment().getWidth();
273       int alheight = av.getAlignment().getHeight();
274
275       if (av.hasHiddenColumns())
276       {
277         maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
278       }
279
280       int annotationHeight = 0;
281
282       if (av.showAnnotation)
283       {
284         if (ap == null)
285         {
286           ap = new AnnotationPanel(av);
287         }
288
289         annotationHeight = ap.adjustPanelHeight();
290         if (labels == null)
291         {
292           labels = new AnnotationLabels(av);
293         }
294       }
295
296       int hgap = av.charHeight;
297       if (av.scaleAboveWrapped)
298       {
299         hgap += av.charHeight;
300       }
301
302       int cHeight = alheight * av.charHeight + hgap + annotationHeight;
303
304       int rowSize = av.getEndRes() - av.getStartRes();
305
306       // Draw the rest of the panels
307       for (int ypos = hgap, row = av.startRes; (ypos <= getHeight())
308               && (row < maxwidth); ypos += cHeight, row += rowSize)
309       {
310         for (int i = starty; i < alheight; i++)
311         {
312           SequenceI s = av.getAlignment().getSequenceAt(i);
313           if (av.hasHiddenRows())
314           {
315             setHiddenFont(s);
316           }
317           else
318           {
319             gg.setFont(idfont);
320           }
321
322           drawIdString(gg, s, i, 0, ypos);
323         }
324
325         if (labels != null && av.showAnnotation)
326         {
327           gg.translate(0, ypos + (alheight * av.charHeight));
328           labels.drawComponent(gg, getWidth());
329           gg.translate(0, -ypos - (alheight * av.charHeight));
330         }
331       }
332     }
333     else
334     {
335       // No need to hang on to labels if we're not wrapped
336       labels = null;
337
338       // Now draw the id strings
339       int panelWidth = getWidth();
340       int xPos = 0;
341
342       SequenceI sequence;
343       // Now draw the id strings
344       for (int i = starty; i < endy; i++)
345       {
346         sequence = av.getAlignment().getSequenceAt(i);
347
348         if (sequence == null)
349         {
350           continue;
351         }
352
353         if (av.hasHiddenRows())
354         {
355           setHiddenFont(sequence);
356         }
357
358         // Selected sequence colours
359         if ((searchResults != null) && searchResults.contains(sequence))
360         {
361           currentColor = Color.black;
362           currentTextColor = Color.white;
363         }
364         else if ((av.getSelectionGroup() != null)
365                 && av.getSelectionGroup().getSequences(null)
366                         .contains(sequence))
367         {
368           currentColor = Color.lightGray;
369           currentTextColor = Color.black;
370         }
371         else
372         {
373           currentColor = av.getSequenceColour(sequence);
374           currentTextColor = Color.black;
375         }
376
377         gg.setColor(currentColor);
378
379         gg.fillRect(0, (i - starty) * av.charHeight, getWidth(),
380                 av.charHeight);
381
382         gg.setColor(currentTextColor);
383
384         String string = sequence.getDisplayId(av.getShowJVSuffix());
385
386         if (av.rightAlignIds)
387         {
388           xPos = panelWidth - fm.stringWidth(string) - 4;
389         }
390
391         gg.drawString(string, xPos,
392                 (((i - starty) * av.charHeight) + av.charHeight)
393                         - (av.charHeight / 5));
394
395         if (av.hasHiddenRows() && av.showHiddenMarkers)
396         {
397           drawMarker(i, starty, 0);
398         }
399
400       }
401
402     }
403   }
404
405   void drawMarker(int i, int starty, int yoffset)
406   {
407
408     SequenceI[] hseqs = av.getAlignment().getHiddenSequences().hiddenSequences;
409     // Use this method here instead of calling hiddenSeq adjust
410     // 3 times.
411     int hSize = hseqs.length;
412
413     int hiddenIndex = i;
414     int lastIndex = i - 1;
415     int nextIndex = i + 1;
416
417     for (int j = 0; j < hSize; j++)
418     {
419       if (hseqs[j] != null)
420       {
421         if (j - 1 < hiddenIndex)
422         {
423           hiddenIndex++;
424         }
425         if (j - 1 < lastIndex)
426         {
427           lastIndex++;
428         }
429         if (j - 1 < nextIndex)
430         {
431           nextIndex++;
432         }
433       }
434     }
435
436     boolean below = (hiddenIndex > lastIndex + 1);
437     boolean above = (nextIndex > hiddenIndex + 1);
438
439     gg.setColor(Color.blue);
440     if (below)
441     {
442       gg.fillPolygon(
443               new int[]
444               { getWidth() - av.charHeight, getWidth() - av.charHeight,
445                   getWidth() }, new int[]
446               {
447                   (i - starty) * av.charHeight + yoffset,
448                   (i - starty) * av.charHeight + yoffset + av.charHeight
449                           / 4, (i - starty) * av.charHeight + yoffset }, 3);
450     }
451     if (above)
452     {
453       gg.fillPolygon(
454               new int[]
455               { getWidth() - av.charHeight, getWidth() - av.charHeight,
456                   getWidth() }, new int[]
457               {
458                   (i - starty + 1) * av.charHeight + yoffset,
459                   (i - starty + 1) * av.charHeight + yoffset
460                           - av.charHeight / 4,
461                   (i - starty + 1) * av.charHeight + yoffset }, 3);
462
463     }
464   }
465
466   void setHiddenFont(SequenceI seq)
467   {
468     Font bold = new Font(av.getFont().getName(), Font.BOLD, av.getFont()
469             .getSize());
470
471     if (av.isHiddenRepSequence(seq))
472     {
473       gg.setFont(bold);
474     }
475     else
476     {
477       gg.setFont(idfont);
478     }
479   }
480
481   /**
482    * DOCUMENT ME!
483    * 
484    * @param list
485    *          DOCUMENT ME!
486    */
487   public void setHighlighted(List<SequenceI> list)
488   {
489     searchResults = list;
490     repaint();
491   }
492 }