Use paintAlignment
[jalview.git] / src / jalview / appletgui / AlignmentPanel.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2007 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.datamodel.*;\r
26 \r
27 public class AlignmentPanel\r
28     extends Panel implements AdjustmentListener\r
29 {\r
30 \r
31   public AlignViewport av;\r
32   OverviewPanel overviewPanel;\r
33   SeqPanel seqPanel;\r
34   IdPanel idPanel;\r
35   IdwidthAdjuster idwidthAdjuster;\r
36   public AlignFrame alignFrame;\r
37   ScalePanel scalePanel;\r
38   AnnotationPanel annotationPanel;\r
39   AnnotationLabels alabels;\r
40 \r
41   // this value is set false when selection area being dragged\r
42   boolean fastPaint = true;\r
43 \r
44   public AlignmentPanel(AlignFrame af, final AlignViewport av)\r
45   {\r
46     try\r
47     {\r
48       jbInit();\r
49     }\r
50     catch (Exception e)\r
51     {\r
52       e.printStackTrace();\r
53     }\r
54 \r
55     alignFrame = af;\r
56     this.av = av;\r
57     seqPanel = new SeqPanel(av, this);\r
58     idPanel = new IdPanel(av, this);\r
59     scalePanel = new ScalePanel(av, this);\r
60     idwidthAdjuster = new IdwidthAdjuster(this);\r
61     annotationPanel = new AnnotationPanel(this);\r
62 \r
63     sequenceHolderPanel.add(annotationPanel, BorderLayout.SOUTH);\r
64 \r
65     alabels = new AnnotationLabels(this);\r
66 \r
67     setAnnotationVisible(av.showAnnotation);\r
68 \r
69     idPanelHolder.add(idPanel, BorderLayout.CENTER);\r
70     idSpaceFillerPanel1.add(idwidthAdjuster, BorderLayout.CENTER);\r
71     annotationSpaceFillerHolder.add(alabels, BorderLayout.CENTER);\r
72     scalePanelHolder.add(scalePanel, BorderLayout.CENTER);\r
73     seqPanelHolder.add(seqPanel, BorderLayout.CENTER);\r
74 \r
75     fontChanged();\r
76     setScrollValues(0, 0);\r
77 \r
78     hscroll.addAdjustmentListener(this);\r
79     vscroll.addAdjustmentListener(this);\r
80 \r
81     addComponentListener(new ComponentAdapter()\r
82     {\r
83       public void componentResized(ComponentEvent evt)\r
84       {\r
85         setScrollValues(av.getStartRes(), av.getStartSeq());\r
86         repaint();\r
87       }\r
88     });\r
89 \r
90     Dimension d = calculateIdWidth();\r
91     idPanel.idCanvas.setSize(d);\r
92 \r
93     hscrollFillerPanel.setSize(d.width, annotationPanel.getSize().height);\r
94 \r
95     idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);\r
96     annotationSpaceFillerHolder.setSize(d.width,\r
97                                         annotationPanel.getSize().height);\r
98     alabels.setSize(d.width, annotationPanel.getSize().height);\r
99 \r
100     final AlignmentPanel ap = this;\r
101     av.addPropertyChangeListener(new java.beans.PropertyChangeListener()\r
102     {\r
103       public void propertyChange(java.beans.PropertyChangeEvent evt)\r
104       {\r
105         if (evt.getPropertyName().equals("alignment"))\r
106         {\r
107           PaintRefresher.Refresh(ap,\r
108                                  av.getSequenceSetId(),\r
109                                  true,\r
110                                  true);\r
111           alignmentChanged();\r
112         }\r
113       }\r
114     });\r
115 \r
116   }\r
117 \r
118   public SequenceRenderer getSequenceRenderer()\r
119   {\r
120     return seqPanel.seqCanvas.sr;\r
121   }\r
122 \r
123   public FeatureRenderer getFeatureRenderer()\r
124   {\r
125     return seqPanel.seqCanvas.fr;\r
126   }\r
127 \r
128   public void alignmentChanged()\r
129   {\r
130     av.alignmentChanged(this);\r
131 \r
132     if (overviewPanel != null)\r
133     {\r
134       overviewPanel.updateOverviewImage();\r
135     }\r
136 \r
137     alignFrame.updateEditMenuBar();\r
138 \r
139     repaint();\r
140   }\r
141 \r
142   public void fontChanged()\r
143   {\r
144     // set idCanvas bufferedImage to null\r
145     // to prevent drawing old image\r
146     idPanel.idCanvas.image = null;\r
147     FontMetrics fm = getFontMetrics(av.getFont());\r
148 \r
149     scalePanel.setSize(new Dimension(10, av.charHeight + fm.getDescent()));\r
150     idwidthAdjuster.setSize(new Dimension(10, av.charHeight + fm.getDescent()));\r
151 \r
152     annotationPanel.image = null;\r
153     int ap = annotationPanel.adjustPanelHeight();\r
154     annotationPanel.repaint();\r
155     Dimension d = calculateIdWidth();\r
156     d.setSize(d.width + 4, seqPanel.seqCanvas.getSize().height);\r
157     alabels.setSize(d.width + 4, ap);\r
158     idPanel.idCanvas.setSize(d);\r
159     hscrollFillerPanel.setSize(d);\r
160 \r
161     validate();\r
162     repaint();\r
163 \r
164     if (overviewPanel != null)\r
165     {\r
166       overviewPanel.updateOverviewImage();\r
167     }\r
168   }\r
169 \r
170   public void setIdWidth(int w, int h)\r
171   {\r
172     idPanel.idCanvas.setSize(w, h);\r
173     idPanelHolder.setSize(w, idPanelHolder.getSize().height);\r
174     alabels.setSize(w, alabels.getSize().height);\r
175     validate();\r
176   }\r
177 \r
178   Dimension calculateIdWidth()\r
179   {\r
180     if (av.nullFrame == null)\r
181     {\r
182       av.nullFrame = new Frame();\r
183       av.nullFrame.addNotify();\r
184     }\r
185 \r
186     Graphics g = av.nullFrame.getGraphics();\r
187 \r
188     FontMetrics fm = g.getFontMetrics(av.font);\r
189     AlignmentI al = av.getAlignment();\r
190 \r
191     int i = 0;\r
192     int idWidth = 0;\r
193     String id;\r
194     while (i < al.getHeight() && al.getSequenceAt(i) != null)\r
195     {\r
196       SequenceI s = al.getSequenceAt(i);\r
197       id = s.getDisplayId(av.getShowJVSuffix());\r
198 \r
199       if (fm.stringWidth(id) > idWidth)\r
200       {\r
201         idWidth = fm.stringWidth(id);\r
202       }\r
203       i++;\r
204     }\r
205 \r
206     // Also check annotation label widths\r
207     i = 0;\r
208     if (al.getAlignmentAnnotation() != null)\r
209     {\r
210       fm = g.getFontMetrics(av.nullFrame.getFont());\r
211       while (i < al.getAlignmentAnnotation().length)\r
212       {\r
213         String label = al.getAlignmentAnnotation()[i].label;\r
214         if (fm.stringWidth(label) > idWidth)\r
215         {\r
216           idWidth = fm.stringWidth(label);\r
217         }\r
218         i++;\r
219       }\r
220     }\r
221 \r
222     return new Dimension(idWidth, idPanel.idCanvas.getSize().height);\r
223   }\r
224 \r
225   public void highlightSearchResults(SearchResults results)\r
226   {\r
227     seqPanel.seqCanvas.highlightSearchResults(results);\r
228 \r
229     // do we need to scroll the panel?\r
230     if (results != null)\r
231     {\r
232       SequenceI seq = results.getResultSequence(0);\r
233       int seqIndex = av.alignment.findIndex(seq);\r
234       int start = seq.findIndex(results.getResultStart(0)) - 1;\r
235       int end = seq.findIndex(results.getResultEnd(0)) - 1;\r
236 \r
237       if (!av.wrapAlignment)\r
238       {\r
239         if ( (av.getStartRes() > end) || (av.getEndRes() < start) ||\r
240             ( (av.getStartSeq() > seqIndex) || (av.getEndSeq() < seqIndex)))\r
241         {\r
242           if (start > av.alignment.getWidth() - hextent)\r
243           {\r
244             start = av.alignment.getWidth() - hextent;\r
245             if (start < 0)\r
246             {\r
247               start = 0;\r
248             }\r
249           }\r
250           if (seqIndex > av.alignment.getHeight() - vextent)\r
251           {\r
252             seqIndex = av.alignment.getHeight() - vextent;\r
253             if (seqIndex < 0)\r
254             {\r
255               seqIndex = 0;\r
256             }\r
257           }\r
258           setScrollValues(start, seqIndex);\r
259         }\r
260       }\r
261       else\r
262       {\r
263         scrollToWrappedVisible(start);\r
264       }\r
265     }\r
266 \r
267     repaint();\r
268   }\r
269 \r
270   void scrollToWrappedVisible(int res)\r
271   {\r
272     int cwidth = seqPanel.seqCanvas.getWrappedCanvasWidth(seqPanel.seqCanvas.\r
273         getSize().width);\r
274     if (res <= av.getStartRes() || res >= (av.getStartRes() + cwidth))\r
275     {\r
276       vscroll.setValue(res / cwidth);\r
277       av.startRes = vscroll.getValue() * cwidth;\r
278     }\r
279   }\r
280 \r
281   public OverviewPanel getOverviewPanel()\r
282   {\r
283     return overviewPanel;\r
284   }\r
285 \r
286   public void setOverviewPanel(OverviewPanel op)\r
287   {\r
288     overviewPanel = op;\r
289   }\r
290 \r
291   public void setAnnotationVisible(boolean b)\r
292   {\r
293     if (!av.wrapAlignment)\r
294     {\r
295       annotationSpaceFillerHolder.setVisible(b);\r
296       annotationPanel.setVisible(b);\r
297     }\r
298     validate();\r
299     repaint();\r
300   }\r
301 \r
302   public void setWrapAlignment(boolean wrap)\r
303   {\r
304     av.startSeq = 0;\r
305     av.startRes = 0;\r
306     scalePanelHolder.setVisible(!wrap);\r
307 \r
308     hscroll.setVisible(!wrap);\r
309     idwidthAdjuster.setVisible(!wrap);\r
310 \r
311     if (wrap)\r
312     {\r
313       annotationPanel.setVisible(false);\r
314       annotationSpaceFillerHolder.setVisible(false);\r
315     }\r
316     else if (av.showAnnotation)\r
317     {\r
318       annotationPanel.setVisible(true);\r
319       annotationSpaceFillerHolder.setVisible(true);\r
320     }\r
321 \r
322     idSpaceFillerPanel1.setVisible(!wrap);\r
323 \r
324     fontChanged(); //This is so that the scalePanel is resized correctly\r
325 \r
326     validate();\r
327     repaint();\r
328 \r
329   }\r
330 \r
331   int hextent = 0;\r
332   int vextent = 0;\r
333 \r
334   // return value is true if the scroll is valid\r
335   public boolean scrollUp(boolean up)\r
336   {\r
337     if (up)\r
338     {\r
339       if (vscroll.getValue() < 1)\r
340       {\r
341         return false;\r
342       }\r
343       setScrollValues(hscroll.getValue(), vscroll.getValue() - 1);\r
344     }\r
345     else\r
346     {\r
347       if (vextent + vscroll.getValue() >= av.getAlignment().getHeight())\r
348       {\r
349         return false;\r
350       }\r
351       setScrollValues(hscroll.getValue(), vscroll.getValue() + 1);\r
352     }\r
353 \r
354     repaint();\r
355     return true;\r
356   }\r
357 \r
358   public boolean scrollRight(boolean right)\r
359   {\r
360     if (!right)\r
361     {\r
362       if (hscroll.getValue() < 1)\r
363       {\r
364         return false;\r
365       }\r
366       setScrollValues(hscroll.getValue() - 1, vscroll.getValue());\r
367     }\r
368     else\r
369     {\r
370       if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())\r
371       {\r
372         return false;\r
373       }\r
374       setScrollValues(hscroll.getValue() + 1, vscroll.getValue());\r
375     }\r
376 \r
377     repaint();\r
378     return true;\r
379   }\r
380 \r
381   public void setScrollValues(int x, int y)\r
382   {\r
383     int width = av.alignment.getWidth();\r
384     int height = av.alignment.getHeight();\r
385 \r
386     if (av.hasHiddenColumns)\r
387     {\r
388       width = av.getColumnSelection().findColumnPosition(width);\r
389     }\r
390 \r
391     av.setStartRes(x);\r
392     av.setEndRes( (x + (seqPanel.seqCanvas.getSize().width / av.charWidth)) - 1);\r
393 \r
394     hextent = seqPanel.seqCanvas.getSize().width / av.charWidth;\r
395     vextent = seqPanel.seqCanvas.getSize().height / av.charHeight;\r
396 \r
397     if (hextent > width)\r
398     {\r
399       hextent = width;\r
400     }\r
401 \r
402     if (vextent > height)\r
403     {\r
404       vextent = height;\r
405     }\r
406 \r
407     if ( (hextent + x) > width)\r
408     {\r
409       x = width - hextent;\r
410     }\r
411 \r
412     if ( (vextent + y) > height)\r
413     {\r
414       y = height - vextent;\r
415     }\r
416 \r
417     if (y < 0)\r
418     {\r
419       y = 0;\r
420     }\r
421 \r
422     if (x < 0)\r
423     {\r
424       x = 0;\r
425     }\r
426 \r
427     av.setStartSeq(y);\r
428 \r
429     int endSeq = y + vextent;\r
430     if (endSeq > av.alignment.getHeight())\r
431     {\r
432       endSeq = av.alignment.getHeight();\r
433     }\r
434 \r
435     av.setEndSeq(endSeq);\r
436     hscroll.setValues(x, hextent, 0, width);\r
437     vscroll.setValues(y, vextent, 0, height);\r
438 \r
439     if (overviewPanel != null)\r
440     {\r
441       overviewPanel.setBoxPosition();\r
442     }\r
443 \r
444   }\r
445 \r
446   public void adjustmentValueChanged(AdjustmentEvent evt)\r
447   {\r
448     int oldX = av.getStartRes();\r
449     int oldY = av.getStartSeq();\r
450 \r
451     if (evt == null || evt.getSource() == hscroll)\r
452     {\r
453       int x = hscroll.getValue();\r
454       av.setStartRes(x);\r
455       av.setEndRes(x + seqPanel.seqCanvas.getSize().width / av.getCharWidth() -\r
456                    1);\r
457     }\r
458 \r
459     if (evt == null || evt.getSource() == vscroll)\r
460     {\r
461       int offy = vscroll.getValue();\r
462       if (av.getWrapAlignment())\r
463       {\r
464         int rowSize = seqPanel.seqCanvas.getWrappedCanvasWidth(seqPanel.\r
465             seqCanvas.getSize().width);\r
466         av.setStartRes(vscroll.getValue() * rowSize);\r
467         av.setEndRes( (vscroll.getValue() + 1) * rowSize);\r
468       }\r
469       else\r
470       {\r
471         av.setStartSeq(offy);\r
472         av.setEndSeq(offy +\r
473                      seqPanel.seqCanvas.getSize().height / av.getCharHeight());\r
474       }\r
475     }\r
476 \r
477     if (overviewPanel != null)\r
478     {\r
479       overviewPanel.setBoxPosition();\r
480     }\r
481 \r
482     int scrollX = av.startRes - oldX;\r
483     int scrollY = av.startSeq - oldY;\r
484 \r
485     if (av.getWrapAlignment() || !fastPaint || av.MAC)\r
486     {\r
487       repaint();\r
488     }\r
489     else\r
490     {\r
491       // Make sure we're not trying to draw a panel\r
492       // larger than the visible window\r
493       if (scrollX > av.endRes - av.startRes)\r
494       {\r
495         scrollX = av.endRes - av.startRes;\r
496       }\r
497       else if (scrollX < av.startRes - av.endRes)\r
498       {\r
499         scrollX = av.startRes - av.endRes;\r
500       }\r
501 \r
502       idPanel.idCanvas.fastPaint(scrollY);\r
503       seqPanel.seqCanvas.fastPaint(scrollX,\r
504                                    scrollY);\r
505 \r
506       scalePanel.repaint();\r
507       if (av.getShowAnnotation())\r
508       {\r
509         annotationPanel.fastPaint(av.getStartRes() - oldX);\r
510       }\r
511     }\r
512 \r
513   }\r
514 \r
515   public void paintAlignment(boolean updateOverview)\r
516   {\r
517     repaint();\r
518 \r
519     if(updateOverview)\r
520     {\r
521       jalview.structure.StructureSelectionManager.getStructureSelectionManager()\r
522           .sequenceColoursChanged(this);\r
523 \r
524       if (overviewPanel != null)\r
525       {\r
526         overviewPanel.updateOverviewImage();\r
527       }\r
528     }\r
529   }\r
530 \r
531   public void update(Graphics g)\r
532   {\r
533     paint(g);\r
534   }\r
535 \r
536   public void paint(Graphics g)\r
537   {\r
538     invalidate();\r
539     Dimension d = idPanel.idCanvas.getSize();\r
540     idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);\r
541     annotationSpaceFillerHolder.setSize(d.width,\r
542                                         annotationPanel.getSize().height);\r
543 \r
544     alabels.setSize(d.width, annotationPanel.getSize().height);\r
545 \r
546     if (av.getWrapAlignment())\r
547     {\r
548       int maxwidth = av.alignment.getWidth();\r
549 \r
550       if (av.hasHiddenColumns)\r
551       {\r
552         maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;\r
553       }\r
554 \r
555       int canvasWidth = seqPanel.seqCanvas.getWrappedCanvasWidth\r
556           (seqPanel.seqCanvas.getSize().width);\r
557 \r
558       if (canvasWidth > 0)\r
559       {\r
560         int max = maxwidth / canvasWidth;\r
561         vscroll.setMaximum(max);\r
562         vscroll.setUnitIncrement(1);\r
563         vscroll.setVisibleAmount(1);\r
564       }\r
565     }\r
566     else\r
567     {\r
568       setScrollValues(av.getStartRes(), av.getStartSeq());\r
569     }\r
570 \r
571     alabels.repaint();\r
572 \r
573     seqPanel.seqCanvas.repaint();\r
574     scalePanel.repaint();\r
575     annotationPanel.repaint();\r
576     idPanel.idCanvas.repaint();\r
577   }\r
578 \r
579   protected Panel sequenceHolderPanel = new Panel();\r
580   protected Scrollbar vscroll = new Scrollbar();\r
581   protected Scrollbar hscroll = new Scrollbar();\r
582   protected Panel seqPanelHolder = new Panel();\r
583   BorderLayout borderLayout1 = new BorderLayout();\r
584   BorderLayout borderLayout3 = new BorderLayout();\r
585   protected Panel scalePanelHolder = new Panel();\r
586   protected Panel idPanelHolder = new Panel();\r
587   BorderLayout borderLayout5 = new BorderLayout();\r
588   protected Panel idSpaceFillerPanel1 = new Panel();\r
589   public Panel annotationSpaceFillerHolder = new Panel();\r
590   BorderLayout borderLayout6 = new BorderLayout();\r
591   BorderLayout borderLayout7 = new BorderLayout();\r
592   Panel hscrollHolder = new Panel();\r
593   BorderLayout borderLayout10 = new BorderLayout();\r
594   protected Panel hscrollFillerPanel = new Panel();\r
595   BorderLayout borderLayout11 = new BorderLayout();\r
596   BorderLayout borderLayout4 = new BorderLayout();\r
597   BorderLayout borderLayout2 = new BorderLayout();\r
598 \r
599   private void jbInit()\r
600       throws Exception\r
601   {\r
602     //  idPanelHolder.setPreferredSize(new Dimension(70, 10));\r
603     this.setLayout(borderLayout7);\r
604 \r
605     //   sequenceHolderPanel.setPreferredSize(new Dimension(150, 150));\r
606     sequenceHolderPanel.setLayout(borderLayout3);\r
607     seqPanelHolder.setLayout(borderLayout1);\r
608     scalePanelHolder.setBackground(Color.white);\r
609 \r
610     // scalePanelHolder.setPreferredSize(new Dimension(10, 30));\r
611     scalePanelHolder.setLayout(borderLayout6);\r
612     idPanelHolder.setLayout(borderLayout5);\r
613     idSpaceFillerPanel1.setBackground(Color.white);\r
614 \r
615     //  idSpaceFillerPanel1.setPreferredSize(new Dimension(10, 30));\r
616     idSpaceFillerPanel1.setLayout(borderLayout11);\r
617     annotationSpaceFillerHolder.setBackground(Color.white);\r
618 \r
619     //  annotationSpaceFillerHolder.setPreferredSize(new Dimension(10, 80));\r
620     annotationSpaceFillerHolder.setLayout(borderLayout4);\r
621     hscroll.setOrientation(Scrollbar.HORIZONTAL);\r
622     hscrollHolder.setLayout(borderLayout10);\r
623     hscrollFillerPanel.setBackground(Color.white);\r
624 \r
625     //  hscrollFillerPanel.setPreferredSize(new Dimension(70, 10));\r
626     hscrollHolder.setBackground(Color.white);\r
627 \r
628     //    annotationScroller.setPreferredSize(new Dimension(10, 80));\r
629     //  this.setPreferredSize(new Dimension(220, 166));\r
630     seqPanelHolder.setBackground(Color.white);\r
631     idPanelHolder.setBackground(Color.white);\r
632     sequenceHolderPanel.add(scalePanelHolder, BorderLayout.NORTH);\r
633     sequenceHolderPanel.add(seqPanelHolder, BorderLayout.CENTER);\r
634     seqPanelHolder.add(vscroll, BorderLayout.EAST);\r
635 \r
636     //  Panel3.add(secondaryPanelHolder,  BorderLayout.SOUTH);\r
637     this.add(idPanelHolder, BorderLayout.WEST);\r
638     idPanelHolder.add(idSpaceFillerPanel1, BorderLayout.NORTH);\r
639     idPanelHolder.add(annotationSpaceFillerHolder, BorderLayout.SOUTH);\r
640     this.add(hscrollHolder, BorderLayout.SOUTH);\r
641     hscrollHolder.add(hscroll, BorderLayout.CENTER);\r
642     hscrollHolder.add(hscrollFillerPanel, BorderLayout.WEST);\r
643     this.add(sequenceHolderPanel, BorderLayout.CENTER);\r
644   }\r
645 \r
646 }\r