Dont call fastPaint if Mac
[jalview.git] / src / jalview / appletgui / AlignmentPanel.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 \r
20 package jalview.appletgui;\r
21 \r
22 import java.awt.*;\r
23 import java.awt.event.*;\r
24 \r
25 import jalview.analysis.*;\r
26 import jalview.datamodel.*;\r
27 import jalview.jbappletgui.*;\r
28 import jalview.schemes.*;\r
29 \r
30 public class AlignmentPanel\r
31     extends GAlignmentPanel implements AdjustmentListener\r
32 {\r
33 \r
34   AlignViewport av;\r
35   OverviewPanel overviewPanel;\r
36   SeqPanel seqPanel;\r
37   IdPanel idPanel;\r
38   IdwidthAdjuster idwidthAdjuster;\r
39   public AlignFrame alignFrame;\r
40   ScalePanel scalePanel;\r
41   AnnotationPanel annotationPanel;\r
42   AnnotationLabels alabels;\r
43 \r
44   // this value is set false when selection area being dragged\r
45   boolean fastPaint = true;\r
46 \r
47   public AlignmentPanel(AlignFrame af, final AlignViewport av)\r
48   {\r
49     alignFrame = af;\r
50     this.av = av;\r
51     seqPanel = new SeqPanel(av, this);\r
52     idPanel = new IdPanel(av, this);\r
53     scalePanel = new ScalePanel(av, this);\r
54     idwidthAdjuster = new IdwidthAdjuster(this);\r
55     annotationPanel = new AnnotationPanel(this);\r
56     alabels = new AnnotationLabels(this);\r
57 \r
58     idPanelHolder.add(idPanel, BorderLayout.CENTER);\r
59     idSpaceFillerPanel1.add(idwidthAdjuster, BorderLayout.CENTER);\r
60     annotationScroller.add(annotationPanel);\r
61     annotationSpaceFillerHolder.add(alabels, BorderLayout.CENTER);\r
62     scalePanelHolder.add(scalePanel, BorderLayout.CENTER);\r
63     seqPanelHolder.add(seqPanel, BorderLayout.CENTER);\r
64 \r
65     fontChanged();\r
66     setScrollValues(0, 0);\r
67 \r
68     hscroll.addAdjustmentListener(this);\r
69     vscroll.addAdjustmentListener(this);\r
70 \r
71     seqPanel.seqCanvas.addKeyListener(new MyKeyAdapter());\r
72     idPanel.idCanvas.addKeyListener(new MyKeyAdapter());\r
73 \r
74     addComponentListener(new ComponentAdapter()\r
75     {\r
76       public void componentResized(ComponentEvent evt)\r
77       {\r
78         setScrollValues(av.getStartRes(), av.getStartSeq());\r
79         repaint();\r
80       }\r
81     });\r
82 \r
83     Dimension d = calculateIdWidth();\r
84     idPanel.idCanvas.setSize(d);\r
85 \r
86     hscrollFillerPanel.setSize(d.width, annotationPanel.getSize().height);\r
87     annotationScroller.setSize(annotationPanel.getSize());\r
88 \r
89     idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);\r
90     annotationSpaceFillerHolder.setSize(d.width,\r
91                                         annotationPanel.getSize().height);\r
92     alabels.setSize(d.width, annotationPanel.getSize().height);\r
93 \r
94   }\r
95 \r
96   class MyKeyAdapter\r
97       extends KeyAdapter\r
98   {\r
99     public void keyPressed(KeyEvent evt)\r
100     {\r
101       // System.out.println(evt.getKeyCode()); log.\r
102       switch (evt.getKeyCode())\r
103       {\r
104         case 27: // escape key\r
105           av.setSelectionGroup(null);\r
106           alignFrame.alignPanel.repaint();\r
107           break;\r
108         case KeyEvent.VK_X:\r
109           if (evt.isControlDown())\r
110           {\r
111             alignFrame.cut_actionPerformed(null);\r
112           }\r
113           break;\r
114         case KeyEvent.VK_C:\r
115           if (evt.isControlDown())\r
116           {\r
117             alignFrame.copy_actionPerformed(null);\r
118           }\r
119           break;\r
120         case KeyEvent.VK_V:\r
121           if (evt.isControlDown())\r
122           {\r
123             alignFrame.paste(true);\r
124           }\r
125           break;\r
126         case KeyEvent.VK_A:\r
127           if (evt.isControlDown())\r
128           {\r
129             alignFrame.selectAllSequenceMenuItem_actionPerformed(null);\r
130           }\r
131           break;\r
132         case KeyEvent.VK_DOWN:\r
133           alignFrame.moveSelectedSequences(false);\r
134           break;\r
135         case KeyEvent.VK_UP:\r
136           alignFrame.moveSelectedSequences(true);\r
137           break;\r
138         case KeyEvent.VK_F:\r
139           if (evt.isControlDown())\r
140           {\r
141             alignFrame.findMenuItem_actionPerformed(null);\r
142           }\r
143           break;\r
144         case KeyEvent.VK_BACK_SPACE:\r
145         case KeyEvent.VK_DELETE:\r
146           alignFrame.cut_actionPerformed(null);\r
147           break;\r
148 \r
149       }\r
150     }\r
151   }\r
152 \r
153   public void fontChanged()\r
154   {\r
155     // set idCanvas bufferedImage to null\r
156     // to prevent drawing old image\r
157     FontMetrics fm = getFontMetrics(av.getFont());\r
158 \r
159     scalePanel.setSize(new Dimension(10, av.charHeight + fm.getDescent()));\r
160     idwidthAdjuster.setSize(new Dimension(10, av.charHeight + fm.getDescent()));\r
161 \r
162     annotationPanel.adjustPanelHeight();\r
163     annotationPanel.repaint();\r
164     Dimension d = calculateIdWidth();\r
165     d.setSize(d.width + 4, seqPanel.seqCanvas.getSize().height);\r
166     idPanel.idCanvas.setSize(d);\r
167     hscrollFillerPanel.setSize(d);\r
168 \r
169     alignFrame.pack();\r
170   }\r
171 \r
172   public void setIdWidth(int w, int h)\r
173   {\r
174     idPanel.idCanvas.setSize(w, h);\r
175     idPanelHolder.setSize(w, idPanelHolder.getSize().height);\r
176     alabels.setSize(w, alabels.getSize().height);\r
177     validate();\r
178   }\r
179 \r
180   Dimension calculateIdWidth()\r
181   {\r
182     Frame frame = new Frame();\r
183     frame.addNotify();\r
184     Graphics g = frame.getGraphics();\r
185     if (g == null)\r
186     {\r
187       Frame f = new Frame();\r
188       f.addNotify();\r
189       g = f.getGraphics();\r
190     }\r
191 \r
192     FontMetrics fm = g.getFontMetrics(av.font);\r
193     AlignmentI al = av.getAlignment();\r
194 \r
195     int i = 0;\r
196     int idWidth = 0;\r
197     String id;\r
198     while (i < al.getHeight() && al.getSequenceAt(i) != null)\r
199     {\r
200       SequenceI s = al.getSequenceAt(i);\r
201       if (av.getShowFullId())\r
202       {\r
203         id = s.getDisplayId();\r
204       }\r
205       else\r
206       {\r
207         id = s.getName();\r
208       }\r
209 \r
210       if (fm.stringWidth(id) > idWidth)\r
211       {\r
212         idWidth = fm.stringWidth(id);\r
213       }\r
214       i++;\r
215     }\r
216 \r
217     // Also check annotation label widths\r
218     i = 0;\r
219     if (al.getAlignmentAnnotation() != null)\r
220     {\r
221       fm = g.getFontMetrics(frame.getFont());\r
222       while (i < al.getAlignmentAnnotation().length)\r
223       {\r
224         String label = al.getAlignmentAnnotation()[i].label;\r
225         if (fm.stringWidth(label) > idWidth)\r
226         {\r
227           idWidth = fm.stringWidth(label);\r
228         }\r
229         i++;\r
230       }\r
231     }\r
232 \r
233     return new Dimension(idWidth, idPanel.idCanvas.getSize().height);\r
234   }\r
235 \r
236   public void highlightSearchResults(int[] results)\r
237   {\r
238     seqPanel.seqCanvas.highlightSearchResults(results);\r
239 \r
240     // do we need to scroll the panel?\r
241     if (results != null)\r
242     {\r
243       SequenceI seq = av.alignment.getSequenceAt(results[0]);\r
244       int start = seq.findIndex(results[1]) - 1;\r
245       int end = seq.findIndex(results[2]) - 1;\r
246       if (av.getStartRes() > start\r
247           || av.getEndRes() < end\r
248           || (av.getStartSeq() > results[0]\r
249               || av.getEndSeq() < results[0]))\r
250       {\r
251         setScrollValues(start, results[0]);\r
252       }\r
253     }\r
254 \r
255   }\r
256 \r
257   public OverviewPanel getOverviewPanel()\r
258   {\r
259     return overviewPanel;\r
260   }\r
261 \r
262   public void setOverviewPanel(OverviewPanel op)\r
263   {\r
264     overviewPanel = op;\r
265   }\r
266 \r
267   public void setAnnotationVisible(boolean b)\r
268   {\r
269     annotationSpaceFillerHolder.setVisible(b);\r
270     annotationScroller.setVisible(b);\r
271     validate();\r
272     repaint();\r
273   }\r
274 \r
275   public void setWrapAlignment(boolean wrap)\r
276   {\r
277     scalePanelHolder.setVisible(!wrap);\r
278     hscroll.setVisible(!wrap);\r
279     idwidthAdjuster.setVisible(!wrap);\r
280 \r
281     av.setShowAnnotation(!wrap);\r
282     annotationScroller.setVisible(!wrap);\r
283     annotationSpaceFillerHolder.setVisible(!wrap);\r
284     idSpaceFillerPanel1.setVisible(!wrap);\r
285 \r
286     validate();\r
287     repaint();\r
288 \r
289   }\r
290 \r
291 \r
292   int hextent = 0;\r
293   int vextent = 0;\r
294 \r
295   // return value is true if the scroll is valid\r
296   public boolean scrollUp(boolean up)\r
297   {\r
298     if (up)\r
299     {\r
300       if (vscroll.getValue() < 1)\r
301       {\r
302         return false;\r
303       }\r
304       fastPaint = false;\r
305       vscroll.setValue(vscroll.getValue() - 1);\r
306     }\r
307     else\r
308     {\r
309       if (vextent + vscroll.getValue() >= av.getAlignment().getHeight())\r
310       {\r
311         return false;\r
312       }\r
313       fastPaint = false;\r
314       vscroll.setValue(vscroll.getValue() + 1);\r
315     }\r
316     fastPaint = true;\r
317     return true;\r
318   }\r
319 \r
320   public boolean scrollRight(boolean right)\r
321   {\r
322 \r
323     if (right)\r
324     {\r
325       if (hscroll.getValue() < 1)\r
326       {\r
327         return false;\r
328       }\r
329       fastPaint = false;\r
330       hscroll.setValue(hscroll.getValue() - 1);\r
331     }\r
332     else\r
333     {\r
334       if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())\r
335       {\r
336         return false;\r
337       }\r
338       fastPaint = false;\r
339       hscroll.setValue(hscroll.getValue() + 1);\r
340     }\r
341     fastPaint = true;\r
342     return true;\r
343   }\r
344 \r
345   public void setScrollValues(int x, int y)\r
346   {\r
347 \r
348     av.setStartRes(x);\r
349     av.setStartSeq(y);\r
350     av.setEndRes(x + seqPanel.seqCanvas.getSize().width / av.getCharWidth() - 1);\r
351 \r
352     hextent = seqPanel.seqCanvas.getSize().width / av.charWidth;\r
353     vextent = seqPanel.seqCanvas.getSize().height / av.charHeight;\r
354 \r
355     if (hextent > av.alignment.getWidth())\r
356     {\r
357       hextent = av.alignment.getWidth();\r
358     }\r
359     if (vextent > av.alignment.getHeight())\r
360     {\r
361       vextent = av.alignment.getHeight();\r
362     }\r
363 \r
364     if (hextent + x > av.getAlignment().getWidth())\r
365     {\r
366       x = av.getAlignment().getWidth() - hextent;\r
367     }\r
368 \r
369     if (vextent + y > av.getAlignment().getHeight())\r
370     {\r
371       y = av.getAlignment().getHeight() - vextent;\r
372     }\r
373 \r
374     if (y < 0)\r
375     {\r
376       y = 0;\r
377     }\r
378 \r
379     if (x < 0)\r
380     {\r
381       x = 0;\r
382     }\r
383 \r
384     int endSeq = y + vextent;\r
385     if (endSeq > av.alignment.getHeight())\r
386     {\r
387       endSeq = av.alignment.getHeight();\r
388     }\r
389 \r
390     av.setEndSeq(endSeq);\r
391     hscroll.setValues(x, hextent, 0, av.getAlignment().getWidth());\r
392     vscroll.setValues(y, vextent, 0, av.getAlignment().getHeight());\r
393 \r
394   }\r
395 \r
396   public void adjustmentValueChanged(AdjustmentEvent evt)\r
397   {\r
398     int oldX = av.getStartRes();\r
399     int oldY = av.getStartSeq();\r
400 \r
401     if (evt.getSource() == hscroll)\r
402     {\r
403       int x = hscroll.getValue();\r
404       av.setStartRes(x);\r
405       av.setEndRes(x + seqPanel.seqCanvas.getSize().width / av.getCharWidth() -\r
406                    1);\r
407     }\r
408 \r
409     if (evt.getSource() == vscroll)\r
410     {\r
411       int offy = vscroll.getValue();\r
412       if (av.getWrapAlignment())\r
413       {\r
414         int rowSize = seqPanel.seqCanvas.getWrappedCanvasWidth(seqPanel.\r
415             seqCanvas.getSize().width);\r
416         av.setStartRes(vscroll.getValue() * rowSize);\r
417         av.setEndRes( (vscroll.getValue() + 1) * rowSize);\r
418       }\r
419       else\r
420       {\r
421         av.setStartSeq(offy);\r
422         av.setEndSeq(offy +\r
423                      seqPanel.seqCanvas.getSize().height / av.getCharHeight());\r
424       }\r
425     }\r
426 \r
427     if (overviewPanel != null)\r
428     {\r
429       overviewPanel.setBoxPosition();\r
430     }\r
431 \r
432     if (av.getWrapAlignment() || !fastPaint || System.getProperty("os.name").startsWith("Mac"))\r
433     {\r
434       repaint();\r
435     }\r
436     else\r
437     {\r
438       idPanel.idCanvas.fastPaint(av.getStartSeq() - oldY);\r
439       seqPanel.seqCanvas.fastPaint(av.getStartRes() - oldX,\r
440                                    av.getStartSeq() - oldY);\r
441 \r
442       scalePanel.repaint();\r
443       if (av.getShowAnnotation())\r
444       {\r
445         annotationPanel.fastPaint(av.getStartRes() - oldX);\r
446       }\r
447     }\r
448 \r
449   }\r
450 \r
451   public void update(Graphics g)\r
452   {\r
453     paint(g);\r
454   }\r
455 \r
456   public void paint(Graphics g)\r
457   {\r
458     Dimension d = idPanel.idCanvas.getSize();\r
459     idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);\r
460     annotationSpaceFillerHolder.setSize(d.width,\r
461                                         annotationPanel.getSize().height);\r
462     alabels.setSize(d.width, annotationPanel.getSize().height);\r
463 \r
464     alabels.repaint();\r
465     idPanel.idCanvas.repaint();\r
466     seqPanel.seqCanvas.repaint();\r
467     scalePanel.repaint();\r
468     annotationPanel.repaint();\r
469 \r
470     if (av.getWrapAlignment())\r
471     {\r
472       int max = av.alignment.getWidth() /\r
473           seqPanel.seqCanvas.\r
474           getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);\r
475       vscroll.setMaximum(max);\r
476       vscroll.setUnitIncrement(1);\r
477       vscroll.setVisibleAmount(1);\r
478     }\r
479     else\r
480     {\r
481       setScrollValues(av.getStartRes(), av.getStartSeq());\r
482     }\r
483 \r
484   }\r
485 }\r