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