press del to cut
[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   public void setColourScheme()\r
292   {\r
293     ColourSchemeI cs = av.getGlobalColourScheme();\r
294 \r
295     if (av.getConservationSelected())\r
296     {\r
297 \r
298       Alignment al = (Alignment) av.getAlignment();\r
299       Conservation c = new Conservation("All",\r
300                                         ResidueProperties.propHash, 3,\r
301                                         al.getSequences(), 0,\r
302                                         al.getWidth());\r
303 \r
304       c.calculate();\r
305       c.verdict(false, av.ConsPercGaps);\r
306       ConservationColourScheme ccs = new ConservationColourScheme(c, cs);\r
307 \r
308       av.setGlobalColourScheme(ccs);\r
309 \r
310     }\r
311 \r
312     repaint();\r
313   }\r
314 \r
315   int hextent = 0;\r
316   int vextent = 0;\r
317 \r
318   // return value is true if the scroll is valid\r
319   public boolean scrollUp(boolean up)\r
320   {\r
321     if (up)\r
322     {\r
323       if (vscroll.getValue() < 1)\r
324       {\r
325         return false;\r
326       }\r
327       fastPaint = false;\r
328       vscroll.setValue(vscroll.getValue() - 1);\r
329     }\r
330     else\r
331     {\r
332       if (vextent + vscroll.getValue() >= av.getAlignment().getHeight())\r
333       {\r
334         return false;\r
335       }\r
336       fastPaint = false;\r
337       vscroll.setValue(vscroll.getValue() + 1);\r
338     }\r
339     fastPaint = true;\r
340     return true;\r
341   }\r
342 \r
343   public boolean scrollRight(boolean right)\r
344   {\r
345 \r
346     if (right)\r
347     {\r
348       if (hscroll.getValue() < 1)\r
349       {\r
350         return false;\r
351       }\r
352       fastPaint = false;\r
353       hscroll.setValue(hscroll.getValue() - 1);\r
354     }\r
355     else\r
356     {\r
357       if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())\r
358       {\r
359         return false;\r
360       }\r
361       fastPaint = false;\r
362       hscroll.setValue(hscroll.getValue() + 1);\r
363     }\r
364     fastPaint = true;\r
365     return true;\r
366   }\r
367 \r
368   public void setScrollValues(int x, int y)\r
369   {\r
370 \r
371     av.setStartRes(x);\r
372     av.setStartSeq(y);\r
373     av.setEndRes(x + seqPanel.seqCanvas.getSize().width / av.getCharWidth() - 1);\r
374 \r
375     hextent = seqPanel.seqCanvas.getSize().width / av.charWidth;\r
376     vextent = seqPanel.seqCanvas.getSize().height / av.charHeight;\r
377 \r
378     if (hextent > av.alignment.getWidth())\r
379     {\r
380       hextent = av.alignment.getWidth();\r
381     }\r
382     if (vextent > av.alignment.getHeight())\r
383     {\r
384       vextent = av.alignment.getHeight();\r
385     }\r
386 \r
387     if (hextent + x > av.getAlignment().getWidth())\r
388     {\r
389       x = av.getAlignment().getWidth() - hextent;\r
390     }\r
391 \r
392     if (vextent + y > av.getAlignment().getHeight())\r
393     {\r
394       y = av.getAlignment().getHeight() - vextent;\r
395     }\r
396 \r
397     if (y < 0)\r
398     {\r
399       y = 0;\r
400     }\r
401 \r
402     if (x < 0)\r
403     {\r
404       x = 0;\r
405     }\r
406 \r
407     int endSeq = y + vextent;\r
408     if (endSeq > av.alignment.getHeight())\r
409     {\r
410       endSeq = av.alignment.getHeight();\r
411     }\r
412 \r
413     av.setEndSeq(endSeq);\r
414     hscroll.setValues(x, hextent, 0, av.getAlignment().getWidth());\r
415     vscroll.setValues(y, vextent, 0, av.getAlignment().getHeight());\r
416 \r
417   }\r
418 \r
419   public void adjustmentValueChanged(AdjustmentEvent evt)\r
420   {\r
421     int oldX = av.getStartRes();\r
422     int oldY = av.getStartSeq();\r
423 \r
424     if (evt.getSource() == hscroll)\r
425     {\r
426       int x = hscroll.getValue();\r
427       av.setStartRes(x);\r
428       av.setEndRes(x + seqPanel.seqCanvas.getSize().width / av.getCharWidth() -\r
429                    1);\r
430     }\r
431 \r
432     if (evt.getSource() == vscroll)\r
433     {\r
434       int offy = vscroll.getValue();\r
435       if (av.getWrapAlignment())\r
436       {\r
437         int rowSize = seqPanel.seqCanvas.getWrappedCanvasWidth(seqPanel.\r
438             seqCanvas.getSize().width);\r
439         av.setStartRes(vscroll.getValue() * rowSize);\r
440         av.setEndRes( (vscroll.getValue() + 1) * rowSize);\r
441       }\r
442       else\r
443       {\r
444         av.setStartSeq(offy);\r
445         av.setEndSeq(offy +\r
446                      seqPanel.seqCanvas.getSize().height / av.getCharHeight());\r
447       }\r
448     }\r
449 \r
450     if (overviewPanel != null)\r
451     {\r
452       overviewPanel.setBoxPosition();\r
453     }\r
454 \r
455     if (av.getWrapAlignment() || !fastPaint)\r
456     {\r
457       repaint();\r
458     }\r
459     else\r
460     {\r
461       idPanel.idCanvas.fastPaint(av.getStartSeq() - oldY);\r
462       seqPanel.seqCanvas.fastPaint(av.getStartRes() - oldX,\r
463                                    av.getStartSeq() - oldY);\r
464 \r
465       scalePanel.repaint();\r
466       if (av.getShowAnnotation())\r
467       {\r
468         annotationPanel.fastPaint(av.getStartRes() - oldX);\r
469       }\r
470     }\r
471 \r
472   }\r
473 \r
474   public void update(Graphics g)\r
475   {\r
476     paint(g);\r
477   }\r
478 \r
479   public void paint(Graphics g)\r
480   {\r
481     Dimension d = idPanel.idCanvas.getSize();\r
482     idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);\r
483     annotationSpaceFillerHolder.setSize(d.width,\r
484                                         annotationPanel.getSize().height);\r
485     alabels.setSize(d.width, annotationPanel.getSize().height);\r
486 \r
487     alabels.repaint();\r
488     idPanel.idCanvas.repaint();\r
489     seqPanel.seqCanvas.repaint();\r
490     scalePanel.repaint();\r
491     annotationPanel.repaint();\r
492 \r
493     if (av.getWrapAlignment())\r
494     {\r
495       int max = av.alignment.getWidth() /\r
496           seqPanel.seqCanvas.\r
497           getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);\r
498       vscroll.setMaximum(max);\r
499       vscroll.setUnitIncrement(1);\r
500       vscroll.setVisibleAmount(1);\r
501     }\r
502     else\r
503     {\r
504       setScrollValues(av.getStartRes(), av.getStartSeq());\r
505     }\r
506 \r
507   }\r
508 }\r