635e4550591766e076fb979312246ccb701981fe
[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 \r
25 import javax.swing.*;\r
26 \r
27 \r
28 /**\r
29  * DOCUMENT ME!\r
30  *\r
31  * @author $author$\r
32  * @version $Revision$\r
33  */\r
34 public class OverviewPanel extends JPanel implements Runnable\r
35 {\r
36     BufferedImage miniMe;\r
37     AlignViewport av;\r
38     AlignmentPanel ap;\r
39     float scalew = 1f;\r
40     float scaleh = 1f;\r
41     int width;\r
42     int sequencesHeight;\r
43     int graphHeight = 20;\r
44     int boxX = -1;\r
45     int boxY = -1;\r
46     int boxWidth = -1;\r
47     int boxHeight = -1;\r
48     boolean resizing = false;\r
49 \r
50     // Can set different properties in this seqCanvas than\r
51     // main visible SeqCanvas\r
52     SeqCanvas overviewSeq;\r
53 \r
54     /**\r
55      * Creates a new OverviewPanel object.\r
56      *\r
57      * @param ap DOCUMENT ME!\r
58      */\r
59     public OverviewPanel(AlignmentPanel ap)\r
60     {\r
61         this.av = ap.av;\r
62         this.ap = ap;\r
63         setLayout(null);\r
64 \r
65         overviewSeq = new SeqCanvas(av);\r
66         overviewSeq.isOverview = true;\r
67         overviewSeq.sr.renderGaps = false;\r
68 \r
69         // scale the initial size of overviewpanel to shape of alignment\r
70         float initialScale = (float) av.alignment.getWidth() / (float) av.alignment.getHeight();\r
71 \r
72         if(av.vconsensus==null)\r
73           graphHeight = 0;\r
74 \r
75 \r
76         if (av.alignment.getWidth() > av.alignment.getHeight())\r
77         {\r
78             // wider\r
79             width = 400;\r
80             sequencesHeight = (int) (400f / initialScale);\r
81             if(sequencesHeight<40)\r
82               sequencesHeight = 40;\r
83         }\r
84         else\r
85         {\r
86             // taller\r
87             width = (int) (400f * initialScale);\r
88             sequencesHeight = 300;\r
89 \r
90             if (width < 120)\r
91             {\r
92                 width = 120;\r
93             }\r
94         }\r
95 \r
96         addComponentListener(new ComponentAdapter()\r
97             {\r
98                 public void componentResized(ComponentEvent evt)\r
99                 {\r
100                     if ((getWidth() != width) ||\r
101                             (getHeight() != (sequencesHeight + graphHeight)))\r
102                     {\r
103                         updateOverviewImage();\r
104                     }\r
105                 }\r
106             });\r
107 \r
108         addMouseMotionListener(new MouseMotionAdapter()\r
109             {\r
110                 public void mouseDragged(MouseEvent evt)\r
111                 {\r
112                   if(!av.wrapAlignment)\r
113                     doMouseDragged(evt);\r
114                 }\r
115             });\r
116 \r
117         addMouseListener(new MouseAdapter()\r
118             {\r
119                 public void mousePressed(MouseEvent evt)\r
120                 {\r
121                   if(!av.wrapAlignment)\r
122                     doMousePressed(evt);\r
123                 }\r
124 \r
125                 public void mouseReleased(MouseEvent evt)\r
126                 {\r
127                   if(!av.wrapAlignment)\r
128                     doMouseReleased(evt);\r
129                 }\r
130             });\r
131 \r
132         updateOverviewImage();\r
133     }\r
134 \r
135     /**\r
136      * DOCUMENT ME!\r
137      *\r
138      * @param evt DOCUMENT ME!\r
139      */\r
140     public void doMousePressed(MouseEvent evt)\r
141     {\r
142         boxX = evt.getX();\r
143         boxY = evt.getY();\r
144 \r
145         checkValid();\r
146         repaint();\r
147     }\r
148 \r
149     /**\r
150      * DOCUMENT ME!\r
151      *\r
152      * @param evt DOCUMENT ME!\r
153      */\r
154     public void doMouseReleased(MouseEvent evt)\r
155     {\r
156         boxX = evt.getX();\r
157         boxY = evt.getY();\r
158         checkValid();\r
159 \r
160         ap.setScrollValues((int) (boxX / scalew / av.getCharWidth()),\r
161                 (int) (boxY / scaleh / av.getCharHeight()));\r
162     }\r
163 \r
164     /**\r
165      * DOCUMENT ME!\r
166      *\r
167      * @param evt DOCUMENT ME!\r
168      */\r
169     public void doMouseDragged(MouseEvent evt)\r
170     {\r
171         boxX = evt.getX();\r
172         boxY = evt.getY();\r
173         checkValid();\r
174 \r
175         ap.setScrollValues( (int) (boxX / scalew / av.getCharWidth()),\r
176                            (int) (boxY / scaleh / av.getCharHeight()));\r
177        repaint();\r
178     }\r
179 \r
180     /**\r
181      * DOCUMENT ME!\r
182      */\r
183     void checkValid()\r
184     {\r
185         if (boxY < 0)\r
186         {\r
187             boxY = 0;\r
188         }\r
189 \r
190         if (boxY > (sequencesHeight - boxHeight))\r
191         {\r
192             boxY = sequencesHeight - boxHeight + 1;\r
193         }\r
194 \r
195         if (boxX < 0)\r
196         {\r
197             boxX = 0;\r
198         }\r
199 \r
200         if (boxX > (width - boxWidth))\r
201         {\r
202             boxX = width - boxWidth;\r
203         }\r
204     }\r
205 \r
206     /**\r
207      * DOCUMENT ME!\r
208      */\r
209     public void updateOverviewImage()\r
210     {\r
211         if (resizing)\r
212         {\r
213             resizeAgain = true;\r
214             return;\r
215         }\r
216 \r
217         resizing = true;\r
218 \r
219         if ( (getWidth() > 0) && (getHeight() > 0))\r
220         {\r
221           width = getWidth();\r
222           sequencesHeight = getHeight() - graphHeight;\r
223         }\r
224 \r
225         setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));\r
226         setBoxPosition();\r
227 \r
228         Thread thread = new Thread(this);\r
229         thread.start();\r
230         repaint();\r
231     }\r
232 \r
233     // This is set true if the user resizes whilst\r
234     // the overview is being calculated\r
235     boolean resizeAgain = false;\r
236 \r
237     /**\r
238      * DOCUMENT ME!\r
239      */\r
240     public void run()\r
241     {\r
242         miniMe = null;\r
243 \r
244         int alwidth = av.alignment.getWidth();\r
245         int alheight = av.alignment.getHeight();\r
246 \r
247         setPreferredSize(new Dimension(width, sequencesHeight + graphHeight));\r
248 \r
249         int fullsizeWidth = alwidth * av.getCharWidth();\r
250         int fullsizeHeight = alheight * av.getCharHeight();\r
251 \r
252         scalew = (float) width / (float) fullsizeWidth;\r
253         scaleh = (float) sequencesHeight / (float) fullsizeHeight;\r
254 \r
255         miniMe = new BufferedImage(width, sequencesHeight + graphHeight,\r
256                 BufferedImage.TYPE_INT_RGB);\r
257 \r
258 \r
259         Graphics mg = miniMe.getGraphics();\r
260 \r
261         float sampleCol = (float) alwidth / (float) width;\r
262         float sampleRow = (float) alheight / (float) sequencesHeight;\r
263 \r
264         for (int col = 0; col < width; col++)\r
265         {\r
266           for (int row = 0; row < sequencesHeight; row++)\r
267           {\r
268             overviewSeq.drawPanel(mg,\r
269                                             (int) (col * sampleCol),\r
270                                             (int) (col * sampleCol),\r
271                                             (int) (row * sampleRow),\r
272                                             (int) (row * sampleRow) + 1,\r
273                                             (int) (col * sampleCol),\r
274                                             (int) (row * sampleRow), 0);\r
275             mg.translate(0, 1);\r
276 \r
277             if (av.conservation != null)\r
278               ap.annotationPanel.drawGraph(mg, av.conservation,\r
279                                            (int) (sampleCol) + 1,\r
280                                            graphHeight,\r
281                                            (int) (col * sampleCol),\r
282                                            (int) (col * sampleCol) + 1);\r
283 \r
284           }\r
285           mg.translate(0, -sequencesHeight);\r
286           mg.translate(1, 0);\r
287 \r
288         }\r
289 \r
290         System.gc();\r
291 \r
292         resizing = false;\r
293 \r
294         setBoxPosition();\r
295 \r
296         if(resizeAgain)\r
297         {\r
298           resizeAgain = false;\r
299           updateOverviewImage();\r
300         }\r
301     }\r
302 \r
303     /**\r
304      * DOCUMENT ME!\r
305      */\r
306     public void setBoxPosition()\r
307     {\r
308       int fullsizeWidth = av.alignment.getWidth() * av.getCharWidth();\r
309       int fullsizeHeight = av.alignment.getHeight() * av.getCharHeight();\r
310 \r
311       scalew = (float) width / (float) fullsizeWidth;\r
312       scaleh = (float) sequencesHeight / (float) fullsizeHeight;\r
313 \r
314         boxX = (int) (av.getStartRes() * av.getCharWidth() * scalew);\r
315         boxY = (int) (av.getStartSeq() * av.getCharHeight() * scaleh);\r
316         boxWidth = (int) ((av.getEndRes() - av.getStartRes() + 1) * av.getCharWidth() * scalew);\r
317         boxHeight = (int) (av.getEndSeq() * av.getCharHeight() * scaleh) -\r
318             boxY;\r
319         repaint();\r
320     }\r
321 \r
322     /**\r
323      * DOCUMENT ME!\r
324      *\r
325      * @param g DOCUMENT ME!\r
326      */\r
327     public void paintComponent(Graphics g)\r
328     {\r
329         if (miniMe != null && !resizing)\r
330         {\r
331           g.drawImage(miniMe, 0, 0, this);\r
332         }\r
333         else\r
334         {\r
335           g.setColor(Color.white);\r
336           g.fillRect(0, 0, getWidth(), getHeight());\r
337           g.setColor(Color.black);\r
338           g.setFont(new Font("Verdana", Font.BOLD, 15));\r
339           g.drawString("Recalculating", 5, sequencesHeight / 2);\r
340           g.drawString("Overview.....", 5, (sequencesHeight / 2) + 20);\r
341         }\r
342 \r
343 \r
344         g.setColor(Color.red);\r
345         g.drawRect(boxX, boxY, boxWidth, boxHeight);\r
346         g.drawRect(boxX + 1, boxY + 1, boxWidth - 2, boxHeight - 2);\r
347 \r
348     }\r
349 }\r