b2f58b9a3d151f52e7da199e63eb421bd2ebf041
[jalview.git] / src / jalview / appletgui / AlignmentPanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.appletgui;
22
23 import jalview.api.AlignmentViewPanel;
24 import jalview.datamodel.AlignmentI;
25 import jalview.datamodel.SearchResults;
26 import jalview.datamodel.SequenceI;
27 import jalview.structure.StructureSelectionManager;
28
29 import java.awt.BorderLayout;
30 import java.awt.Color;
31 import java.awt.Dimension;
32 import java.awt.FontMetrics;
33 import java.awt.Frame;
34 import java.awt.Graphics;
35 import java.awt.Panel;
36 import java.awt.Scrollbar;
37 import java.awt.event.AdjustmentEvent;
38 import java.awt.event.AdjustmentListener;
39 import java.awt.event.ComponentAdapter;
40 import java.awt.event.ComponentEvent;
41
42 public class AlignmentPanel extends Panel implements AdjustmentListener,
43         AlignmentViewPanel
44 {
45
46   public AlignViewport av;
47
48   OverviewPanel overviewPanel;
49
50   SeqPanel seqPanel;
51
52   IdPanel idPanel;
53
54   IdwidthAdjuster idwidthAdjuster;
55
56   public AlignFrame alignFrame;
57
58   ScalePanel scalePanel;
59
60   AnnotationPanel annotationPanel;
61
62   AnnotationLabels alabels;
63
64   // this value is set false when selection area being dragged
65   boolean fastPaint = true;
66
67   public void finalize()
68   {
69     alignFrame = null;
70     av = null;
71     seqPanel = null;
72     seqPanelHolder = null;
73     sequenceHolderPanel = null;
74     scalePanel = null;
75     scalePanelHolder = null;
76     annotationPanel = null;
77     annotationPanelHolder = null;
78     annotationSpaceFillerHolder = null;
79   }
80
81   public AlignmentPanel(AlignFrame af, final AlignViewport av)
82   {
83     try
84     {
85       jbInit();
86     } catch (Exception e)
87     {
88       e.printStackTrace();
89     }
90
91     alignFrame = af;
92     this.av = av;
93     seqPanel = new SeqPanel(av, this);
94     idPanel = new IdPanel(av, this);
95     scalePanel = new ScalePanel(av, this);
96     idwidthAdjuster = new IdwidthAdjuster(this);
97     annotationPanel = new AnnotationPanel(this);
98     annotationPanelHolder.add(annotationPanel, BorderLayout.CENTER);
99
100     sequenceHolderPanel.add(annotationPanelHolder, BorderLayout.SOUTH);
101     alabels = new AnnotationLabels(this);
102
103     setAnnotationVisible(av.showAnnotation);
104
105     idPanelHolder.add(idPanel, BorderLayout.CENTER);
106     idSpaceFillerPanel1.add(idwidthAdjuster, BorderLayout.CENTER);
107     annotationSpaceFillerHolder.add(alabels, BorderLayout.CENTER);
108     scalePanelHolder.add(scalePanel, BorderLayout.CENTER);
109     seqPanelHolder.add(seqPanel, BorderLayout.CENTER);
110
111     fontChanged();
112     setScrollValues(0, 0);
113
114     apvscroll.addAdjustmentListener(this);
115     hscroll.addAdjustmentListener(this);
116     vscroll.addAdjustmentListener(this);
117
118     addComponentListener(new ComponentAdapter()
119     {
120       public void componentResized(ComponentEvent evt)
121       {
122         setScrollValues(av.getStartRes(), av.getStartSeq());
123         if (getSize().height > 0
124                 && annotationPanelHolder.getSize().height > 0)
125         {
126           validateAnnotationDimensions(false);
127         }
128         repaint();
129       }
130
131     });
132
133     Dimension d = calculateIdWidth();
134     idPanel.idCanvas.setSize(d);
135
136     hscrollFillerPanel.setSize(d.width, annotationPanel.getSize().height);
137
138     idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);
139     annotationSpaceFillerHolder.setSize(d.width,
140             annotationPanel.getSize().height);
141     alabels.setSize(d.width, annotationPanel.getSize().height);
142     final AlignmentPanel ap = this;
143     av.addPropertyChangeListener(new java.beans.PropertyChangeListener()
144     {
145       public void propertyChange(java.beans.PropertyChangeEvent evt)
146       {
147         if (evt.getPropertyName().equals("alignment"))
148         {
149           PaintRefresher.Refresh(ap, av.getSequenceSetId(), true, true);
150           alignmentChanged();
151         }
152       }
153     });
154   }
155
156   public SequenceRenderer getSequenceRenderer()
157   {
158     return seqPanel.seqCanvas.sr;
159   }
160   @Override
161   public jalview.api.FeatureRenderer getFeatureRenderer()
162   {
163     return seqPanel.seqCanvas.fr;
164   }
165   @Override
166   public jalview.api.FeatureRenderer cloneFeatureRenderer()
167   {
168     FeatureRenderer nfr = new FeatureRenderer(av);
169     nfr.transferSettings(seqPanel.seqCanvas.fr);
170     return nfr;
171   }
172   public void alignmentChanged()
173   {
174     av.alignmentChanged(this);
175
176     if (overviewPanel != null)
177     {
178       overviewPanel.updateOverviewImage();
179     }
180
181     alignFrame.updateEditMenuBar();
182
183     repaint();
184   }
185
186   public void fontChanged()
187   {
188     // set idCanvas bufferedImage to null
189     // to prevent drawing old image
190     idPanel.idCanvas.image = null;
191     FontMetrics fm = getFontMetrics(av.getFont());
192
193     scalePanel.setSize(new Dimension(10, av.charHeight + fm.getDescent()));
194     idwidthAdjuster.setSize(new Dimension(10, av.charHeight
195             + fm.getDescent()));
196     av.updateSequenceIdColours();
197     annotationPanel.image = null;
198     int ap = annotationPanel.adjustPanelHeight(false);
199     Dimension d = calculateIdWidth();
200     d.setSize(d.width + 4, seqPanel.seqCanvas.getSize().height);
201     alabels.setSize(d.width + 4, ap);
202
203     idPanel.idCanvas.setSize(d);
204     hscrollFillerPanel.setSize(d);
205
206     validateAnnotationDimensions(false);
207     annotationPanel.repaint();
208     validate();
209     repaint();
210
211     if (overviewPanel != null)
212     {
213       overviewPanel.updateOverviewImage();
214     }
215   }
216
217   public void setIdWidth(int w, int h)
218   {
219     idPanel.idCanvas.setSize(w, h);
220     idPanelHolder.setSize(w, idPanelHolder.getSize().height);
221     annotationSpaceFillerHolder.setSize(w,
222             annotationSpaceFillerHolder.getSize().height);
223     alabels.setSize(w, alabels.getSize().height);
224     validate();
225   }
226
227   Dimension calculateIdWidth()
228   {
229     if (av.nullFrame == null)
230     {
231       av.nullFrame = new Frame();
232       av.nullFrame.addNotify();
233     }
234
235     Graphics g = av.nullFrame.getGraphics();
236
237     FontMetrics fm = g.getFontMetrics(av.font);
238     AlignmentI al = av.getAlignment();
239
240     int i = 0;
241     int idWidth = 0;
242     String id;
243     while (i < al.getHeight() && al.getSequenceAt(i) != null)
244     {
245       SequenceI s = al.getSequenceAt(i);
246       id = s.getDisplayId(av.getShowJVSuffix());
247
248       if (fm.stringWidth(id) > idWidth)
249       {
250         idWidth = fm.stringWidth(id);
251       }
252       i++;
253     }
254
255     // Also check annotation label widths
256     i = 0;
257     if (al.getAlignmentAnnotation() != null)
258     {
259       fm = g.getFontMetrics(av.nullFrame.getFont());
260       while (i < al.getAlignmentAnnotation().length)
261       {
262         String label = al.getAlignmentAnnotation()[i].label;
263         if (fm.stringWidth(label) > idWidth)
264         {
265           idWidth = fm.stringWidth(label);
266         }
267         i++;
268       }
269     }
270
271     return new Dimension(idWidth, idPanel.idCanvas.getSize().height);
272   }
273
274   /**
275    * Highlight the given results on the alignment.
276    * 
277    */
278   public void highlightSearchResults(SearchResults results)
279   {
280     scrollToPosition(results);
281     seqPanel.seqCanvas.highlightSearchResults(results);
282   }
283
284   /**
285    * scroll the view to show the position of the highlighted region in results
286    * (if any) and redraw the overview
287    * 
288    * @param results
289    * @return false if results were not found
290    */
291   public boolean scrollToPosition(SearchResults results)
292   {
293     return scrollToPosition(results, true);
294   }
295
296   /**
297    * scroll the view to show the position of the highlighted region in results
298    * (if any)
299    * 
300    * @param results
301    * @param redrawOverview
302    *          - when set, the overview will be recalculated (takes longer)
303    * @return false if results were not found
304    */
305   public boolean scrollToPosition(SearchResults results,
306           boolean redrawOverview)
307   {
308
309     // do we need to scroll the panel?
310     if (results != null && results.getSize() > 0)
311     {
312       AlignmentI alignment = av.getAlignment();
313       int seqIndex = alignment.findIndex(results);
314       if (seqIndex == -1)
315       {
316         return false;
317       }
318       SequenceI seq = alignment.getSequenceAt(seqIndex);
319       int[] r = results.getResults(seq, 0, alignment.getWidth());
320       if (r == null)
321       {
322         if (av.applet.debug)
323         {// DEBUG
324           System.out
325                   .println("DEBUG: scroll didn't happen - results not within alignment : "
326                           + seq.getStart() + "," + seq.getEnd());
327         }
328         return false;
329       }
330       if (av.applet.debug)
331       {
332         // DEBUG
333         /*
334          * System.out.println("DEBUG: scroll: start=" + r[0] +
335          * " av.getStartRes()=" + av.getStartRes() + " end=" + r[1] +
336          * " seq.end=" + seq.getEnd() + " av.getEndRes()=" + av.getEndRes() +
337          * " hextent=" + hextent);
338          */
339       }
340       int start = r[0];
341       int end = r[1];
342       if (start < 0)
343       {
344         return false;
345       }
346       if (end == seq.getEnd())
347       {
348         return false;
349       }
350       return scrollTo(start, end, seqIndex, false, redrawOverview);
351     }
352     return true;
353   }
354
355   public boolean scrollTo(int ostart, int end, int seqIndex,
356           boolean scrollToNearest, boolean redrawOverview)
357   {
358     int startv, endv, starts, ends, width;
359
360     int start = -1;
361     if (av.hasHiddenColumns())
362     {
363       start = av.getColumnSelection().findColumnPosition(ostart);
364       end = av.getColumnSelection().findColumnPosition(end);
365       if (start == end)
366       {
367         if (!scrollToNearest && !av.getColumnSelection().isVisible(ostart))
368         {
369           // don't scroll - position isn't visible
370           return false;
371         }
372       }
373     }
374     else
375     {
376       start = ostart;
377     }
378     if (!av.wrapAlignment)
379     {
380       /*
381        * int spos=av.getStartRes(),sqpos=av.getStartSeq(); if ((startv =
382        * av.getStartRes()) >= start) { spos=start-1; // seqIn //
383        * setScrollValues(start - 1, seqIndex); } else if ((endv =
384        * av.getEndRes()) <= end) { // setScrollValues(spos=startv + 1 + end -
385        * endv, seqIndex); spos=startv + 1 + end - endv; } else if ((starts =
386        * av.getStartSeq()) > seqIndex) { setScrollValues(av.getStartRes(),
387        * seqIndex); } else if ((ends = av.getEndSeq()) <= seqIndex) {
388        * setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1); }
389        * 
390        * /*
391        */
392       if ((av.getStartRes() > end)
393               || (av.getEndRes() < start)
394               || ((av.getStartSeq() > seqIndex) || (av.getEndSeq() < seqIndex)))
395       {
396         if (start > av.getAlignment().getWidth() - hextent)
397         {
398           start = av.getAlignment().getWidth() - hextent;
399           if (start < 0)
400           {
401             start = 0;
402           }
403
404         }
405         if (seqIndex > av.getAlignment().getHeight() - vextent)
406         {
407           seqIndex = av.getAlignment().getHeight() - vextent;
408           if (seqIndex < 0)
409           {
410             seqIndex = 0;
411           }
412         }
413         // System.out.println("trying to scroll to: "+start+" "+seqIndex);
414         setScrollValues(start, seqIndex);
415       }/**/
416     }
417     else
418     {
419       scrollToWrappedVisible(start);
420     }
421     if (redrawOverview && overviewPanel != null)
422     {
423       overviewPanel.setBoxPosition();
424     }
425     paintAlignment(redrawOverview);
426     return true;
427   }
428
429   void scrollToWrappedVisible(int res)
430   {
431     int cwidth = seqPanel.seqCanvas
432             .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
433     if (res <= av.getStartRes() || res >= (av.getStartRes() + cwidth))
434     {
435       vscroll.setValue(res / cwidth);
436       av.startRes = vscroll.getValue() * cwidth;
437     }
438   }
439
440   public OverviewPanel getOverviewPanel()
441   {
442     return overviewPanel;
443   }
444
445   public void setOverviewPanel(OverviewPanel op)
446   {
447     overviewPanel = op;
448   }
449
450   public void setAnnotationVisible(boolean b)
451   {
452     if (!av.wrapAlignment)
453     {
454       annotationSpaceFillerHolder.setVisible(b);
455       annotationPanelHolder.setVisible(b);
456     }
457     else
458     {
459       annotationSpaceFillerHolder.setVisible(false);
460       annotationPanelHolder.setVisible(false);
461     }
462     validate();
463     repaint();
464   }
465
466   /**
467    * automatically adjust annotation panel height for new annotation whilst
468    * ensuring the alignment is still visible.
469    */
470   public void adjustAnnotationHeight()
471   {
472     // TODO: display vertical annotation scrollbar if necessary
473     // this is called after loading new annotation onto alignment
474     if (alignFrame.getSize().height == 0)
475     {
476       System.out.println("NEEDS FIXING");
477     }
478     fontChanged();
479     validateAnnotationDimensions(true);
480     apvscroll.addNotify();
481     hscroll.addNotify();
482     validate();
483     paintAlignment(true);
484   }
485
486   /**
487    * calculate the annotation dimensions and refresh slider values accordingly.
488    * need to do repaints/notifys afterwards.
489    */
490   protected void validateAnnotationDimensions(boolean adjustPanelHeight)
491   {
492     boolean modified = false;
493     int height = av.calcPanelHeight();
494     int minsize = 0;
495     if (hscroll.isVisible())
496     {
497       height += (minsize = hscroll.getPreferredSize().height);
498     }
499     if (apvscroll.isVisible())
500     {
501       minsize += apvscroll.getPreferredSize().height;
502     }
503     int mheight = height;
504     Dimension d = sequenceHolderPanel.getSize(), e = idPanel.getSize();
505     int seqandannot = d.height - scalePanelHolder.getSize().height;
506
507     if (adjustPanelHeight)
508     {
509       // NOTE: this logic is different in the application. Need a better
510       // algorithm to define behaviour
511       // sets initial preferred height
512       // try and set height according to alignment
513       float sscaling = (float) ((av.getCharHeight() * av.getAlignment()
514               .getHeight()) / (1.0 * mheight));
515       if (sscaling > 0.5)
516       {
517         // if the alignment is too big then
518         // default is 0.5 split
519         height = seqandannot / 2;
520       }
521       else
522       {
523         // otherwise just set the panel so that one row of sequence is visible
524         height = -av.getCharHeight() * 1
525                 + (int) (seqandannot * (1 - sscaling));
526       }
527     }
528     else
529     {
530       // maintain same window layout whilst updating sliders
531       height = annotationPanelHolder.getSize().height;
532     }
533
534     if (seqandannot - height < 5)
535     {
536       height = seqandannot;
537     }
538     annotationPanel.setSize(new Dimension(d.width, height));
539     alabels.setSize(new Dimension(e.width, height));
540     annotationSpaceFillerHolder.setSize(new Dimension(e.width, height));
541     annotationPanelHolder.setSize(new Dimension(d.width, height));
542     // seqPanelHolder.setSize(d.width, seqandannot - height);
543     seqPanel.seqCanvas
544             .setSize(d.width, seqPanel.seqCanvas.getSize().height);
545     int s = apvscroll.getValue();
546     if (s > mheight - height)
547     {
548       s = 0;
549     }
550     apvscroll.setValues(s, height, 0, mheight);
551     annotationPanel.setScrollOffset(apvscroll.getValue(), false);
552     alabels.setScrollOffset(apvscroll.getValue(), false);
553   }
554
555   public void setWrapAlignment(boolean wrap)
556   {
557     av.startSeq = 0;
558     av.startRes = 0;
559     scalePanelHolder.setVisible(!wrap);
560
561     hscroll.setVisible(!wrap);
562     idwidthAdjuster.setVisible(!wrap);
563
564     if (wrap)
565     {
566       annotationPanelHolder.setVisible(false);
567       annotationSpaceFillerHolder.setVisible(false);
568     }
569     else if (av.showAnnotation)
570     {
571       annotationPanelHolder.setVisible(true);
572       annotationSpaceFillerHolder.setVisible(true);
573     }
574
575     idSpaceFillerPanel1.setVisible(!wrap);
576
577     fontChanged(); // This is so that the scalePanel is resized correctly
578
579     validate();
580     sequenceHolderPanel.validate();
581     repaint();
582
583   }
584
585   int hextent = 0;
586
587   int vextent = 0;
588
589   // return value is true if the scroll is valid
590   public boolean scrollUp(boolean up)
591   {
592     if (up)
593     {
594       if (vscroll.getValue() < 1)
595       {
596         return false;
597       }
598       setScrollValues(hscroll.getValue(), vscroll.getValue() - 1);
599     }
600     else
601     {
602       if (vextent + vscroll.getValue() >= av.getAlignment().getHeight())
603       {
604         return false;
605       }
606       setScrollValues(hscroll.getValue(), vscroll.getValue() + 1);
607     }
608
609     repaint();
610     return true;
611   }
612
613   public boolean scrollRight(boolean right)
614   {
615     if (!right)
616     {
617       if (hscroll.getValue() < 1)
618       {
619         return false;
620       }
621       setScrollValues(hscroll.getValue() - 1, vscroll.getValue());
622     }
623     else
624     {
625       if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())
626       {
627         return false;
628       }
629       setScrollValues(hscroll.getValue() + 1, vscroll.getValue());
630     }
631
632     repaint();
633     return true;
634   }
635
636   public void setScrollValues(int x, int y)
637   {
638     int width = av.getAlignment().getWidth();
639     int height = av.getAlignment().getHeight();
640
641     if (av.hasHiddenColumns())
642     {
643       width = av.getColumnSelection().findColumnPosition(width);
644     }
645     if (x < 0)
646     {
647       x = 0;
648     }
649     ;
650
651     hextent = seqPanel.seqCanvas.getSize().width / av.charWidth;
652     vextent = seqPanel.seqCanvas.getSize().height / av.charHeight;
653
654     if (hextent > width)
655     {
656       hextent = width;
657     }
658
659     if (vextent > height)
660     {
661       vextent = height;
662     }
663
664     if ((hextent + x) > width)
665     {
666       System.err.println("hextent was " + hextent + " and x was " + x);
667
668       x = width - hextent;
669     }
670
671     if ((vextent + y) > height)
672     {
673       y = height - vextent;
674     }
675
676     if (y < 0)
677     {
678       y = 0;
679     }
680
681     if (x < 0)
682     {
683       System.err.println("x was " + x);
684       x = 0;
685     }
686
687     av.setStartSeq(y);
688
689     int endSeq = y + vextent;
690     if (endSeq > av.getAlignment().getHeight())
691     {
692       endSeq = av.getAlignment().getHeight();
693     }
694
695     av.setEndSeq(endSeq);
696     av.setStartRes(x);
697     av.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av.charWidth)) - 1);
698
699     hscroll.setValues(x, hextent, 0, width);
700     vscroll.setValues(y, vextent, 0, height);
701
702     if (overviewPanel != null)
703     {
704       overviewPanel.setBoxPosition();
705     }
706     sendViewPosition();
707
708   }
709
710   public void adjustmentValueChanged(AdjustmentEvent evt)
711   {
712     int oldX = av.getStartRes();
713     int oldY = av.getStartSeq();
714
715     if (evt == null || evt.getSource() == apvscroll)
716     {
717       annotationPanel.setScrollOffset(apvscroll.getValue(), false);
718       alabels.setScrollOffset(apvscroll.getValue(), false);
719       // annotationPanel.image=null;
720       // alabels.image=null;
721       // alabels.repaint();
722       // annotationPanel.repaint();
723     }
724     if (evt == null || evt.getSource() == hscroll)
725     {
726       int x = hscroll.getValue();
727       av.setStartRes(x);
728       av.setEndRes(x + seqPanel.seqCanvas.getSize().width
729               / av.getCharWidth() - 1);
730     }
731
732     if (evt == null || evt.getSource() == vscroll)
733     {
734       int offy = vscroll.getValue();
735       if (av.getWrapAlignment())
736       {
737         int rowSize = seqPanel.seqCanvas
738                 .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
739         av.setStartRes(vscroll.getValue() * rowSize);
740         av.setEndRes((vscroll.getValue() + 1) * rowSize);
741       }
742       else
743       {
744         av.setStartSeq(offy);
745         av.setEndSeq(offy + seqPanel.seqCanvas.getSize().height
746                 / av.getCharHeight());
747       }
748     }
749
750     if (overviewPanel != null)
751     {
752       overviewPanel.setBoxPosition();
753     }
754
755     int scrollX = av.startRes - oldX;
756     int scrollY = av.startSeq - oldY;
757
758     if (av.getWrapAlignment() || !fastPaint || av.MAC)
759     {
760       repaint();
761     }
762     else
763     {
764       // Make sure we're not trying to draw a panel
765       // larger than the visible window
766       if (scrollX > av.endRes - av.startRes)
767       {
768         scrollX = av.endRes - av.startRes;
769       }
770       else if (scrollX < av.startRes - av.endRes)
771       {
772         scrollX = av.startRes - av.endRes;
773       }
774
775       idPanel.idCanvas.fastPaint(scrollY);
776       seqPanel.seqCanvas.fastPaint(scrollX, scrollY);
777
778       scalePanel.repaint();
779       if (av.getShowAnnotation())
780       {
781         annotationPanel.fastPaint(av.getStartRes() - oldX);
782       }
783     }
784     sendViewPosition();
785
786   }
787
788   private void sendViewPosition()
789   {
790     StructureSelectionManager.getStructureSelectionManager(av.applet)
791             .sendViewPosition(this, av.startRes, av.endRes, av.startSeq,
792                     av.endSeq);
793   }
794
795   public void paintAlignment(boolean updateOverview)
796   {
797     repaint();
798
799     if (updateOverview)
800     {
801       jalview.structure.StructureSelectionManager
802               .getStructureSelectionManager(av.applet)
803               .sequenceColoursChanged(this);
804
805       if (overviewPanel != null)
806       {
807         overviewPanel.updateOverviewImage();
808       }
809     }
810   }
811
812   public void update(Graphics g)
813   {
814     paint(g);
815   }
816
817   public void paint(Graphics g)
818   {
819     invalidate();
820     Dimension d = idPanel.idCanvas.getSize();
821     idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);
822
823     if (av.getWrapAlignment())
824     {
825       int maxwidth = av.getAlignment().getWidth();
826
827       if (av.hasHiddenColumns())
828       {
829         maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
830       }
831
832       int canvasWidth = seqPanel.seqCanvas
833               .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
834
835       if (canvasWidth > 0)
836       {
837         int max = maxwidth / canvasWidth;
838         vscroll.setMaximum(1 + max);
839         vscroll.setUnitIncrement(1);
840         vscroll.setVisibleAmount(1);
841       }
842     }
843     else
844     {
845       setScrollValues(av.getStartRes(), av.getStartSeq());
846     }
847
848     seqPanel.seqCanvas.repaint();
849     idPanel.idCanvas.repaint();
850     if (!av.wrapAlignment)
851     {
852       if (av.showAnnotation)
853       {
854         alabels.repaint();
855         annotationPanel.repaint();
856       }
857       scalePanel.repaint();
858     }
859
860   }
861
862   protected Panel sequenceHolderPanel = new Panel();
863
864   protected Scrollbar vscroll = new Scrollbar();
865
866   protected Scrollbar hscroll = new Scrollbar();
867
868   protected Panel seqPanelHolder = new Panel();
869
870   BorderLayout borderLayout1 = new BorderLayout();
871
872   BorderLayout borderLayout3 = new BorderLayout();
873
874   protected Panel scalePanelHolder = new Panel();
875
876   protected Panel idPanelHolder = new Panel();
877
878   BorderLayout borderLayout5 = new BorderLayout();
879
880   protected Panel idSpaceFillerPanel1 = new Panel();
881
882   public Panel annotationSpaceFillerHolder = new Panel();
883
884   BorderLayout borderLayout6 = new BorderLayout();
885
886   BorderLayout borderLayout7 = new BorderLayout();
887
888   Panel hscrollHolder = new Panel();
889
890   BorderLayout borderLayout10 = new BorderLayout();
891
892   protected Panel hscrollFillerPanel = new Panel();
893
894   BorderLayout borderLayout11 = new BorderLayout();
895
896   BorderLayout borderLayout4 = new BorderLayout();
897
898   BorderLayout borderLayout2 = new BorderLayout();
899
900   Panel annotationPanelHolder = new Panel();
901
902   protected Scrollbar apvscroll = new Scrollbar();
903
904   BorderLayout borderLayout12 = new BorderLayout();
905
906   private void jbInit() throws Exception
907   {
908     // idPanelHolder.setPreferredSize(new Dimension(70, 10));
909     this.setLayout(borderLayout7);
910
911     // sequenceHolderPanel.setPreferredSize(new Dimension(150, 150));
912     sequenceHolderPanel.setLayout(borderLayout3);
913     seqPanelHolder.setLayout(borderLayout1);
914     scalePanelHolder.setBackground(Color.white);
915
916     // scalePanelHolder.setPreferredSize(new Dimension(10, 30));
917     scalePanelHolder.setLayout(borderLayout6);
918     idPanelHolder.setLayout(borderLayout5);
919     idSpaceFillerPanel1.setBackground(Color.white);
920
921     // idSpaceFillerPanel1.setPreferredSize(new Dimension(10, 30));
922     idSpaceFillerPanel1.setLayout(borderLayout11);
923     annotationSpaceFillerHolder.setBackground(Color.white);
924
925     // annotationSpaceFillerHolder.setPreferredSize(new Dimension(10, 80));
926     annotationSpaceFillerHolder.setLayout(borderLayout4);
927     hscroll.setOrientation(Scrollbar.HORIZONTAL);
928     hscrollHolder.setLayout(borderLayout10);
929     hscrollFillerPanel.setBackground(Color.white);
930     apvscroll.setOrientation(Scrollbar.VERTICAL);
931     apvscroll.setVisible(true);
932     apvscroll.addAdjustmentListener(this);
933
934     annotationPanelHolder.setBackground(Color.white);
935     annotationPanelHolder.setLayout(borderLayout12);
936     annotationPanelHolder.add(apvscroll, BorderLayout.EAST);
937     // hscrollFillerPanel.setPreferredSize(new Dimension(70, 10));
938     hscrollHolder.setBackground(Color.white);
939
940     // annotationScroller.setPreferredSize(new Dimension(10, 80));
941     // this.setPreferredSize(new Dimension(220, 166));
942     seqPanelHolder.setBackground(Color.white);
943     idPanelHolder.setBackground(Color.white);
944     sequenceHolderPanel.add(scalePanelHolder, BorderLayout.NORTH);
945     sequenceHolderPanel.add(seqPanelHolder, BorderLayout.CENTER);
946     seqPanelHolder.add(vscroll, BorderLayout.EAST);
947
948     // Panel3.add(secondaryPanelHolder, BorderLayout.SOUTH);
949     this.add(idPanelHolder, BorderLayout.WEST);
950     idPanelHolder.add(idSpaceFillerPanel1, BorderLayout.NORTH);
951     idPanelHolder.add(annotationSpaceFillerHolder, BorderLayout.SOUTH);
952     this.add(hscrollHolder, BorderLayout.SOUTH);
953     hscrollHolder.add(hscroll, BorderLayout.CENTER);
954     hscrollHolder.add(hscrollFillerPanel, BorderLayout.WEST);
955     this.add(sequenceHolderPanel, BorderLayout.CENTER);
956   }
957
958   /**
959    * hides or shows dynamic annotation rows based on groups and av state flags
960    */
961   public void updateAnnotation()
962   {
963     updateAnnotation(false);
964   }
965
966   public void updateAnnotation(boolean applyGlobalSettings)
967   {
968     updateAnnotation(applyGlobalSettings, false);
969   }
970
971   public void updateAnnotation(boolean applyGlobalSettings,
972           boolean preserveNewGroupSettings)
973   {
974     av.updateGroupAnnotationSettings(applyGlobalSettings,
975             preserveNewGroupSettings);
976     adjustAnnotationHeight();
977   }
978
979   @Override
980   public AlignmentI getAlignment()
981   {
982     return av.getAlignment();
983   }
984
985   @Override
986   public String getViewName()
987   {
988     return getName();
989   }
990
991   @Override
992   public StructureSelectionManager getStructureSelectionManager()
993   {
994     return StructureSelectionManager
995             .getStructureSelectionManager(av.applet);
996   }
997
998   @Override
999   public void raiseOOMWarning(String string, OutOfMemoryError error)
1000   {
1001     // TODO: JAL-960
1002     System.err.println("Out of memory whilst '" + string + "'");
1003     error.printStackTrace();
1004   }
1005
1006 }