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