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