Formatted source
[jalview.git] / src / jalview / gui / OverviewPanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 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.event.*;\r
23 import java.awt.image.*;\r
24 import javax.swing.*;\r
25 \r
26 public class OverviewPanel\r
27     extends JPanel implements Runnable\r
28 {\r
29   BufferedImage miniMe;\r
30   AlignViewport av;\r
31   AlignmentPanel ap;\r
32   float scalew = 1f;\r
33   float scaleh = 1f;\r
34   int width;\r
35   int sequencesHeight;\r
36   int graphHeight = 30;\r
37   int boxX = -1;\r
38   int boxY = -1;\r
39   int boxWidth = -1;\r
40   int boxHeight = -1;\r
41   boolean resizing = false;\r
42 \r
43   public OverviewPanel(AlignmentPanel ap)\r
44   {\r
45     this.av = ap.av;\r
46     this.ap = ap;\r
47     setLayout(null);\r
48 \r
49     // scale the initial size of overviewpanel to shape of alignment\r
50     float initialScale = (float) av.alignment.getWidth() /\r
51         (float) av.alignment.getHeight();\r
52 \r
53     if (av.alignment.getWidth() > av.alignment.getHeight())\r
54     {\r
55       // wider\r
56       width = 400;\r
57       sequencesHeight = (int) (400f / initialScale);\r
58     }\r
59     else\r
60     {\r
61       // taller\r
62       width = (int) (400f * initialScale);\r
63       sequencesHeight = 300;\r
64 \r
65       if (width < 120)\r
66       {\r
67         width = 120;\r
68       }\r
69     }\r
70 \r
71     addComponentListener(new ComponentAdapter()\r
72     {\r
73       public void componentResized(ComponentEvent evt)\r
74       {\r
75         if ( (getWidth() != width) ||\r
76             (getHeight() != (sequencesHeight + graphHeight)))\r
77         {\r
78           updateOverviewImage();\r
79         }\r
80       }\r
81     });\r
82 \r
83     addMouseMotionListener(new MouseMotionAdapter()\r
84     {\r
85       public void mouseDragged(MouseEvent evt)\r
86       {\r
87         doMouseDragged(evt);\r
88       }\r
89     });\r
90 \r
91     addMouseListener(new MouseAdapter()\r
92     {\r
93       public void mousePressed(MouseEvent evt)\r
94       {\r
95         doMousePressed(evt);\r
96       }\r
97 \r
98       public void mouseReleased(MouseEvent evt)\r
99       {\r
100         doMouseReleased(evt);\r
101       }\r
102     });\r
103 \r
104     updateOverviewImage();\r
105   }\r
106 \r
107   public void doMousePressed(MouseEvent evt)\r
108   {\r
109     boxX = evt.getX();\r
110     boxY = evt.getY();\r
111 \r
112     checkValid();\r
113     repaint();\r
114   }\r
115 \r
116   public void doMouseReleased(MouseEvent evt)\r
117   {\r
118     boxX = evt.getX();\r
119     boxY = evt.getY();\r
120     checkValid();\r
121 \r
122     if (!resizing)\r
123     {\r
124       ap.setScrollValues( (int) (boxX / scalew / av.getCharWidth()),\r
125                          (int) (boxY / scaleh / av.getCharHeight()));\r
126     }\r
127   }\r
128 \r
129   public void doMouseDragged(MouseEvent evt)\r
130   {\r
131     boxX = evt.getX();\r
132     boxY = evt.getY();\r
133     checkValid();\r
134 \r
135     if (!resizing)\r
136     {\r
137       ap.setScrollValues( (int) (boxX / scalew / av.getCharWidth()),\r
138                          (int) (boxY / scaleh / av.getCharHeight()));\r
139     }\r
140   }\r
141 \r
142   void checkValid()\r
143   {\r
144     if (boxY < 0)\r
145     {\r
146       boxY = 0;\r
147     }\r
148 \r
149     if (boxY > (sequencesHeight - boxHeight))\r
150     {\r
151       boxY = sequencesHeight - boxHeight + 1;\r
152     }\r
153 \r
154     if (boxX < 0)\r
155     {\r
156       boxX = 0;\r
157     }\r
158 \r
159     if (boxX > (width - boxWidth))\r
160     {\r
161       boxX = width - boxWidth;\r
162     }\r
163   }\r
164 \r
165   public void updateOverviewImage()\r
166   {\r
167     if (resizing)\r
168     {\r
169       return;\r
170     }\r
171 \r
172     resizing = true;\r
173 \r
174     Thread thread = new Thread(this);\r
175     thread.start();\r
176     repaint();\r
177   }\r
178 \r
179   public void run()\r
180   {\r
181     miniMe = null;\r
182 \r
183     int alwidth = av.alignment.getWidth();\r
184     int alheight = av.alignment.getHeight();\r
185 \r
186     if ( (getWidth() > 0) && (getHeight() > 0))\r
187     {\r
188       width = getWidth();\r
189       sequencesHeight = getHeight() - graphHeight;\r
190     }\r
191 \r
192     setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));\r
193 \r
194     int fullsizeWidth = alwidth * av.getCharWidth();\r
195     int fullsizeHeight = alheight * av.getCharHeight();\r
196 \r
197     scalew = (float) width / (float) fullsizeWidth;\r
198     scaleh = (float) sequencesHeight / (float) fullsizeHeight;\r
199 \r
200     miniMe = new BufferedImage(width, sequencesHeight + graphHeight,\r
201                                BufferedImage.TYPE_INT_RGB);\r
202 \r
203     Graphics mg = miniMe.getGraphics();\r
204     BufferedImage consensus = new BufferedImage(fullsizeWidth, 60,\r
205                                                 BufferedImage.TYPE_3BYTE_BGR);\r
206     Graphics g = consensus.getGraphics();\r
207     ap.annotationPanel.drawGraph(g, av.conservation, fullsizeWidth, 60);\r
208     mg.drawImage(consensus, 0, sequencesHeight, width,\r
209                  sequencesHeight + graphHeight, 0, 0, fullsizeWidth, 60, this);\r
210 \r
211     boolean oldRenderGaps = av.renderGaps;\r
212 \r
213     try\r
214     {\r
215       // We'll have to draw the full size alignment in chunks, as an image of the\r
216       // whole alignment requires too much memory\r
217       // Max size depends on the font size, the following is a\r
218       // guess at a size which works\r
219       int maxSize = 2000 / av.getFont().getSize();\r
220       BufferedImage block;\r
221       int blockx = 0;\r
222       int blocky = 0;\r
223       int blockw = 0;\r
224       int blockh = 0;\r
225       int eRes = 0;\r
226       int eSeq = 0;\r
227 \r
228       av.setRenderGaps(false);\r
229 \r
230       for (int sRes = 0, chunkx = 0; sRes < alwidth;\r
231            sRes += maxSize, chunkx++)\r
232       {\r
233         eSeq = 0;\r
234         eRes += maxSize;\r
235 \r
236         if (eRes > alwidth)\r
237         {\r
238           eRes = alwidth;\r
239         }\r
240 \r
241         for (int sSeq = 0, chunky = 0; sSeq < alheight;\r
242              sSeq += maxSize, chunky++)\r
243         {\r
244           eSeq += maxSize;\r
245 \r
246           if (eSeq > alheight)\r
247           {\r
248             eSeq = alheight;\r
249           }\r
250 \r
251           blocky = 0;\r
252           blockx = (int) ( (float) sRes / (float) alwidth * width);\r
253 \r
254           block = new BufferedImage( (eRes - sRes) * av.charWidth,\r
255                                     (eSeq - sSeq) * av.charHeight,\r
256                                     BufferedImage.TYPE_3BYTE_BGR);\r
257           g = block.getGraphics();\r
258 \r
259           ap.seqPanel.seqCanvas.drawPanel(g, sRes, eRes, sSeq, eSeq,\r
260                                           sRes, sSeq, 0);\r
261 \r
262           blockh = (int) ( (float) (eSeq - sSeq) / (float) alheight *\r
263                           sequencesHeight) +\r
264               1;\r
265           blockw = (int) ( (float) (eRes - sRes) / (float) alwidth * width) +\r
266               1;\r
267 \r
268           blocky += (int) ( (float) sSeq / (float) alheight * sequencesHeight);\r
269 \r
270           mg.drawImage(block, blockx, blocky, blockx + blockw,\r
271                        blocky + blockh, 0, 0, block.getWidth(),\r
272                        block.getHeight(), this);\r
273 \r
274           block = null;\r
275         }\r
276       }\r
277     }\r
278     catch (OutOfMemoryError error)\r
279     {\r
280       System.err.println(\r
281           "Out of memory when trying to calculate the overview window image!");\r
282     }\r
283 \r
284     av.setRenderGaps(oldRenderGaps);\r
285     resizing = false;\r
286 \r
287     setBoxPosition();\r
288   }\r
289 \r
290   public void setBoxPosition()\r
291   {\r
292     boxX = (int) (av.getStartRes() * av.getCharWidth() * scalew);\r
293     boxY = (int) (av.getStartSeq() * av.getCharHeight() * scaleh);\r
294     boxWidth = (int) ( (av.getEndRes() - av.getStartRes() + 1) *\r
295                       av.getCharWidth() * scalew);\r
296     boxHeight = (int) (av.getEndSeq() * av.getCharHeight() * scaleh) -\r
297         boxY;\r
298     repaint();\r
299   }\r
300 \r
301   public void paintComponent(Graphics g)\r
302   {\r
303     g.setColor(Color.white);\r
304     g.fillRect(0, 0, getWidth(), getHeight());\r
305     g.setColor(Color.black);\r
306 \r
307     if (resizing)\r
308     {\r
309       g.setFont(new Font("Verdana", Font.BOLD, 15));\r
310       g.drawString("Recalculating", 5, sequencesHeight / 2);\r
311       g.drawString("Overview.....", 5, (sequencesHeight / 2) + 20);\r
312     }\r
313     else\r
314     {\r
315       if (miniMe != null)\r
316       {\r
317         g.drawImage(miniMe, 0, 0, this);\r
318       }\r
319 \r
320       g.setColor(Color.red);\r
321       g.drawRect(boxX, boxY, boxWidth, boxHeight);\r
322       g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);\r
323     }\r
324   }\r
325 }\r