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