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