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