Use propertyListener for alignment edits
[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     if(overviewPanel!=null)\r
177           overviewPanel.updateOverviewImage();\r
178   }\r
179 \r
180   public void setIdWidth(int w, int h)\r
181   {\r
182     idPanel.idCanvas.setSize(w, h);\r
183     idPanelHolder.setSize(w, idPanelHolder.getSize().height);\r
184     alabels.setSize(w, alabels.getSize().height);\r
185     validate();\r
186   }\r
187 \r
188   Dimension calculateIdWidth()\r
189   {\r
190     Frame frame = new Frame();\r
191     frame.addNotify();\r
192     Graphics g = frame.getGraphics();\r
193     if (g == null)\r
194     {\r
195       Frame f = new Frame();\r
196       f.addNotify();\r
197       g = f.getGraphics();\r
198     }\r
199 \r
200     FontMetrics fm = g.getFontMetrics(av.font);\r
201     AlignmentI al = av.getAlignment();\r
202 \r
203     int i = 0;\r
204     int idWidth = 0;\r
205     String id;\r
206     while (i < al.getHeight() && al.getSequenceAt(i) != null)\r
207     {\r
208       SequenceI s = al.getSequenceAt(i);\r
209       if (av.getShowFullId())\r
210       {\r
211         id = s.getDisplayId();\r
212       }\r
213       else\r
214       {\r
215         id = s.getName();\r
216       }\r
217 \r
218       if (fm.stringWidth(id) > idWidth)\r
219       {\r
220         idWidth = fm.stringWidth(id);\r
221       }\r
222       i++;\r
223     }\r
224 \r
225     // Also check annotation label widths\r
226     i = 0;\r
227     if (al.getAlignmentAnnotation() != null)\r
228     {\r
229       fm = g.getFontMetrics(frame.getFont());\r
230       while (i < al.getAlignmentAnnotation().length)\r
231       {\r
232         String label = al.getAlignmentAnnotation()[i].label;\r
233         if (fm.stringWidth(label) > idWidth)\r
234         {\r
235           idWidth = fm.stringWidth(label);\r
236         }\r
237         i++;\r
238       }\r
239     }\r
240 \r
241     return new Dimension(idWidth, idPanel.idCanvas.getSize().height);\r
242   }\r
243 \r
244   public void highlightSearchResults(int[] results)\r
245   {\r
246     seqPanel.seqCanvas.highlightSearchResults(results);\r
247 \r
248     // do we need to scroll the panel?\r
249     if (results != null)\r
250     {\r
251       SequenceI seq = av.alignment.getSequenceAt(results[0]);\r
252       int start = seq.findIndex(results[1]) - 1;\r
253       int end = seq.findIndex(results[2]) - 1;\r
254       if (av.getStartRes() > start\r
255           || av.getEndRes() < end\r
256           || (av.getStartSeq() > results[0]\r
257               || av.getEndSeq() < results[0]))\r
258       {\r
259         setScrollValues(start, results[0]);\r
260       }\r
261     }\r
262 \r
263   }\r
264 \r
265   public OverviewPanel getOverviewPanel()\r
266   {\r
267     return overviewPanel;\r
268   }\r
269 \r
270   public void setOverviewPanel(OverviewPanel op)\r
271   {\r
272     overviewPanel = op;\r
273   }\r
274 \r
275   public void setAnnotationVisible(boolean b)\r
276   {\r
277     annotationSpaceFillerHolder.setVisible(b);\r
278     annotationScroller.setVisible(b);\r
279     validate();\r
280     repaint();\r
281   }\r
282 \r
283   public void setWrapAlignment(boolean wrap)\r
284   {\r
285     av.startSeq = 0;\r
286     scalePanelHolder.setVisible(!wrap);\r
287     hscroll.setVisible(!wrap);\r
288     idwidthAdjuster.setVisible(!wrap);\r
289 \r
290     av.setShowAnnotation(!wrap);\r
291     annotationScroller.setVisible(!wrap);\r
292     annotationSpaceFillerHolder.setVisible(!wrap);\r
293     idSpaceFillerPanel1.setVisible(!wrap);\r
294 \r
295     validate();\r
296     repaint();\r
297 \r
298   }\r
299 \r
300 \r
301   int hextent = 0;\r
302   int vextent = 0;\r
303 \r
304   // return value is true if the scroll is valid\r
305   public boolean scrollUp(boolean up)\r
306   {\r
307     if (up)\r
308     {\r
309       if (vscroll.getValue() < 1)\r
310       {\r
311         return false;\r
312       }\r
313       fastPaint = false;\r
314       vscroll.setValue(vscroll.getValue() - 1);\r
315     }\r
316     else\r
317     {\r
318       if (vextent + vscroll.getValue() >= av.getAlignment().getHeight())\r
319       {\r
320         return false;\r
321       }\r
322       fastPaint = false;\r
323       vscroll.setValue(vscroll.getValue() + 1);\r
324     }\r
325     fastPaint = true;\r
326     return true;\r
327   }\r
328 \r
329   public boolean scrollRight(boolean right)\r
330   {\r
331 \r
332     if (right)\r
333     {\r
334       if (hscroll.getValue() < 1)\r
335       {\r
336         return false;\r
337       }\r
338       fastPaint = false;\r
339       hscroll.setValue(hscroll.getValue() - 1);\r
340     }\r
341     else\r
342     {\r
343       if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())\r
344       {\r
345         return false;\r
346       }\r
347       fastPaint = false;\r
348       hscroll.setValue(hscroll.getValue() + 1);\r
349     }\r
350     fastPaint = true;\r
351     return true;\r
352   }\r
353 \r
354   public void setScrollValues(int x, int y)\r
355   {\r
356 \r
357     av.setStartRes(x);\r
358     av.setStartSeq(y);\r
359     av.setEndRes(x + seqPanel.seqCanvas.getSize().width / av.getCharWidth() - 1);\r
360 \r
361     hextent = seqPanel.seqCanvas.getSize().width / av.charWidth;\r
362     vextent = seqPanel.seqCanvas.getSize().height / av.charHeight;\r
363 \r
364     if (hextent > av.alignment.getWidth())\r
365     {\r
366       hextent = av.alignment.getWidth();\r
367     }\r
368     if (vextent > av.alignment.getHeight())\r
369     {\r
370       vextent = av.alignment.getHeight();\r
371     }\r
372 \r
373     if (hextent + x > av.getAlignment().getWidth())\r
374     {\r
375       x = av.getAlignment().getWidth() - hextent;\r
376     }\r
377 \r
378     if (vextent + y > av.getAlignment().getHeight())\r
379     {\r
380       y = av.getAlignment().getHeight() - vextent;\r
381     }\r
382 \r
383     if (y < 0)\r
384     {\r
385       y = 0;\r
386     }\r
387 \r
388     if (x < 0)\r
389     {\r
390       x = 0;\r
391     }\r
392 \r
393     int endSeq = y + vextent;\r
394     if (endSeq > av.alignment.getHeight())\r
395     {\r
396       endSeq = av.alignment.getHeight();\r
397     }\r
398 \r
399     av.setEndSeq(endSeq);\r
400     hscroll.setValues(x, hextent, 0, av.getAlignment().getWidth());\r
401     vscroll.setValues(y, vextent, 0, av.getAlignment().getHeight());\r
402 \r
403   }\r
404 \r
405   public void adjustmentValueChanged(AdjustmentEvent evt)\r
406   {\r
407     int oldX = av.getStartRes();\r
408     int oldY = av.getStartSeq();\r
409 \r
410     if (evt.getSource() == hscroll)\r
411     {\r
412       int x = hscroll.getValue();\r
413       av.setStartRes(x);\r
414       av.setEndRes(x + seqPanel.seqCanvas.getSize().width / av.getCharWidth() -\r
415                    1);\r
416     }\r
417 \r
418     if (evt.getSource() == vscroll)\r
419     {\r
420       int offy = vscroll.getValue();\r
421       if (av.getWrapAlignment())\r
422       {\r
423         int rowSize = seqPanel.seqCanvas.getWrappedCanvasWidth(seqPanel.\r
424             seqCanvas.getSize().width);\r
425         av.setStartRes(vscroll.getValue() * rowSize);\r
426         av.setEndRes( (vscroll.getValue() + 1) * rowSize);\r
427       }\r
428       else\r
429       {\r
430         av.setStartSeq(offy);\r
431         av.setEndSeq(offy +\r
432                      seqPanel.seqCanvas.getSize().height / av.getCharHeight());\r
433       }\r
434     }\r
435 \r
436     if (overviewPanel != null)\r
437     {\r
438       overviewPanel.setBoxPosition();\r
439     }\r
440 \r
441     if (av.getWrapAlignment() || !fastPaint || MAC)\r
442     {\r
443       repaint();\r
444     }\r
445     else\r
446     {\r
447       idPanel.idCanvas.fastPaint(av.getStartSeq() - oldY);\r
448       seqPanel.seqCanvas.fastPaint(av.getStartRes() - oldX,\r
449                                    av.getStartSeq() - oldY);\r
450 \r
451       scalePanel.repaint();\r
452       if (av.getShowAnnotation())\r
453       {\r
454         annotationPanel.fastPaint(av.getStartRes() - oldX);\r
455       }\r
456     }\r
457 \r
458   }\r
459 \r
460   public void update(Graphics g)\r
461   {\r
462     paint(g);\r
463   }\r
464 \r
465   public void paint(Graphics g)\r
466   {\r
467     Dimension d = idPanel.idCanvas.getSize();\r
468     idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);\r
469     annotationSpaceFillerHolder.setSize(d.width,\r
470                                         annotationPanel.getSize().height);\r
471 \r
472     alabels.setSize(d.width, annotationPanel.getSize().height);\r
473 \r
474     if (av.getWrapAlignment())\r
475     {\r
476       int max = av.alignment.getWidth() /\r
477           seqPanel.seqCanvas.\r
478           getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);\r
479       vscroll.setMaximum(max);\r
480       vscroll.setUnitIncrement(1);\r
481       vscroll.setVisibleAmount(1);\r
482     }\r
483     else\r
484     {\r
485       setScrollValues(av.getStartRes(), av.getStartSeq());\r
486     }\r
487 \r
488     alabels.repaint();\r
489     idPanel.idCanvas.repaint();\r
490     seqPanel.seqCanvas.repaint();\r
491     scalePanel.repaint();\r
492     annotationPanel.repaint();\r
493 \r
494   }\r
495 }\r