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