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