a35be1510f36712603e585d1bd4ecd69cbc0d8b1
[jalview.git] / src / jalview / appletgui / IdCanvas.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.appletgui;
19
20 import java.awt.*;
21 import java.util.List;
22
23 import jalview.datamodel.*;
24
25 public class IdCanvas extends Panel
26 {
27   protected AlignViewport av;
28
29   protected boolean showScores = true;
30
31   protected int maxIdLength = -1;
32
33   protected String maxIdStr = null;
34
35   Image image;
36
37   Graphics gg;
38
39   int imgHeight = 0;
40
41   boolean fastPaint = false;
42
43   List<SequenceI> searchResults;
44
45   public IdCanvas(AlignViewport av)
46   {
47     setLayout(null);
48     this.av = av;
49     PaintRefresher.Register(this, av.getSequenceSetId());
50   }
51
52   public void drawIdString(Graphics gg, SequenceI s, int i, int starty,
53           int ypos)
54   {
55     int charHeight = av.getCharHeight();
56
57     if (searchResults != null && searchResults.contains(s))
58     {
59       gg.setColor(Color.black);
60       gg.fillRect(0, ((i - starty) * charHeight) + ypos, getSize().width,
61               charHeight);
62       gg.setColor(Color.white);
63     }
64     else if (av.getSelectionGroup() != null
65             && av.getSelectionGroup().getSequences(null).contains(s))
66     {
67       gg.setColor(Color.lightGray);
68       gg.fillRect(0, ((i - starty) * charHeight) + ypos, getSize().width,
69               charHeight);
70       gg.setColor(Color.white);
71     }
72     else
73     {
74       gg.setColor(av.getSequenceColour(s));
75       gg.fillRect(0, ((i - starty) * charHeight) + ypos, getSize().width,
76               charHeight);
77       gg.setColor(Color.black);
78     }
79
80     gg.drawString(s.getDisplayId(av.getShowJVSuffix()), 0,
81             ((i - starty) * charHeight) + ypos + charHeight
82                     - (charHeight / 5));
83
84     if (av.hasHiddenRows() && av.showHiddenMarkers)
85     {
86       drawMarker(i, starty, ypos);
87     }
88
89   }
90
91   public void fastPaint(int vertical)
92   {
93     if (gg == null)
94     {
95       repaint();
96       return;
97     }
98
99     gg.copyArea(0, 0, getSize().width, imgHeight, 0, -vertical
100             * av.charHeight);
101
102     int ss = av.startSeq, es = av.endSeq, transY = 0;
103     if (vertical > 0) // scroll down
104     {
105       ss = es - vertical;
106       if (ss < av.startSeq) // ie scrolling too fast, more than a page at a time
107       {
108         ss = av.startSeq;
109       }
110       else
111       {
112         transY = imgHeight - vertical * av.charHeight;
113       }
114     }
115     else if (vertical < 0)
116     {
117       es = ss - vertical;
118       if (es > av.endSeq)
119       {
120         es = av.endSeq;
121       }
122     }
123
124     gg.translate(0, transY);
125
126     drawIds(ss, es);
127
128     gg.translate(0, -transY);
129
130     fastPaint = true;
131     repaint();
132   }
133
134   public void update(Graphics g)
135   {
136     paint(g);
137   }
138
139   public void paint(Graphics g)
140   {
141     if (getSize().height < 0 || getSize().width < 0)
142     {
143       return;
144     }
145     if (fastPaint)
146     {
147       fastPaint = false;
148       g.drawImage(image, 0, 0, this);
149       return;
150     }
151
152     imgHeight = getSize().height;
153     imgHeight -= imgHeight % av.charHeight;
154
155     if (imgHeight < 1)
156     {
157       return;
158     }
159
160     if (image == null || imgHeight != image.getHeight(this))
161     {
162       image = createImage(getSize().width, imgHeight);
163       gg = image.getGraphics();
164       gg.setFont(av.getFont());
165     }
166
167     // Fill in the background
168     gg.setColor(Color.white);
169     Font italic = new Font(av.getFont().getName(), Font.ITALIC, av
170             .getFont().getSize());
171     gg.setFont(italic);
172
173     gg.fillRect(0, 0, getSize().width, getSize().height);
174     drawIds(av.startSeq, av.endSeq);
175     g.drawImage(image, 0, 0, this);
176   }
177
178   void drawIds(int starty, int endy)
179   {
180     Font italic = new Font(av.getFont().getName(), Font.ITALIC, av
181             .getFont().getSize());
182
183     gg.setFont(italic);
184
185     Color currentColor = Color.white;
186     Color currentTextColor = Color.black;
187
188     if (av.getWrapAlignment())
189     {
190       int maxwidth = av.getAlignment().getWidth();
191       int alheight = av.getAlignment().getHeight();
192
193       if (av.hasHiddenColumns())
194       {
195         maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
196       }
197
198       int annotationHeight = 0;
199       AnnotationLabels labels = null;
200
201       if (av.showAnnotation)
202       {
203         AnnotationPanel ap = new AnnotationPanel(av);
204         annotationHeight = ap.adjustPanelHeight();
205         labels = new AnnotationLabels(av);
206       }
207
208       int hgap = av.charHeight;
209       if (av.scaleAboveWrapped)
210       {
211         hgap += av.charHeight;
212       }
213
214       int cHeight = alheight * av.charHeight + hgap + annotationHeight;
215
216       int rowSize = av.getEndRes() - av.getStartRes();
217
218       // Draw the rest of the panels
219       for (int ypos = hgap, row = av.startRes; (ypos <= getSize().height)
220               && (row < maxwidth); ypos += cHeight, row += rowSize)
221       {
222         for (int i = starty; i < alheight; i++)
223         {
224
225           SequenceI s = av.getAlignment().getSequenceAt(i);
226           gg.setFont(italic);
227           if (av.hasHiddenRows())
228           {
229             setHiddenFont(s);
230           }
231           drawIdString(gg, s, i, 0, ypos);
232         }
233
234         if (labels != null)
235         {
236           gg.translate(0, ypos + (alheight * av.charHeight));
237           labels.drawComponent(gg, getSize().width);
238           gg.translate(0, -ypos - (alheight * av.charHeight));
239         }
240
241       }
242     }
243     else
244     {
245       // Now draw the id strings
246       SequenceI seq;
247       for (int i = starty; i < endy; i++)
248       {
249
250         seq = av.getAlignment().getSequenceAt(i);
251         if (seq == null)
252         {
253           continue;
254         }
255         gg.setFont(italic);
256         // boolean isrep=false;
257         if (av.hasHiddenRows())
258         {
259           // isrep =
260           setHiddenFont(seq);
261         }
262
263         // Selected sequence colours
264         if ((searchResults != null) && searchResults.contains(seq))
265         {
266           currentColor = Color.black;
267           currentTextColor = Color.white;
268         }
269         else if ((av.getSelectionGroup() != null)
270                 && av.getSelectionGroup().getSequences(null).contains(seq))
271         {
272           currentColor = Color.lightGray;
273           currentTextColor = Color.black;
274         }
275         else
276         {
277           currentColor = av.getSequenceColour(seq);
278           currentTextColor = Color.black;
279         }
280
281         gg.setColor(currentColor);
282         // TODO: isrep could be used to highlight the representative in a
283         // different way
284         gg.fillRect(0, (i - starty) * av.charHeight, getSize().width,
285                 av.charHeight);
286         gg.setColor(currentTextColor);
287
288         gg.drawString(seq.getDisplayId(av.getShowJVSuffix()), 0,
289                 (((i - starty) * av.charHeight) + av.charHeight)
290                         - (av.charHeight / 5));
291
292         if (av.hasHiddenRows() && av.showHiddenMarkers)
293         {
294           drawMarker(i, starty, 0);
295         }
296       }
297     }
298   }
299
300   public void setHighlighted(List<SequenceI> list)
301   {
302     searchResults = list;
303     repaint();
304   }
305
306   void drawMarker(int i, int starty, int yoffset)
307   {
308     SequenceI[] hseqs = av.getAlignment().getHiddenSequences().hiddenSequences;
309     // Use this method here instead of calling hiddenSeq adjust
310     // 3 times.
311     int hSize = hseqs.length;
312
313     int hiddenIndex = i;
314     int lastIndex = i - 1;
315     int nextIndex = i + 1;
316
317     for (int j = 0; j < hSize; j++)
318     {
319       if (hseqs[j] != null)
320       {
321         if (j - 1 < hiddenIndex)
322         {
323           hiddenIndex++;
324         }
325         if (j - 1 < lastIndex)
326         {
327           lastIndex++;
328         }
329         if (j - 1 < nextIndex)
330         {
331           nextIndex++;
332         }
333       }
334     }
335
336     boolean below = (hiddenIndex > lastIndex + 1);
337     boolean above = (nextIndex > hiddenIndex + 1);
338
339     gg.setColor(Color.blue);
340     if (below)
341     {
342       gg.fillPolygon(new int[]
343       { getSize().width - av.charHeight, getSize().width - av.charHeight,
344           getSize().width }, new int[]
345       { (i - starty) * av.charHeight + yoffset,
346           (i - starty) * av.charHeight + yoffset + av.charHeight / 4,
347           (i - starty) * av.charHeight + yoffset }, 3);
348     }
349     if (above)
350     {
351       gg.fillPolygon(new int[]
352       { getSize().width - av.charHeight, getSize().width - av.charHeight,
353           getSize().width }, new int[]
354       { (i - starty + 1) * av.charHeight + yoffset,
355           (i - starty + 1) * av.charHeight + yoffset - av.charHeight / 4,
356           (i - starty + 1) * av.charHeight + yoffset }, 3);
357
358     }
359   }
360
361   boolean setHiddenFont(SequenceI seq)
362   {
363     Font bold = new Font(av.getFont().getName(), Font.BOLD, av.getFont()
364             .getSize());
365
366     if (av.getHiddenRepSequences() != null
367             && av.getHiddenRepSequences().containsKey(seq))
368     {
369       gg.setFont(bold);
370       return true;
371     }
372     return false;
373   }
374 }