JAL-1517 update copyright to version 2.8.2
[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 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     } else {
437       annotationSpaceFillerHolder.setVisible(false);
438       annotationPanelHolder.setVisible(false);
439     }
440     validate();
441     repaint();
442   }
443
444   /**
445    * automatically adjust annotation panel height for new annotation whilst
446    * ensuring the alignment is still visible.
447    */
448   public void adjustAnnotationHeight()
449   {
450     // TODO: display vertical annotation scrollbar if necessary
451     // this is called after loading new annotation onto alignment
452     if (alignFrame.getSize().height == 0)
453     {
454       System.out.println("NEEDS FIXING");
455     }
456     fontChanged();
457     validateAnnotationDimensions(true);
458     apvscroll.addNotify();
459     hscroll.addNotify();
460     validate();
461     paintAlignment(true);
462   }
463
464   /**
465    * calculate the annotation dimensions and refresh slider values accordingly.
466    * need to do repaints/notifys afterwards.
467    */
468   protected void validateAnnotationDimensions(boolean adjustPanelHeight)
469   {
470     boolean modified = false;
471     int height = av.calcPanelHeight();
472     int minsize = 0;
473     if (hscroll.isVisible())
474     {
475       height += (minsize = hscroll.getPreferredSize().height);
476     }
477     if (apvscroll.isVisible())
478     {
479       minsize += apvscroll.getPreferredSize().height;
480     }
481     int mheight = height;
482     Dimension d = sequenceHolderPanel.getSize(), e = idPanel.getSize();
483     int seqandannot = d.height - scalePanelHolder.getSize().height;
484
485     if (adjustPanelHeight)
486     {
487       // NOTE: this logic is different in the application. Need a better algorithm to define behaviour
488       // sets initial preferred height
489       // try and set height according to alignment
490       float sscaling = (float) ((av.getCharHeight() * av.getAlignment().getHeight())/(1.0*mheight));
491       if (sscaling > 0.5)
492       {
493         // if the alignment is too big then
494         // default is 0.5 split
495         height = seqandannot / 2;
496       }
497       else
498       {
499         // otherwise just set the panel so that one row of sequence is visible 
500         height = -av.getCharHeight() * 1
501                 + (int) (seqandannot * (1 - sscaling));
502       }
503     }
504     else
505     {
506       // maintain same window layout whilst updating sliders
507       height = annotationPanelHolder.getSize().height;
508     }
509
510     if (seqandannot - height < 5)
511     {
512       height = seqandannot;
513     }
514     annotationPanel.setSize(new Dimension(d.width, height));
515     alabels.setSize(new Dimension(e.width, height));
516     annotationSpaceFillerHolder.setSize(new Dimension(e.width, height));
517     annotationPanelHolder.setSize(new Dimension(d.width, height));
518     // seqPanelHolder.setSize(d.width, seqandannot - height);
519     seqPanel.seqCanvas
520             .setSize(d.width, seqPanel.seqCanvas.getSize().height);
521     int s = apvscroll.getValue();
522     if (s > mheight - height)
523     {
524       s = 0;
525     }
526     apvscroll.setValues(s, height, 0, mheight);
527     annotationPanel.setScrollOffset(apvscroll.getValue(), false);
528     alabels.setScrollOffset(apvscroll.getValue(), false);
529   }
530
531   public void setWrapAlignment(boolean wrap)
532   {
533     av.startSeq = 0;
534     av.startRes = 0;
535     scalePanelHolder.setVisible(!wrap);
536
537     hscroll.setVisible(!wrap);
538     idwidthAdjuster.setVisible(!wrap);
539
540     if (wrap)
541     {
542       annotationPanelHolder.setVisible(false);
543       annotationSpaceFillerHolder.setVisible(false);
544     }
545     else if (av.showAnnotation)
546     {
547       annotationPanelHolder.setVisible(true);
548       annotationSpaceFillerHolder.setVisible(true);
549     }
550     
551     idSpaceFillerPanel1.setVisible(!wrap);
552
553     fontChanged(); // This is so that the scalePanel is resized correctly
554
555     validate();
556     sequenceHolderPanel.revalidate();
557     repaint();
558
559   }
560
561   int hextent = 0;
562
563   int vextent = 0;
564
565   // return value is true if the scroll is valid
566   public boolean scrollUp(boolean up)
567   {
568     if (up)
569     {
570       if (vscroll.getValue() < 1)
571       {
572         return false;
573       }
574       setScrollValues(hscroll.getValue(), vscroll.getValue() - 1);
575     }
576     else
577     {
578       if (vextent + vscroll.getValue() >= av.getAlignment().getHeight())
579       {
580         return false;
581       }
582       setScrollValues(hscroll.getValue(), vscroll.getValue() + 1);
583     }
584
585     repaint();
586     return true;
587   }
588
589   public boolean scrollRight(boolean right)
590   {
591     if (!right)
592     {
593       if (hscroll.getValue() < 1)
594       {
595         return false;
596       }
597       setScrollValues(hscroll.getValue() - 1, vscroll.getValue());
598     }
599     else
600     {
601       if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())
602       {
603         return false;
604       }
605       setScrollValues(hscroll.getValue() + 1, vscroll.getValue());
606     }
607
608     repaint();
609     return true;
610   }
611
612   public void setScrollValues(int x, int y)
613   {
614     int width = av.getAlignment().getWidth();
615     int height = av.getAlignment().getHeight();
616
617     if (av.hasHiddenColumns())
618     {
619       width = av.getColumnSelection().findColumnPosition(width);
620     }
621     if (x < 0)
622     {
623       x = 0;
624     }
625     ;
626
627     hextent = seqPanel.seqCanvas.getSize().width / av.charWidth;
628     vextent = seqPanel.seqCanvas.getSize().height / av.charHeight;
629
630     if (hextent > width)
631     {
632       hextent = width;
633     }
634
635     if (vextent > height)
636     {
637       vextent = height;
638     }
639
640     if ((hextent + x) > width)
641     {
642       System.err.println("hextent was " + hextent + " and x was " + x);
643
644       x = width - hextent;
645     }
646
647     if ((vextent + y) > height)
648     {
649       y = height - vextent;
650     }
651
652     if (y < 0)
653     {
654       y = 0;
655     }
656
657     if (x < 0)
658     {
659       System.err.println("x was " + x);
660       x = 0;
661     }
662
663     av.setStartSeq(y);
664
665     int endSeq = y + vextent;
666     if (endSeq > av.getAlignment().getHeight())
667     {
668       endSeq = av.getAlignment().getHeight();
669     }
670
671     av.setEndSeq(endSeq);
672     av.setStartRes(x);
673     av.setEndRes((x + (seqPanel.seqCanvas.getSize().width / av.charWidth)) - 1);
674
675     hscroll.setValues(x, hextent, 0, width);
676     vscroll.setValues(y, vextent, 0, height);
677
678     if (overviewPanel != null)
679     {
680       overviewPanel.setBoxPosition();
681     }
682     sendViewPosition();
683
684   }
685
686   public void adjustmentValueChanged(AdjustmentEvent evt)
687   {
688     int oldX = av.getStartRes();
689     int oldY = av.getStartSeq();
690
691     if (evt == null || evt.getSource() == apvscroll)
692     {
693       annotationPanel.setScrollOffset(apvscroll.getValue(), false);
694       alabels.setScrollOffset(apvscroll.getValue(), false);
695       // annotationPanel.image=null;
696       // alabels.image=null;
697       // alabels.repaint();
698       // annotationPanel.repaint();
699     }
700     if (evt == null || evt.getSource() == hscroll)
701     {
702       int x = hscroll.getValue();
703       av.setStartRes(x);
704       av.setEndRes(x + seqPanel.seqCanvas.getSize().width
705               / av.getCharWidth() - 1);
706     }
707
708     if (evt == null || evt.getSource() == vscroll)
709     {
710       int offy = vscroll.getValue();
711       if (av.getWrapAlignment())
712       {
713         int rowSize = seqPanel.seqCanvas
714                 .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
715         av.setStartRes(vscroll.getValue() * rowSize);
716         av.setEndRes((vscroll.getValue() + 1) * rowSize);
717       }
718       else
719       {
720         av.setStartSeq(offy);
721         av.setEndSeq(offy + seqPanel.seqCanvas.getSize().height
722                 / av.getCharHeight());
723       }
724     }
725
726     if (overviewPanel != null)
727     {
728       overviewPanel.setBoxPosition();
729     }
730
731     int scrollX = av.startRes - oldX;
732     int scrollY = av.startSeq - oldY;
733
734     if (av.getWrapAlignment() || !fastPaint || av.MAC)
735     {
736       repaint();
737     }
738     else
739     {
740       // Make sure we're not trying to draw a panel
741       // larger than the visible window
742       if (scrollX > av.endRes - av.startRes)
743       {
744         scrollX = av.endRes - av.startRes;
745       }
746       else if (scrollX < av.startRes - av.endRes)
747       {
748         scrollX = av.startRes - av.endRes;
749       }
750
751       idPanel.idCanvas.fastPaint(scrollY);
752       seqPanel.seqCanvas.fastPaint(scrollX, scrollY);
753
754       scalePanel.repaint();
755       if (av.getShowAnnotation())
756       {
757         annotationPanel.fastPaint(av.getStartRes() - oldX);
758       }
759     }
760     sendViewPosition();
761
762   }
763
764   private void sendViewPosition()
765   {
766     StructureSelectionManager.getStructureSelectionManager(av.applet)
767             .sendViewPosition(this, av.startRes, av.endRes, av.startSeq,
768                     av.endSeq);
769   }
770
771   public void paintAlignment(boolean updateOverview)
772   {
773     repaint();
774
775     if (updateOverview)
776     {
777       jalview.structure.StructureSelectionManager
778               .getStructureSelectionManager(av.applet)
779               .sequenceColoursChanged(this);
780
781       if (overviewPanel != null)
782       {
783         overviewPanel.updateOverviewImage();
784       }
785     }
786   }
787
788   public void update(Graphics g)
789   {
790     paint(g);
791   }
792
793   public void paint(Graphics g)
794   {
795     invalidate();
796     Dimension d = idPanel.idCanvas.getSize();
797     idPanel.idCanvas.setSize(d.width, seqPanel.seqCanvas.getSize().height);
798
799     if (av.getWrapAlignment())
800     {
801       int maxwidth = av.getAlignment().getWidth();
802
803       if (av.hasHiddenColumns())
804       {
805         maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
806       }
807
808       int canvasWidth = seqPanel.seqCanvas
809               .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width);
810
811       if (canvasWidth > 0)
812       {
813         int max = maxwidth / canvasWidth;
814         vscroll.setMaximum(1 + max);
815         vscroll.setUnitIncrement(1);
816         vscroll.setVisibleAmount(1);
817       }
818     }
819     else
820     {
821       setScrollValues(av.getStartRes(), av.getStartSeq());
822     }
823
824     seqPanel.seqCanvas.repaint();
825     idPanel.idCanvas.repaint();
826     if (!av.wrapAlignment) 
827     {
828       if (av.showAnnotation)
829       {
830         alabels.repaint();
831         annotationPanel.repaint();
832       }
833       scalePanel.repaint();
834     }
835     
836   }
837
838   protected Panel sequenceHolderPanel = new Panel();
839
840   protected Scrollbar vscroll = new Scrollbar();
841
842   protected Scrollbar hscroll = new Scrollbar();
843
844   protected Panel seqPanelHolder = new Panel();
845
846   BorderLayout borderLayout1 = new BorderLayout();
847
848   BorderLayout borderLayout3 = new BorderLayout();
849
850   protected Panel scalePanelHolder = new Panel();
851
852   protected Panel idPanelHolder = new Panel();
853
854   BorderLayout borderLayout5 = new BorderLayout();
855
856   protected Panel idSpaceFillerPanel1 = new Panel();
857
858   public Panel annotationSpaceFillerHolder = new Panel();
859
860   BorderLayout borderLayout6 = new BorderLayout();
861
862   BorderLayout borderLayout7 = new BorderLayout();
863
864   Panel hscrollHolder = new Panel();
865
866   BorderLayout borderLayout10 = new BorderLayout();
867
868   protected Panel hscrollFillerPanel = new Panel();
869
870   BorderLayout borderLayout11 = new BorderLayout();
871
872   BorderLayout borderLayout4 = new BorderLayout();
873
874   BorderLayout borderLayout2 = new BorderLayout();
875
876   Panel annotationPanelHolder = new Panel();
877
878   protected Scrollbar apvscroll = new Scrollbar();
879
880   BorderLayout borderLayout12 = new BorderLayout();
881
882   private void jbInit() throws Exception
883   {
884     // idPanelHolder.setPreferredSize(new Dimension(70, 10));
885     this.setLayout(borderLayout7);
886
887     // sequenceHolderPanel.setPreferredSize(new Dimension(150, 150));
888     sequenceHolderPanel.setLayout(borderLayout3);
889     seqPanelHolder.setLayout(borderLayout1);
890     scalePanelHolder.setBackground(Color.white);
891
892     // scalePanelHolder.setPreferredSize(new Dimension(10, 30));
893     scalePanelHolder.setLayout(borderLayout6);
894     idPanelHolder.setLayout(borderLayout5);
895     idSpaceFillerPanel1.setBackground(Color.white);
896
897     // idSpaceFillerPanel1.setPreferredSize(new Dimension(10, 30));
898     idSpaceFillerPanel1.setLayout(borderLayout11);
899     annotationSpaceFillerHolder.setBackground(Color.white);
900
901     // annotationSpaceFillerHolder.setPreferredSize(new Dimension(10, 80));
902     annotationSpaceFillerHolder.setLayout(borderLayout4);
903     hscroll.setOrientation(Scrollbar.HORIZONTAL);
904     hscrollHolder.setLayout(borderLayout10);
905     hscrollFillerPanel.setBackground(Color.white);
906     apvscroll.setOrientation(Scrollbar.VERTICAL);
907     apvscroll.setVisible(true);
908     apvscroll.addAdjustmentListener(this);
909
910     annotationPanelHolder.setBackground(Color.white);
911     annotationPanelHolder.setLayout(borderLayout12);
912     annotationPanelHolder.add(apvscroll, BorderLayout.EAST);
913     // hscrollFillerPanel.setPreferredSize(new Dimension(70, 10));
914     hscrollHolder.setBackground(Color.white);
915
916     // annotationScroller.setPreferredSize(new Dimension(10, 80));
917     // this.setPreferredSize(new Dimension(220, 166));
918     seqPanelHolder.setBackground(Color.white);
919     idPanelHolder.setBackground(Color.white);
920     sequenceHolderPanel.add(scalePanelHolder, BorderLayout.NORTH);
921     sequenceHolderPanel.add(seqPanelHolder, BorderLayout.CENTER);
922     seqPanelHolder.add(vscroll, BorderLayout.EAST);
923
924     // Panel3.add(secondaryPanelHolder, BorderLayout.SOUTH);
925     this.add(idPanelHolder, BorderLayout.WEST);
926     idPanelHolder.add(idSpaceFillerPanel1, BorderLayout.NORTH);
927     idPanelHolder.add(annotationSpaceFillerHolder, BorderLayout.SOUTH);
928     this.add(hscrollHolder, BorderLayout.SOUTH);
929     hscrollHolder.add(hscroll, BorderLayout.CENTER);
930     hscrollHolder.add(hscrollFillerPanel, BorderLayout.WEST);
931     this.add(sequenceHolderPanel, BorderLayout.CENTER);
932   }
933
934   /**
935    * hides or shows dynamic annotation rows based on groups and av state flags
936    */
937   public void updateAnnotation()
938   {
939     updateAnnotation(false);
940   }
941
942   public void updateAnnotation(boolean applyGlobalSettings)
943   {
944     updateAnnotation(applyGlobalSettings, false);
945   }
946
947   public void updateAnnotation(boolean applyGlobalSettings,
948           boolean preserveNewGroupSettings)
949   {
950     av.updateGroupAnnotationSettings(applyGlobalSettings,
951             preserveNewGroupSettings);
952     adjustAnnotationHeight();
953   }
954
955   @Override
956   public AlignmentI getAlignment()
957   {
958     return av.getAlignment();
959   }
960
961   @Override
962   public StructureSelectionManager getStructureSelectionManager()
963   {
964     return StructureSelectionManager
965             .getStructureSelectionManager(av.applet);
966   }
967
968   @Override
969   public void raiseOOMWarning(String string, OutOfMemoryError error)
970   {
971     // TODO: JAL-960
972     System.err.println("Out of memory whilst '" + string + "'");
973     error.printStackTrace();
974   }
975
976 }