JAL-1640 updates to use get/setter on viewportI: efficiencies - temp variables create...
[jalview.git] / src / jalview / appletgui / AlignmentPanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
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.isShowAnnotation());
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.getCharHeight()
194             + fm.getDescent()));
195     idwidthAdjuster.setSize(new Dimension(10, av.getCharHeight()
196             + fm.getDescent()));
197     av.updateSequenceIdColours();
198     annotationPanel.image = null;
199     int ap = annotationPanel.adjustPanelHeight(false);
200     Dimension d = calculateIdWidth();
201     d.setSize(d.width + 4, seqPanel.seqCanvas.getSize().height);
202     alabels.setSize(d.width + 4, ap);
203
204     idPanel.idCanvas.setSize(d);
205     hscrollFillerPanel.setSize(d);
206
207     validateAnnotationDimensions(false);
208     annotationPanel.repaint();
209     validate();
210     repaint();
211
212     if (overviewPanel != null)
213     {
214       overviewPanel.updateOverviewImage();
215     }
216   }
217
218   public void setIdWidth(int w, int h)
219   {
220     idPanel.idCanvas.setSize(w, h);
221     idPanelHolder.setSize(w, idPanelHolder.getSize().height);
222     annotationSpaceFillerHolder.setSize(w,
223             annotationSpaceFillerHolder.getSize().height);
224     alabels.setSize(w, alabels.getSize().height);
225     validate();
226   }
227
228   Dimension calculateIdWidth()
229   {
230     if (av.nullFrame == null)
231     {
232       av.nullFrame = new Frame();
233       av.nullFrame.addNotify();
234     }
235
236     Graphics g = av.nullFrame.getGraphics();
237
238     FontMetrics fm = g.getFontMetrics(av.font);
239     AlignmentI al = av.getAlignment();
240
241     int i = 0;
242     int idWidth = 0;
243     String id;
244     while (i < al.getHeight() && al.getSequenceAt(i) != null)
245     {
246       SequenceI s = al.getSequenceAt(i);
247       id = s.getDisplayId(av.getShowJVSuffix());
248
249       if (fm.stringWidth(id) > idWidth)
250       {
251         idWidth = fm.stringWidth(id);
252       }
253       i++;
254     }
255
256     // Also check annotation label widths
257     i = 0;
258     if (al.getAlignmentAnnotation() != null)
259     {
260       fm = g.getFontMetrics(av.nullFrame.getFont());
261       while (i < al.getAlignmentAnnotation().length)
262       {
263         String label = al.getAlignmentAnnotation()[i].label;
264         if (fm.stringWidth(label) > idWidth)
265         {
266           idWidth = fm.stringWidth(label);
267         }
268         i++;
269       }
270     }
271
272     return new Dimension(idWidth, idPanel.idCanvas.getSize().height);
273   }
274
275   /**
276    * Highlight the given results on the alignment.
277    * 
278    */
279   public void highlightSearchResults(SearchResults results)
280   {
281     scrollToPosition(results);
282     seqPanel.seqCanvas.highlightSearchResults(results);
283   }
284
285   /**
286    * scroll the view to show the position of the highlighted region in results
287    * (if any) and redraw the overview
288    * 
289    * @param results
290    * @return false if results were not found
291    */
292   public boolean scrollToPosition(SearchResults results)
293   {
294     return scrollToPosition(results, true);
295   }
296
297   /**
298    * scroll the view to show the position of the highlighted region in results
299    * (if any)
300    * 
301    * @param results
302    * @param redrawOverview
303    *          - when set, the overview will be recalculated (takes longer)
304    * @return false if results were not found
305    */
306   public boolean scrollToPosition(SearchResults results,
307           boolean redrawOverview)
308   {
309
310     // do we need to scroll the panel?
311     if (results != null && results.getSize() > 0)
312     {
313       AlignmentI alignment = av.getAlignment();
314       int seqIndex = alignment.findIndex(results);
315       if (seqIndex == -1)
316       {
317         return false;
318       }
319       SequenceI seq = alignment.getSequenceAt(seqIndex);
320       int[] r = results.getResults(seq, 0, alignment.getWidth());
321       if (r == null)
322       {
323         if (av.applet.debug)
324         {// DEBUG
325           System.out
326                   .println("DEBUG: scroll didn't happen - results not within alignment : "
327                           + seq.getStart() + "," + seq.getEnd());
328         }
329         return false;
330       }
331       if (av.applet.debug)
332       {
333         // DEBUG
334         /*
335          * System.out.println("DEBUG: scroll: start=" + r[0] +
336          * " av.getStartRes()=" + av.getStartRes() + " end=" + r[1] +
337          * " seq.end=" + seq.getEnd() + " av.getEndRes()=" + av.getEndRes() +
338          * " hextent=" + hextent);
339          */
340       }
341       int start = r[0];
342       int end = r[1];
343       if (start < 0)
344       {
345         return false;
346       }
347       if (end == seq.getEnd())
348       {
349         return false;
350       }
351       return scrollTo(start, end, seqIndex, false, redrawOverview);
352     }
353     return true;
354   }
355
356   public boolean scrollTo(int ostart, int end, int seqIndex,
357           boolean scrollToNearest, boolean redrawOverview)
358   {
359     int startv, endv, starts, ends, width;
360
361     int start = -1;
362     if (av.hasHiddenColumns())
363     {
364       start = av.getColumnSelection().findColumnPosition(ostart);
365       end = av.getColumnSelection().findColumnPosition(end);
366       if (start == end)
367       {
368         if (!scrollToNearest && !av.getColumnSelection().isVisible(ostart))
369         {
370           // don't scroll - position isn't visible
371           return false;
372         }
373       }
374     }
375     else
376     {
377       start = ostart;
378     }
379     if (!av.getWrapAlignment())
380     {
381       /*
382        * int spos=av.getStartRes(),sqpos=av.getStartSeq(); if ((startv =
383        * av.getStartRes()) >= start) { spos=start-1; // seqIn //
384        * setScrollValues(start - 1, seqIndex); } else if ((endv =
385        * av.getEndRes()) <= end) { // setScrollValues(spos=startv + 1 + end -
386        * endv, seqIndex); spos=startv + 1 + end - endv; } else if ((starts =
387        * av.getStartSeq()) > seqIndex) { setScrollValues(av.getStartRes(),
388        * seqIndex); } else if ((ends = av.getEndSeq()) <= seqIndex) {
389        * setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1); }
390        * 
391        * /*
392        */
393       if ((av.getStartRes() > end)
394               || (av.getEndRes() < start)
395               || ((av.getStartSeq() > seqIndex) || (av.getEndSeq() < seqIndex)))
396       {
397         if (start > av.getAlignment().getWidth() - hextent)
398         {
399           start = av.getAlignment().getWidth() - hextent;
400           if (start < 0)
401           {
402             start = 0;
403           }
404
405         }
406         if (seqIndex > av.getAlignment().getHeight() - vextent)
407         {
408           seqIndex = av.getAlignment().getHeight() - vextent;
409           if (seqIndex < 0)
410           {
411             seqIndex = 0;
412           }
413         }
414         // System.out.println("trying to scroll to: "+start+" "+seqIndex);
415         setScrollValues(start, seqIndex);
416       }/**/
417     }
418     else
419     {
420       scrollToWrappedVisible(start);
421     }
422     if (redrawOverview && overviewPanel != null)
423     {
424       overviewPanel.setBoxPosition();
425     }
426     paintAlignment(redrawOverview);
427     return true;
428   }
429
430   void scrollToWrappedVisible(int res)
431   {
432     int cwidth = seqPanel.seqCanvas
433             .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
434     if (res <= av.getStartRes() || res >= (av.getStartRes() + cwidth))
435     {
436       vscroll.setValue(res / cwidth);
437       av.startRes = vscroll.getValue() * cwidth;
438     }
439   }
440
441   public OverviewPanel getOverviewPanel()
442   {
443     return overviewPanel;
444   }
445
446   public void setOverviewPanel(OverviewPanel op)
447   {
448     overviewPanel = op;
449   }
450
451   public void setAnnotationVisible(boolean b)
452   {
453     if (!av.getWrapAlignment())
454     {
455       annotationSpaceFillerHolder.setVisible(b);
456       annotationPanelHolder.setVisible(b);
457     }
458     else
459     {
460       annotationSpaceFillerHolder.setVisible(false);
461       annotationPanelHolder.setVisible(false);
462     }
463     validate();
464     repaint();
465   }
466
467   /**
468    * automatically adjust annotation panel height for new annotation whilst
469    * ensuring the alignment is still visible.
470    */
471   public void adjustAnnotationHeight()
472   {
473     // TODO: display vertical annotation scrollbar if necessary
474     // this is called after loading new annotation onto alignment
475     if (alignFrame.getSize().height == 0)
476     {
477       System.out.println("NEEDS FIXING");
478     }
479     fontChanged();
480     validateAnnotationDimensions(true);
481     apvscroll.addNotify();
482     hscroll.addNotify();
483     validate();
484     paintAlignment(true);
485   }
486
487   /**
488    * calculate the annotation dimensions and refresh slider values accordingly.
489    * need to do repaints/notifys afterwards.
490    */
491   protected void validateAnnotationDimensions(boolean adjustPanelHeight)
492   {
493     boolean modified = false;
494     int height = av.calcPanelHeight();
495     int minsize = 0;
496     if (hscroll.isVisible())
497     {
498       height += (minsize = hscroll.getPreferredSize().height);
499     }
500     if (apvscroll.isVisible())
501     {
502       minsize += apvscroll.getPreferredSize().height;
503     }
504     int mheight = height;
505     Dimension d = sequenceHolderPanel.getSize(), e = idPanel.getSize();
506     int seqandannot = d.height - scalePanelHolder.getSize().height;
507
508     if (adjustPanelHeight)
509     {
510       // NOTE: this logic is different in the application. Need a better
511       // algorithm to define behaviour
512       // sets initial preferred height
513       // try and set height according to alignment
514       float sscaling = (float) ((av.getCharHeight() * av.getAlignment()
515               .getHeight()) / (1.0 * mheight));
516       if (sscaling > 0.5)
517       {
518         // if the alignment is too big then
519         // default is 0.5 split
520         height = seqandannot / 2;
521       }
522       else
523       {
524         // otherwise just set the panel so that one row of sequence is visible
525         height = -av.getCharHeight() * 1
526                 + (int) (seqandannot * (1 - sscaling));
527       }
528     }
529     else
530     {
531       // maintain same window layout whilst updating sliders
532       height = annotationPanelHolder.getSize().height;
533     }
534
535     if (seqandannot - height < 5)
536     {
537       height = seqandannot;
538     }
539     annotationPanel.setSize(new Dimension(d.width, height));
540     alabels.setSize(new Dimension(e.width, height));
541     annotationSpaceFillerHolder.setSize(new Dimension(e.width, height));
542     annotationPanelHolder.setSize(new Dimension(d.width, height));
543     // seqPanelHolder.setSize(d.width, seqandannot - height);
544     seqPanel.seqCanvas
545             .setSize(d.width, seqPanel.seqCanvas.getSize().height);
546     int s = apvscroll.getValue();
547     if (s > mheight - height)
548     {
549       s = 0;
550     }
551     apvscroll.setValues(s, height, 0, mheight);
552     annotationPanel.setScrollOffset(apvscroll.getValue(), false);
553     alabels.setScrollOffset(apvscroll.getValue(), false);
554   }
555
556   public void setWrapAlignment(boolean wrap)
557   {
558     av.startSeq = 0;
559     av.startRes = 0;
560     scalePanelHolder.setVisible(!wrap);
561
562     hscroll.setVisible(!wrap);
563     idwidthAdjuster.setVisible(!wrap);
564
565     if (wrap)
566     {
567       annotationPanelHolder.setVisible(false);
568       annotationSpaceFillerHolder.setVisible(false);
569     }
570     else if (av.isShowAnnotation())
571     {
572       annotationPanelHolder.setVisible(true);
573       annotationSpaceFillerHolder.setVisible(true);
574     }
575
576     idSpaceFillerPanel1.setVisible(!wrap);
577
578     fontChanged(); // This is so that the scalePanel is resized correctly
579
580     validate();
581     sequenceHolderPanel.validate();
582     repaint();
583
584   }
585
586   int hextent = 0;
587
588   int vextent = 0;
589
590   // return value is true if the scroll is valid
591   public boolean scrollUp(boolean up)
592   {
593     if (up)
594     {
595       if (vscroll.getValue() < 1)
596       {
597         return false;
598       }
599       setScrollValues(hscroll.getValue(), vscroll.getValue() - 1);
600     }
601     else
602     {
603       if (vextent + vscroll.getValue() >= av.getAlignment().getHeight())
604       {
605         return false;
606       }
607       setScrollValues(hscroll.getValue(), vscroll.getValue() + 1);
608     }
609
610     repaint();
611     return true;
612   }
613
614   public boolean scrollRight(boolean right)
615   {
616     if (!right)
617     {
618       if (hscroll.getValue() < 1)
619       {
620         return false;
621       }
622       setScrollValues(hscroll.getValue() - 1, vscroll.getValue());
623     }
624     else
625     {
626       if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())
627       {
628         return false;
629       }
630       setScrollValues(hscroll.getValue() + 1, vscroll.getValue());
631     }
632
633     repaint();
634     return true;
635   }
636
637   public void setScrollValues(int x, int y)
638   {
639     int width = av.getAlignment().getWidth();
640     int height = av.getAlignment().getHeight();
641
642     if (av.hasHiddenColumns())
643     {
644       width = av.getColumnSelection().findColumnPosition(width);
645     }
646     if (x < 0)
647     {
648       x = 0;
649     }
650     ;
651
652     hextent = seqPanel.seqCanvas.getSize().width / av.getCharWidth();
653     vextent = seqPanel.seqCanvas.getSize().height / av.getCharHeight();
654
655     if (hextent > width)
656     {
657       hextent = width;
658     }
659
660     if (vextent > height)
661     {
662       vextent = height;
663     }
664
665     if ((hextent + x) > width)
666     {
667       System.err.println("hextent was " + hextent + " and x was " + x);
668
669       x = width - hextent;
670     }
671
672     if ((vextent + y) > height)
673     {
674       y = height - vextent;
675     }
676
677     if (y < 0)
678     {
679       y = 0;
680     }
681
682     if (x < 0)
683     {
684       System.err.println("x was " + x);
685       x = 0;
686     }
687
688     av.setStartSeq(y);
689
690     int endSeq = y + vextent;
691     if (endSeq > av.getAlignment().getHeight())
692     {
693       endSeq = av.getAlignment().getHeight();
694     }
695
696     av.setEndSeq(endSeq);
697     av.setStartRes(x);
698     av.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av
699             .getCharWidth())) - 1);
700
701     hscroll.setValues(x, hextent, 0, width);
702     vscroll.setValues(y, vextent, 0, height);
703
704     if (overviewPanel != null)
705     {
706       overviewPanel.setBoxPosition();
707     }
708     sendViewPosition();
709
710   }
711
712   public void adjustmentValueChanged(AdjustmentEvent evt)
713   {
714     int oldX = av.getStartRes();
715     int oldY = av.getStartSeq();
716
717     if (evt == null || evt.getSource() == apvscroll)
718     {
719       annotationPanel.setScrollOffset(apvscroll.getValue(), false);
720       alabels.setScrollOffset(apvscroll.getValue(), false);
721       // annotationPanel.image=null;
722       // alabels.image=null;
723       // alabels.repaint();
724       // annotationPanel.repaint();
725     }
726     if (evt == null || evt.getSource() == hscroll)
727     {
728       int x = hscroll.getValue();
729       av.setStartRes(x);
730       av.setEndRes(x + seqPanel.seqCanvas.getSize().width
731               / av.getCharWidth() - 1);
732     }
733
734     if (evt == null || evt.getSource() == vscroll)
735     {
736       int offy = vscroll.getValue();
737       if (av.getWrapAlignment())
738       {
739         int rowSize = seqPanel.seqCanvas
740                 .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
741         av.setStartRes(vscroll.getValue() * rowSize);
742         av.setEndRes((vscroll.getValue() + 1) * rowSize);
743       }
744       else
745       {
746         av.setStartSeq(offy);
747         av.setEndSeq(offy + seqPanel.seqCanvas.getSize().height
748                 / av.getCharHeight());
749       }
750     }
751
752     if (overviewPanel != null)
753     {
754       overviewPanel.setBoxPosition();
755     }
756
757     int scrollX = av.startRes - oldX;
758     int scrollY = av.startSeq - oldY;
759
760     if (av.getWrapAlignment() || !fastPaint || av.MAC)
761     {
762       repaint();
763     }
764     else
765     {
766       // Make sure we're not trying to draw a panel
767       // larger than the visible window
768       if (scrollX > av.endRes - av.startRes)
769       {
770         scrollX = av.endRes - av.startRes;
771       }
772       else if (scrollX < av.startRes - av.endRes)
773       {
774         scrollX = av.startRes - av.endRes;
775       }
776
777       idPanel.idCanvas.fastPaint(scrollY);
778       seqPanel.seqCanvas.fastPaint(scrollX, scrollY);
779
780       scalePanel.repaint();
781       if (av.isShowAnnotation())
782       {
783         annotationPanel.fastPaint(av.getStartRes() - oldX);
784       }
785     }
786     sendViewPosition();
787
788   }
789
790   private void sendViewPosition()
791   {
792     StructureSelectionManager.getStructureSelectionManager(av.applet)
793             .sendViewPosition(this, av.startRes, av.endRes, av.startSeq,
794                     av.endSeq);
795   }
796
797   public void paintAlignment(boolean updateOverview)
798   {
799     repaint();
800
801     if (updateOverview)
802     {
803       jalview.structure.StructureSelectionManager
804               .getStructureSelectionManager(av.applet)
805               .sequenceColoursChanged(this);
806
807       if (overviewPanel != null)
808       {
809         overviewPanel.updateOverviewImage();
810       }
811     }
812   }
813
814   public void update(Graphics g)
815   {
816     paint(g);
817   }
818
819   public void paint(Graphics g)
820   {
821     invalidate();
822     Dimension d = idPanel.idCanvas.getSize();
823     idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);
824
825     if (av.getWrapAlignment())
826     {
827       int maxwidth = av.getAlignment().getWidth();
828
829       if (av.hasHiddenColumns())
830       {
831         maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
832       }
833
834       int canvasWidth = seqPanel.seqCanvas
835               .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
836
837       if (canvasWidth > 0)
838       {
839         int max = maxwidth / canvasWidth;
840         vscroll.setMaximum(1 + max);
841         vscroll.setUnitIncrement(1);
842         vscroll.setVisibleAmount(1);
843       }
844     }
845     else
846     {
847       setScrollValues(av.getStartRes(), av.getStartSeq());
848     }
849
850     seqPanel.seqCanvas.repaint();
851     idPanel.idCanvas.repaint();
852     if (!av.getWrapAlignment())
853     {
854       if (av.isShowAnnotation())
855       {
856         alabels.repaint();
857         annotationPanel.repaint();
858       }
859       scalePanel.repaint();
860     }
861
862   }
863
864   protected Panel sequenceHolderPanel = new Panel();
865
866   protected Scrollbar vscroll = new Scrollbar();
867
868   protected Scrollbar hscroll = new Scrollbar();
869
870   protected Panel seqPanelHolder = new Panel();
871
872   BorderLayout borderLayout1 = new BorderLayout();
873
874   BorderLayout borderLayout3 = new BorderLayout();
875
876   protected Panel scalePanelHolder = new Panel();
877
878   protected Panel idPanelHolder = new Panel();
879
880   BorderLayout borderLayout5 = new BorderLayout();
881
882   protected Panel idSpaceFillerPanel1 = new Panel();
883
884   public Panel annotationSpaceFillerHolder = new Panel();
885
886   BorderLayout borderLayout6 = new BorderLayout();
887
888   BorderLayout borderLayout7 = new BorderLayout();
889
890   Panel hscrollHolder = new Panel();
891
892   BorderLayout borderLayout10 = new BorderLayout();
893
894   protected Panel hscrollFillerPanel = new Panel();
895
896   BorderLayout borderLayout11 = new BorderLayout();
897
898   BorderLayout borderLayout4 = new BorderLayout();
899
900   BorderLayout borderLayout2 = new BorderLayout();
901
902   Panel annotationPanelHolder = new Panel();
903
904   protected Scrollbar apvscroll = new Scrollbar();
905
906   BorderLayout borderLayout12 = new BorderLayout();
907
908   private void jbInit() throws Exception
909   {
910     // idPanelHolder.setPreferredSize(new Dimension(70, 10));
911     this.setLayout(borderLayout7);
912
913     // sequenceHolderPanel.setPreferredSize(new Dimension(150, 150));
914     sequenceHolderPanel.setLayout(borderLayout3);
915     seqPanelHolder.setLayout(borderLayout1);
916     scalePanelHolder.setBackground(Color.white);
917
918     // scalePanelHolder.setPreferredSize(new Dimension(10, 30));
919     scalePanelHolder.setLayout(borderLayout6);
920     idPanelHolder.setLayout(borderLayout5);
921     idSpaceFillerPanel1.setBackground(Color.white);
922
923     // idSpaceFillerPanel1.setPreferredSize(new Dimension(10, 30));
924     idSpaceFillerPanel1.setLayout(borderLayout11);
925     annotationSpaceFillerHolder.setBackground(Color.white);
926
927     // annotationSpaceFillerHolder.setPreferredSize(new Dimension(10, 80));
928     annotationSpaceFillerHolder.setLayout(borderLayout4);
929     hscroll.setOrientation(Scrollbar.HORIZONTAL);
930     hscrollHolder.setLayout(borderLayout10);
931     hscrollFillerPanel.setBackground(Color.white);
932     apvscroll.setOrientation(Scrollbar.VERTICAL);
933     apvscroll.setVisible(true);
934     apvscroll.addAdjustmentListener(this);
935
936     annotationPanelHolder.setBackground(Color.white);
937     annotationPanelHolder.setLayout(borderLayout12);
938     annotationPanelHolder.add(apvscroll, BorderLayout.EAST);
939     // hscrollFillerPanel.setPreferredSize(new Dimension(70, 10));
940     hscrollHolder.setBackground(Color.white);
941
942     // annotationScroller.setPreferredSize(new Dimension(10, 80));
943     // this.setPreferredSize(new Dimension(220, 166));
944     seqPanelHolder.setBackground(Color.white);
945     idPanelHolder.setBackground(Color.white);
946     sequenceHolderPanel.add(scalePanelHolder, BorderLayout.NORTH);
947     sequenceHolderPanel.add(seqPanelHolder, BorderLayout.CENTER);
948     seqPanelHolder.add(vscroll, BorderLayout.EAST);
949
950     // Panel3.add(secondaryPanelHolder, BorderLayout.SOUTH);
951     this.add(idPanelHolder, BorderLayout.WEST);
952     idPanelHolder.add(idSpaceFillerPanel1, BorderLayout.NORTH);
953     idPanelHolder.add(annotationSpaceFillerHolder, BorderLayout.SOUTH);
954     this.add(hscrollHolder, BorderLayout.SOUTH);
955     hscrollHolder.add(hscroll, BorderLayout.CENTER);
956     hscrollHolder.add(hscrollFillerPanel, BorderLayout.WEST);
957     this.add(sequenceHolderPanel, BorderLayout.CENTER);
958   }
959
960   /**
961    * hides or shows dynamic annotation rows based on groups and av state flags
962    */
963   public void updateAnnotation()
964   {
965     updateAnnotation(false);
966   }
967
968   public void updateAnnotation(boolean applyGlobalSettings)
969   {
970     updateAnnotation(applyGlobalSettings, false);
971   }
972
973   public void updateAnnotation(boolean applyGlobalSettings,
974           boolean preserveNewGroupSettings)
975   {
976     av.updateGroupAnnotationSettings(applyGlobalSettings,
977             preserveNewGroupSettings);
978     adjustAnnotationHeight();
979   }
980
981   @Override
982   public AlignmentI getAlignment()
983   {
984     return av.getAlignment();
985   }
986
987   @Override
988   public String getViewName()
989   {
990     return getName();
991   }
992
993   @Override
994   public StructureSelectionManager getStructureSelectionManager()
995   {
996     return StructureSelectionManager
997             .getStructureSelectionManager(av.applet);
998   }
999
1000   @Override
1001   public void raiseOOMWarning(String string, OutOfMemoryError error)
1002   {
1003     // TODO: JAL-960
1004     System.err.println("Out of memory whilst '" + string + "'");
1005     error.printStackTrace();
1006   }
1007
1008 }