JAL-966 allow access to viewport interface from alignPanel
[jalview.git] / src / jalview / gui / 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.gui;
22
23 import jalview.analysis.AnnotationSorter;
24 import jalview.api.AlignViewportI;
25 import jalview.api.AlignmentViewPanel;
26 import jalview.bin.Cache;
27 import jalview.datamodel.AlignmentI;
28 import jalview.datamodel.SearchResults;
29 import jalview.datamodel.SequenceFeature;
30 import jalview.datamodel.SequenceGroup;
31 import jalview.datamodel.SequenceI;
32 import jalview.jbgui.GAlignmentPanel;
33 import jalview.math.AlignmentDimension;
34 import jalview.schemes.ResidueProperties;
35 import jalview.structure.StructureSelectionManager;
36 import jalview.util.MessageManager;
37
38 import java.awt.BorderLayout;
39 import java.awt.Color;
40 import java.awt.Container;
41 import java.awt.Dimension;
42 import java.awt.Font;
43 import java.awt.FontMetrics;
44 import java.awt.Graphics;
45 import java.awt.event.AdjustmentEvent;
46 import java.awt.event.AdjustmentListener;
47 import java.awt.print.PageFormat;
48 import java.awt.print.Printable;
49 import java.awt.print.PrinterException;
50 import java.beans.PropertyChangeEvent;
51 import java.beans.PropertyChangeListener;
52 import java.io.File;
53 import java.io.FileWriter;
54 import java.io.PrintWriter;
55
56 import javax.swing.SwingUtilities;
57
58 /**
59  * DOCUMENT ME!
60  * 
61  * @author $author$
62  * @version $Revision: 1.161 $
63  */
64 public class AlignmentPanel extends GAlignmentPanel implements
65         AdjustmentListener, Printable, AlignmentViewPanel
66 {
67   public AlignViewport av;
68
69   OverviewPanel overviewPanel;
70
71   private SeqPanel seqPanel;
72
73   private IdPanel idPanel;
74
75   private boolean headless;
76   IdwidthAdjuster idwidthAdjuster;
77
78   /** DOCUMENT ME!! */
79   public AlignFrame alignFrame;
80
81   private ScalePanel scalePanel;
82
83   private AnnotationPanel annotationPanel;
84
85   private AnnotationLabels alabels;
86
87   // this value is set false when selection area being dragged
88   boolean fastPaint = true;
89
90   int hextent = 0;
91
92   int vextent = 0;
93
94   /**
95    * Creates a new AlignmentPanel object.
96    * 
97    * @param af
98    *          DOCUMENT ME!
99    * @param av
100    *          DOCUMENT ME!
101    */
102   public AlignmentPanel(AlignFrame af, final AlignViewport av)
103   {
104     alignFrame = af;
105     this.av = av;
106     setSeqPanel(new SeqPanel(av, this));
107     setIdPanel(new IdPanel(av, this));
108
109     setScalePanel(new ScalePanel(av, this));
110
111     idPanelHolder.add(getIdPanel(), BorderLayout.CENTER);
112     idwidthAdjuster = new IdwidthAdjuster(this);
113     idSpaceFillerPanel1.add(idwidthAdjuster, BorderLayout.CENTER);
114
115     setAnnotationPanel(new AnnotationPanel(this));
116     setAlabels(new AnnotationLabels(this));
117
118     annotationScroller.setViewportView(getAnnotationPanel());
119     annotationSpaceFillerHolder.add(getAlabels(), BorderLayout.CENTER);
120
121     scalePanelHolder.add(getScalePanel(), BorderLayout.CENTER);
122     seqPanelHolder.add(getSeqPanel(), BorderLayout.CENTER);
123
124     setScrollValues(0, 0);
125
126     setAnnotationVisible(av.isShowAnnotation());
127
128     hscroll.addAdjustmentListener(this);
129     vscroll.addAdjustmentListener(this);
130
131     final AlignmentPanel ap = this;
132     av.addPropertyChangeListener(new PropertyChangeListener()
133     {
134       public void propertyChange(PropertyChangeEvent evt)
135       {
136         if (evt.getPropertyName().equals("alignment"))
137         {
138           PaintRefresher.Refresh(ap, av.getSequenceSetId(), true, true);
139           alignmentChanged();
140         }
141       }
142     });
143     fontChanged();
144     adjustAnnotationHeight();
145
146   }
147
148   @Override
149   public AlignViewportI getAlignViewport()
150   {
151     return av;
152   }
153   public void alignmentChanged()
154   {
155     av.alignmentChanged(this);
156
157     alignFrame.updateEditMenuBar();
158
159     paintAlignment(true);
160
161   }
162
163   /**
164    * DOCUMENT ME!
165    */
166   public void fontChanged()
167   {
168     // set idCanvas bufferedImage to null
169     // to prevent drawing old image
170     FontMetrics fm = getFontMetrics(av.getFont());
171
172     scalePanelHolder.setPreferredSize(new Dimension(10, av.getCharHeight()
173             + fm.getDescent()));
174     idSpaceFillerPanel1.setPreferredSize(new Dimension(10, av
175             .getCharHeight()
176             + fm.getDescent()));
177
178     getIdPanel().getIdCanvas().gg = null;
179     getSeqPanel().seqCanvas.img = null;
180     getAnnotationPanel().adjustPanelHeight();
181
182     Dimension d = calculateIdWidth();
183     d.setSize(d.width + 4, d.height);
184     getIdPanel().getIdCanvas().setPreferredSize(d);
185     hscrollFillerPanel.setPreferredSize(d);
186
187     if (overviewPanel != null)
188     {
189       overviewPanel.setBoxPosition();
190     }
191
192     repaint();
193   }
194
195   /**
196    * Calculate the width of the alignment labels based on the displayed names
197    * and any bounds on label width set in preferences.
198    * 
199    * @return Dimension giving the maximum width of the alignment label panel
200    *         that should be used.
201    */
202   public Dimension calculateIdWidth()
203   {
204     // calculate sensible default width when no preference is available
205
206     int afwidth = (alignFrame != null ? alignFrame.getWidth() : 300);
207     int maxwidth = Math.max(20,
208             Math.min(afwidth - 200, 2 * afwidth / 3));
209     return calculateIdWidth(maxwidth);
210   }
211
212   /**
213    * Calculate the width of the alignment labels based on the displayed names
214    * and any bounds on label width set in preferences.
215    * 
216    * @param maxwidth
217    *          -1 or maximum width allowed for IdWidth
218    * @return Dimension giving the maximum width of the alignment label panel
219    *         that should be used.
220    */
221   public Dimension calculateIdWidth(int maxwidth)
222   {
223     Container c = new Container();
224
225     FontMetrics fm = c.getFontMetrics(new Font(av.font.getName(),
226             Font.ITALIC, av.font.getSize()));
227
228     AlignmentI al = av.getAlignment();
229     int i = 0;
230     int idWidth = 0;
231     String id;
232
233     while ((i < al.getHeight()) && (al.getSequenceAt(i) != null))
234     {
235       SequenceI s = al.getSequenceAt(i);
236
237       id = s.getDisplayId(av.getShowJVSuffix());
238
239       if (fm.stringWidth(id) > idWidth)
240       {
241         idWidth = fm.stringWidth(id);
242       }
243
244       i++;
245     }
246
247     // Also check annotation label widths
248     i = 0;
249
250     if (al.getAlignmentAnnotation() != null)
251     {
252       fm = c.getFontMetrics(getAlabels().getFont());
253
254       while (i < al.getAlignmentAnnotation().length)
255       {
256         String label = al.getAlignmentAnnotation()[i].label;
257
258         if (fm.stringWidth(label) > idWidth)
259         {
260           idWidth = fm.stringWidth(label);
261         }
262
263         i++;
264       }
265     }
266
267     return new Dimension(maxwidth < 0 ? idWidth : Math.min(maxwidth,
268             idWidth), 12);
269   }
270
271   /**
272    * Highlight the given results on the alignment.
273    * 
274    */
275   public void highlightSearchResults(SearchResults results)
276   {
277     scrollToPosition(results);
278     getSeqPanel().seqCanvas.highlightSearchResults(results);
279   }
280
281   /**
282    * scroll the view to show the position of the highlighted region in results
283    * (if any) and redraw the overview
284    * 
285    * @param results
286    */
287   public boolean scrollToPosition(SearchResults results)
288   {
289     return scrollToPosition(results, true);
290   }
291
292   /**
293    * scroll the view to show the position of the highlighted region in results
294    * (if any)
295    * 
296    * @param results
297    * @param redrawOverview
298    *          - when set, the overview will be recalculated (takes longer)
299    * @return false if results were not found
300    */
301   public boolean scrollToPosition(SearchResults results,
302           boolean redrawOverview)
303   {
304     int startv, endv, starts, ends, width;
305     // TODO: properly locate search results in view when large numbers of hidden
306     // columns exist before highlighted region
307     // do we need to scroll the panel?
308     // TODO: tons of nullpointereexceptions raised here.
309     if (results != null && results.getSize() > 0 && av != null
310             && av.getAlignment() != null)
311     {
312       int seqIndex = av.getAlignment().findIndex(results);
313       if (seqIndex == -1)
314       {
315         return false;
316       }
317       SequenceI seq = av.getAlignment().getSequenceAt(seqIndex);
318
319       int[] r = results.getResults(seq, 0, av.getAlignment().getWidth());
320       if (r == null)
321       {
322         return false;
323       }
324       int start = r[0];
325       int end = r[1];
326       // System.err.println("Seq : "+seqIndex+" Scroll to "+start+","+end); //
327       // DEBUG
328       if (start < 0)
329       {
330         return false;
331       }
332       if (end == seq.getEnd())
333       {
334         return false;
335       }
336       if (av.hasHiddenColumns())
337       {
338         start = av.getColumnSelection().findColumnPosition(start);
339         end = av.getColumnSelection().findColumnPosition(end);
340         if (start == end)
341         {
342           if (!av.getColumnSelection().isVisible(r[0]))
343           {
344             // don't scroll - position isn't visible
345             return false;
346           }
347         }
348       }
349       if (!av.getWrapAlignment())
350       {
351         if ((startv = av.getStartRes()) >= start)
352         {
353           setScrollValues(start - 1, seqIndex);
354         }
355         else if ((endv = av.getEndRes()) <= end)
356         {
357           setScrollValues(startv + 1 + end - endv, seqIndex);
358         }
359         else if ((starts = av.getStartSeq()) > seqIndex)
360         {
361           setScrollValues(av.getStartRes(), seqIndex);
362         }
363         else if ((ends = av.getEndSeq()) <= seqIndex)
364         {
365           setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1);
366         }
367       }
368       else
369       {
370         scrollToWrappedVisible(start);
371       }
372     }
373     if (redrawOverview && overviewPanel != null)
374     {
375       overviewPanel.setBoxPosition();
376     }
377     paintAlignment(redrawOverview);
378     return true;
379   }
380
381   void scrollToWrappedVisible(int res)
382   {
383     int cwidth = getSeqPanel().seqCanvas
384             .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
385     if (res < av.getStartRes() || res >= (av.getStartRes() + cwidth))
386     {
387       vscroll.setValue((res / cwidth));
388       av.startRes = vscroll.getValue() * cwidth;
389     }
390
391   }
392
393   /**
394    * DOCUMENT ME!
395    * 
396    * @return DOCUMENT ME!
397    */
398   public OverviewPanel getOverviewPanel()
399   {
400     return overviewPanel;
401   }
402
403   /**
404    * DOCUMENT ME!
405    * 
406    * @param op
407    *          DOCUMENT ME!
408    */
409   public void setOverviewPanel(OverviewPanel op)
410   {
411     overviewPanel = op;
412   }
413
414   /**
415    * 
416    * @param b
417    *          Hide or show annotation panel
418    * 
419    */
420   public void setAnnotationVisible(boolean b)
421   {
422     if (!av.getWrapAlignment())
423     {
424       annotationSpaceFillerHolder.setVisible(b);
425       annotationScroller.setVisible(b);
426     }
427     repaint();
428   }
429
430   /**
431    * automatically adjust annotation panel height for new annotation whilst
432    * ensuring the alignment is still visible.
433    */
434   public void adjustAnnotationHeight()
435   {
436     // TODO: display vertical annotation scrollbar if necessary
437     // this is called after loading new annotation onto alignment
438     if (alignFrame.getHeight() == 0)
439     {
440       System.out.println("NEEDS FIXING");
441     }
442     validateAnnotationDimensions(true);
443     addNotify();
444     paintAlignment(true);
445   }
446
447   /**
448    * calculate the annotation dimensions and refresh slider values accordingly.
449    * need to do repaints/notifys afterwards.
450    */
451   protected void validateAnnotationDimensions(boolean adjustPanelHeight)
452   {
453     int height = getAnnotationPanel().adjustPanelHeight();
454
455     int theight = av.getCharHeight()
456             * (av.getAlignment().getHeight() + (!av.hasHiddenRows() ? 0
457                     : av.getAlignment().getHiddenSequences().getSize()));
458     float sscaling = (float) (theight / (1.0 * theight + height));
459     float ascaling = (float) (height * 1.0 / alignFrame.getHeight());
460     int rheight = alignFrame.getHeight() - height - av.getCharHeight();
461     if (adjustPanelHeight)
462     {
463       // NOTE: this logic is different in the applet. Need a better algorithm to
464       // define behaviour
465       // try and set height according to alignment
466       if (ascaling > 0 && sscaling < 0.5)
467       {
468         // if the alignment is too big then
469         // default is 0.5 split
470         height = alignFrame.getHeight() / 2;
471       }
472       else
473       {
474         // if space for more than one sequence row left when annotation is fully
475         // displayed then set height to annotation height
476         // otherwise, leave at least two lines of sequence shown.
477         height = (rheight > av.getCharHeight()) ? height
478                 : (-av.getCharHeight() * 3 + (int) (alignFrame.getHeight() * (1 - sscaling)));
479       }
480     }
481     else
482     {
483       // maintain same window layout whilst updating sliders
484       height = annotationScroller.getSize().height;
485     }
486     hscroll.addNotify();
487
488     annotationScroller.setPreferredSize(new Dimension(annotationScroller
489             .getWidth(), height));
490
491     annotationSpaceFillerHolder.setPreferredSize(new Dimension(
492             annotationSpaceFillerHolder.getWidth(), height));
493     annotationScroller.validate();// repaint();
494     annotationScroller.addNotify();
495   }
496
497   /**
498    * DOCUMENT ME!
499    * 
500    * @param wrap
501    *          DOCUMENT ME!
502    */
503   public void setWrapAlignment(boolean wrap)
504   {
505     av.startSeq = 0;
506     scalePanelHolder.setVisible(!wrap);
507     hscroll.setVisible(!wrap);
508     idwidthAdjuster.setVisible(!wrap);
509
510     if (wrap)
511     {
512       annotationScroller.setVisible(false);
513       annotationSpaceFillerHolder.setVisible(false);
514     }
515     else if (av.isShowAnnotation())
516     {
517       annotationScroller.setVisible(true);
518       annotationSpaceFillerHolder.setVisible(true);
519     }
520
521     idSpaceFillerPanel1.setVisible(!wrap);
522
523     repaint();
524   }
525
526   // return value is true if the scroll is valid
527   public boolean scrollUp(boolean up)
528   {
529     if (up)
530     {
531       if (vscroll.getValue() < 1)
532       {
533         return false;
534       }
535
536       fastPaint = false;
537       vscroll.setValue(vscroll.getValue() - 1);
538     }
539     else
540     {
541       if ((vextent + vscroll.getValue()) >= av.getAlignment().getHeight())
542       {
543         return false;
544       }
545
546       fastPaint = false;
547       vscroll.setValue(vscroll.getValue() + 1);
548     }
549
550     fastPaint = true;
551
552     return true;
553   }
554
555   /**
556    * DOCUMENT ME!
557    * 
558    * @param right
559    *          DOCUMENT ME!
560    * 
561    * @return DOCUMENT ME!
562    */
563   public boolean scrollRight(boolean right)
564   {
565     if (!right)
566     {
567       if (hscroll.getValue() < 1)
568       {
569         return false;
570       }
571
572       fastPaint = false;
573       hscroll.setValue(hscroll.getValue() - 1);
574     }
575     else
576     {
577       if ((hextent + hscroll.getValue()) >= av.getAlignment().getWidth())
578       {
579         return false;
580       }
581
582       fastPaint = false;
583       hscroll.setValue(hscroll.getValue() + 1);
584     }
585
586     fastPaint = true;
587
588     return true;
589   }
590
591   /**
592    * Adjust row/column scrollers to show a visible position in the alignment.
593    * 
594    * @param x
595    *          visible column to scroll to DOCUMENT ME!
596    * @param y
597    *          visible row to scroll to
598    * 
599    */
600   public void setScrollValues(int x, int y)
601   {
602     // System.err.println("Scroll to "+x+","+y);
603     if (av == null || av.getAlignment() == null)
604     {
605       return;
606     }
607     int width = av.getAlignment().getWidth();
608     int height = av.getAlignment().getHeight();
609
610     if (av.hasHiddenColumns())
611     {
612       width = av.getColumnSelection().findColumnPosition(width);
613     }
614
615     av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av
616             .getCharWidth())) - 1);
617
618     hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth();
619     vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight();
620
621     if (hextent > width)
622     {
623       hextent = width;
624     }
625
626     if (vextent > height)
627     {
628       vextent = height;
629     }
630
631     if ((hextent + x) > width)
632     {
633       x = width - hextent;
634     }
635
636     if ((vextent + y) > height)
637     {
638       y = height - vextent;
639     }
640
641     if (y < 0)
642     {
643       y = 0;
644     }
645
646     if (x < 0)
647     {
648       x = 0;
649     }
650
651     hscroll.setValues(x, hextent, 0, width);
652     vscroll.setValues(y, vextent, 0, height);
653   }
654
655   /**
656    * DOCUMENT ME!
657    * 
658    * @param evt
659    *          DOCUMENT ME!
660    */
661   public void adjustmentValueChanged(AdjustmentEvent evt)
662   {
663
664     int oldX = av.getStartRes();
665     int oldY = av.getStartSeq();
666
667     if (evt.getSource() == hscroll)
668     {
669       int x = hscroll.getValue();
670       av.setStartRes(x);
671       av.setEndRes((x + (getSeqPanel().seqCanvas.getWidth() / av.getCharWidth())) - 1);
672     }
673
674     if (evt.getSource() == vscroll)
675     {
676       int offy = vscroll.getValue();
677
678       if (av.getWrapAlignment())
679       {
680         if (offy > -1)
681         {
682           int rowSize = getSeqPanel().seqCanvas
683                   .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
684           av.setStartRes(offy * rowSize);
685           av.setEndRes((offy + 1) * rowSize);
686         }
687         else
688         {
689           // This is only called if file loaded is a jar file that
690           // was wrapped when saved and user has wrap alignment true
691           // as preference setting
692           SwingUtilities.invokeLater(new Runnable()
693           {
694             public void run()
695             {
696               setScrollValues(av.getStartRes(), av.getStartSeq());
697             }
698           });
699         }
700       }
701       else
702       {
703         av.setStartSeq(offy);
704         av.setEndSeq(offy
705                 + (getSeqPanel().seqCanvas.getHeight() / 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)
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       if (scrollX != 0 || scrollY != 0)
735       {
736         getIdPanel().getIdCanvas().fastPaint(scrollY);
737         getSeqPanel().seqCanvas.fastPaint(scrollX, scrollY);
738         getScalePanel().repaint();
739
740         if (av.isShowAnnotation() && scrollX != 0)
741         {
742           getAnnotationPanel().fastPaint(scrollX);
743         }
744       }
745     }
746   }
747
748   /**
749    * Repaint the alignment including the annotations and overview panels (if
750    * shown).
751    */
752   public void paintAlignment(boolean updateOverview)
753   {
754     final AnnotationSorter sorter = new AnnotationSorter(getAlignment(),
755             av.isShowAutocalculatedAbove());
756     sorter.sort(getAlignment()
757             .getAlignmentAnnotation(),
758             av.getSortAnnotationsBy());
759     repaint();
760
761     if (updateOverview)
762     {
763       av.getStructureSelectionManager().sequenceColoursChanged(this);
764
765       if (overviewPanel != null)
766       {
767         overviewPanel.updateOverviewImage();
768       }
769     }
770   }
771
772   /**
773    * DOCUMENT ME!
774    * 
775    * @param g
776    *          DOCUMENT ME!
777    */
778   public void paintComponent(Graphics g)
779   {
780     invalidate();
781
782     Dimension d = getIdPanel().getIdCanvas().getPreferredSize();
783     idPanelHolder.setPreferredSize(d);
784     hscrollFillerPanel.setPreferredSize(new Dimension(d.width, 12));
785     validate();
786
787     if (av.getWrapAlignment())
788     {
789       int maxwidth = av.getAlignment().getWidth();
790
791       if (av.hasHiddenColumns())
792       {
793         maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
794       }
795
796       int canvasWidth = getSeqPanel().seqCanvas
797               .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth());
798       if (canvasWidth > 0)
799       {
800         int max = maxwidth
801                 / getSeqPanel().seqCanvas
802                         .getWrappedCanvasWidth(getSeqPanel().seqCanvas
803                                 .getWidth()) + 1;
804         vscroll.setMaximum(max);
805         vscroll.setUnitIncrement(1);
806         vscroll.setVisibleAmount(1);
807       }
808     }
809     else
810     {
811       setScrollValues(av.getStartRes(), av.getStartSeq());
812     }
813   }
814
815   /**
816    * DOCUMENT ME!
817    * 
818    * @param pg
819    *          DOCUMENT ME!
820    * @param pf
821    *          DOCUMENT ME!
822    * @param pi
823    *          DOCUMENT ME!
824    * 
825    * @return DOCUMENT ME!
826    * 
827    * @throws PrinterException
828    *           DOCUMENT ME!
829    */
830   public int print(Graphics pg, PageFormat pf, int pi)
831           throws PrinterException
832   {
833     pg.translate((int) pf.getImageableX(), (int) pf.getImageableY());
834
835     int pwidth = (int) pf.getImageableWidth();
836     int pheight = (int) pf.getImageableHeight();
837
838     if (av.getWrapAlignment())
839     {
840       return printWrappedAlignment(pg, pwidth, pheight, pi);
841     }
842     else
843     {
844       return printUnwrapped(pg, pwidth, pheight, pi);
845     }
846   }
847
848   /**
849    * DOCUMENT ME!
850    * 
851    * @param pg
852    *          DOCUMENT ME!
853    * @param pwidth
854    *          DOCUMENT ME!
855    * @param pheight
856    *          DOCUMENT ME!
857    * @param pi
858    *          DOCUMENT ME!
859    * 
860    * @return DOCUMENT ME!
861    * 
862    * @throws PrinterException
863    *           DOCUMENT ME!
864    */
865   public int printUnwrapped(Graphics pg, int pwidth, int pheight, int pi)
866           throws PrinterException
867   {
868     int idWidth = getVisibleIdWidth(false);
869     FontMetrics fm = getFontMetrics(av.getFont());
870     int scaleHeight = av.getCharHeight() + fm.getDescent();
871
872     pg.setColor(Color.white);
873     pg.fillRect(0, 0, pwidth, pheight);
874     pg.setFont(av.getFont());
875
876     // //////////////////////////////////
877     // / How many sequences and residues can we fit on a printable page?
878     int totalRes = (pwidth - idWidth) / av.getCharWidth();
879
880     int totalSeq = (pheight - scaleHeight) / av.getCharHeight() - 1;
881
882     int pagesWide = (av.getAlignment().getWidth() / totalRes) + 1;
883
884     // ///////////////////////////
885     // / Only print these sequences and residues on this page
886     int startRes;
887
888     // ///////////////////////////
889     // / Only print these sequences and residues on this page
890     int endRes;
891
892     // ///////////////////////////
893     // / Only print these sequences and residues on this page
894     int startSeq;
895
896     // ///////////////////////////
897     // / Only print these sequences and residues on this page
898     int endSeq;
899     startRes = (pi % pagesWide) * totalRes;
900     endRes = (startRes + totalRes) - 1;
901
902     if (endRes > (av.getAlignment().getWidth() - 1))
903     {
904       endRes = av.getAlignment().getWidth() - 1;
905     }
906
907     startSeq = (pi / pagesWide) * totalSeq;
908     endSeq = startSeq + totalSeq;
909
910     if (endSeq > av.getAlignment().getHeight())
911     {
912       endSeq = av.getAlignment().getHeight();
913     }
914
915     int pagesHigh = ((av.getAlignment().getHeight() / totalSeq) + 1)
916             * pheight;
917
918     if (av.isShowAnnotation())
919     {
920       pagesHigh += getAnnotationPanel().adjustPanelHeight() + 3;
921     }
922
923     pagesHigh /= pheight;
924
925     if (pi >= (pagesWide * pagesHigh))
926     {
927       return Printable.NO_SUCH_PAGE;
928     }
929
930     // draw Scale
931     pg.translate(idWidth, 0);
932     getScalePanel().drawScale(pg, startRes, endRes, pwidth - idWidth,
933             scaleHeight);
934     pg.translate(-idWidth, scaleHeight);
935
936     // //////////////
937     // Draw the ids
938     Color currentColor = null;
939     Color currentTextColor = null;
940
941     pg.setFont(getIdPanel().getIdCanvas().getIdfont());
942
943     SequenceI seq;
944     for (int i = startSeq; i < endSeq; i++)
945     {
946       seq = av.getAlignment().getSequenceAt(i);
947       if ((av.getSelectionGroup() != null)
948               && av.getSelectionGroup().getSequences(null).contains(seq))
949       {
950         currentColor = Color.gray;
951         currentTextColor = Color.black;
952       }
953       else
954       {
955         currentColor = av.getSequenceColour(seq);
956         currentTextColor = Color.black;
957       }
958
959       pg.setColor(currentColor);
960       pg.fillRect(0, (i - startSeq) * av.getCharHeight(), idWidth,
961               av.getCharHeight());
962
963       pg.setColor(currentTextColor);
964
965       int xPos = 0;
966       if (av.isRightAlignIds())
967       {
968         fm = pg.getFontMetrics();
969         xPos = idWidth
970                 - fm.stringWidth(seq.getDisplayId(av.getShowJVSuffix()))
971                 - 4;
972       }
973
974       pg.drawString(
975               seq.getDisplayId(av.getShowJVSuffix()),
976               xPos,
977               (((i - startSeq) * av.getCharHeight()) + av.getCharHeight())
978                       - (av.getCharHeight() / 5));
979     }
980
981     pg.setFont(av.getFont());
982
983     // draw main sequence panel
984     pg.translate(idWidth, 0);
985     getSeqPanel().seqCanvas.drawPanel(pg, startRes, endRes, startSeq, endSeq, 0);
986
987     if (av.isShowAnnotation() && (endSeq == av.getAlignment().getHeight()))
988     {
989       // draw annotation - need to offset for current scroll position
990       int offset = -getAlabels().getScrollOffset();
991       pg.translate(0, offset);
992       pg.translate(-idWidth - 3, (endSeq - startSeq) * av.getCharHeight()
993               + 3);
994       getAlabels().drawComponent(pg, idWidth);
995       pg.translate(idWidth + 3, 0);
996       getAnnotationPanel().renderer.drawComponent(getAnnotationPanel(), av,
997               pg, -1, startRes, endRes + 1);
998       pg.translate(0, -offset);
999     }
1000
1001     return Printable.PAGE_EXISTS;
1002   }
1003
1004   /**
1005    * DOCUMENT ME!
1006    * 
1007    * @param pg
1008    *          DOCUMENT ME!
1009    * @param pwidth
1010    *          DOCUMENT ME!
1011    * @param pheight
1012    *          DOCUMENT ME!
1013    * @param pi
1014    *          DOCUMENT ME!
1015    * 
1016    * @return DOCUMENT ME!
1017    * 
1018    * @throws PrinterException
1019    *           DOCUMENT ME!
1020    */
1021   public int printWrappedAlignment(Graphics pg, int pwidth, int pheight,
1022           int pi) throws PrinterException
1023   {
1024     int annotationHeight = 0;
1025     AnnotationLabels labels = null;
1026     if (av.isShowAnnotation())
1027     {
1028       annotationHeight = getAnnotationPanel().adjustPanelHeight();
1029       labels = new AnnotationLabels(av);
1030     }
1031
1032     int hgap = av.getCharHeight();
1033     if (av.getScaleAboveWrapped())
1034     {
1035       hgap += av.getCharHeight();
1036     }
1037
1038     int cHeight = av.getAlignment().getHeight() * av.getCharHeight() + hgap
1039             + annotationHeight;
1040
1041     int idWidth = getVisibleIdWidth(false);
1042
1043     int maxwidth = av.getAlignment().getWidth();
1044     if (av.hasHiddenColumns())
1045     {
1046       maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
1047     }
1048
1049     int resWidth = getSeqPanel().seqCanvas.getWrappedCanvasWidth(pwidth
1050             - idWidth);
1051
1052     int totalHeight = cHeight * (maxwidth / resWidth + 1);
1053
1054     pg.setColor(Color.white);
1055     pg.fillRect(0, 0, pwidth, pheight);
1056     pg.setFont(av.getFont());
1057
1058     // //////////////
1059     // Draw the ids
1060     pg.setColor(Color.black);
1061
1062     pg.translate(0, -pi * pheight);
1063
1064     pg.setClip(0, pi * pheight, pwidth, pheight);
1065
1066     int ypos = hgap;
1067
1068     do
1069     {
1070       for (int i = 0; i < av.getAlignment().getHeight(); i++)
1071       {
1072         pg.setFont(getIdPanel().getIdCanvas().getIdfont());
1073         SequenceI s = av.getAlignment().getSequenceAt(i);
1074         String string = s.getDisplayId(av.getShowJVSuffix());
1075         int xPos = 0;
1076         if (av.isRightAlignIds())
1077         {
1078           FontMetrics fm = pg.getFontMetrics();
1079           xPos = idWidth - fm.stringWidth(string) - 4;
1080         }
1081         pg.drawString(string, xPos,
1082                 ((i * av.getCharHeight()) + ypos + av.getCharHeight())
1083                         - (av.getCharHeight() / 5));
1084       }
1085       if (labels != null)
1086       {
1087         pg.translate(-3, ypos
1088  + (av.getAlignment().getHeight() * av.getCharHeight()));
1089
1090         pg.setFont(av.getFont());
1091         labels.drawComponent(pg, idWidth);
1092         pg.translate(+3, -ypos
1093                         - (av.getAlignment().getHeight() * av
1094                                 .getCharHeight()));
1095       }
1096
1097       ypos += cHeight;
1098     } while (ypos < totalHeight);
1099
1100     pg.translate(idWidth, 0);
1101
1102     getSeqPanel().seqCanvas.drawWrappedPanel(pg, pwidth - idWidth, totalHeight,
1103             0);
1104
1105     if ((pi * pheight) < totalHeight)
1106     {
1107       return Printable.PAGE_EXISTS;
1108
1109     }
1110     else
1111     {
1112       return Printable.NO_SUCH_PAGE;
1113     }
1114   }
1115
1116   /**
1117    * get current sequence ID panel width, or nominal value if panel were to be
1118    * displayed using default settings
1119    * 
1120    * @return
1121    */
1122   public int getVisibleIdWidth()
1123   {
1124     return getVisibleIdWidth(true);
1125   }
1126
1127   /**
1128    * get current sequence ID panel width, or nominal value if panel were to be
1129    * displayed using default settings
1130    * 
1131    * @param onscreen
1132    *          indicate if the Id width for onscreen or offscreen display should
1133    *          be returned
1134    * @return
1135    */
1136   public int getVisibleIdWidth(boolean onscreen)
1137   {
1138     // see if rendering offscreen - check preferences and calc width accordingly
1139     if (!onscreen && Cache.getDefault("FIGURE_AUTOIDWIDTH", false))
1140     {
1141       return calculateIdWidth(-1).width + 4;
1142     }
1143     Integer idwidth = null;
1144     if (onscreen
1145             || (idwidth = Cache.getIntegerProperty("FIGURE_FIXEDIDWIDTH")) == null)
1146     {
1147       return (getIdPanel().getWidth() > 0 ? getIdPanel().getWidth()
1148               : calculateIdWidth().width + 4);
1149     }
1150     return idwidth.intValue() + 4;
1151   }
1152
1153   void makeAlignmentImage(jalview.util.ImageMaker.TYPE type, File file)
1154   {
1155     long progress = System.currentTimeMillis();
1156     headless = (System.getProperty("java.awt.headless") != null && System
1157             .getProperty("java.awt.headless").equals("true"));
1158     if (alignFrame != null && !headless)
1159     {
1160       alignFrame.setProgressBar(MessageManager.formatMessage(
1161               "status.saving_file",
1162               new String[]
1163               { type.getLabel() }), progress);
1164     }
1165     try
1166     {
1167       AlignmentDimension aDimension = getAlignmentDimension();
1168       try
1169       {
1170         jalview.util.ImageMaker im;
1171         final String imageAction, imageTitle;
1172         if (type == jalview.util.ImageMaker.TYPE.PNG)
1173         {
1174           imageAction = "Create PNG image from alignment";
1175           imageTitle = null;
1176         }
1177         else if (type == jalview.util.ImageMaker.TYPE.EPS)
1178         {
1179           imageAction = "Create EPS file from alignment";
1180           imageTitle = alignFrame.getTitle();
1181         }
1182         else
1183         {
1184           imageAction = "Create SVG file from alignment";
1185           imageTitle = alignFrame.getTitle();
1186         }
1187
1188         im = new jalview.util.ImageMaker(this, type, imageAction,
1189                 aDimension.getWidth(), aDimension.getHeight(), file,
1190                 imageTitle);
1191         if (av.getWrapAlignment())
1192         {
1193           if (im.getGraphics() != null)
1194           {
1195             printWrappedAlignment(im.getGraphics(), aDimension.getWidth(),
1196                     aDimension.getHeight(), 0);
1197             im.writeImage();
1198           }
1199         }
1200         else
1201         {
1202           if (im.getGraphics() != null)
1203           {
1204             printUnwrapped(im.getGraphics(), aDimension.getWidth(),
1205                     aDimension.getHeight(), 0);
1206             im.writeImage();
1207           }
1208         }
1209       } catch (OutOfMemoryError err)
1210       {
1211         // Be noisy here.
1212         System.out.println("########################\n" + "OUT OF MEMORY "
1213                 + file + "\n" + "########################");
1214         new OOMWarning("Creating Image for " + file, err);
1215         // System.out.println("Create IMAGE: " + err);
1216       } catch (Exception ex)
1217       {
1218         ex.printStackTrace();
1219       }
1220     } finally
1221     {
1222       if (alignFrame != null && !headless)
1223       {
1224         alignFrame.setProgressBar(MessageManager.getString("status.export_complete"), progress);
1225       }
1226     }
1227   }
1228
1229   public AlignmentDimension getAlignmentDimension()
1230   {
1231     int maxwidth = av.getAlignment().getWidth();
1232     if (av.hasHiddenColumns())
1233     {
1234       maxwidth = av.getColumnSelection().findColumnPosition(maxwidth);
1235     }
1236
1237     int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight())
1238             + getScalePanel().getHeight();
1239     int width = getVisibleIdWidth(false) + (maxwidth * av.getCharWidth());
1240
1241     if (av.getWrapAlignment())
1242     {
1243       height = getWrappedHeight();
1244       if (headless)
1245       {
1246         // need to obtain default alignment width and then add in any
1247         // additional allowance for id margin
1248         // this duplicates the calculation in getWrappedHeight but adjusts for
1249         // offscreen idWith
1250         width = alignFrame.getWidth() - vscroll.getPreferredSize().width
1251                 - alignFrame.getInsets().left
1252                 - alignFrame.getInsets().right - getVisibleIdWidth()
1253                 + getVisibleIdWidth(false);
1254       }
1255       else
1256       {
1257         width = getSeqPanel().getWidth() + getVisibleIdWidth(false);
1258       }
1259
1260     }
1261     else if (av.isShowAnnotation())
1262     {
1263       height += getAnnotationPanel().adjustPanelHeight() + 3;
1264     }
1265     return new AlignmentDimension(width, height);
1266
1267   }
1268
1269   /**
1270    * DOCUMENT ME!
1271    */
1272   public void makeEPS(File epsFile)
1273   {
1274     makeAlignmentImage(jalview.util.ImageMaker.TYPE.EPS, epsFile);
1275   }
1276
1277   /**
1278    * DOCUMENT ME!
1279    */
1280   public void makePNG(File pngFile)
1281   {
1282     makeAlignmentImage(jalview.util.ImageMaker.TYPE.PNG, pngFile);
1283   }
1284
1285   public void makeSVG(File svgFile)
1286   {
1287     makeAlignmentImage(jalview.util.ImageMaker.TYPE.SVG, svgFile);
1288   }
1289   public void makePNGImageMap(File imgMapFile, String imageName)
1290   {
1291     // /////ONLY WORKS WITH NONE WRAPPED ALIGNMENTS
1292     // ////////////////////////////////////////////
1293     int idWidth = getVisibleIdWidth(false);
1294     FontMetrics fm = getFontMetrics(av.getFont());
1295     int scaleHeight = av.getCharHeight() + fm.getDescent();
1296
1297     // Gen image map
1298     // ////////////////////////////////
1299     if (imgMapFile != null)
1300     {
1301       try
1302       {
1303         int s, sSize = av.getAlignment().getHeight(), res, alwidth = av
1304                 .getAlignment().getWidth(), g, gSize, f, fSize, sy;
1305         StringBuffer text = new StringBuffer();
1306         PrintWriter out = new PrintWriter(new FileWriter(imgMapFile));
1307         out.println(jalview.io.HTMLOutput.getImageMapHTML());
1308         out.println("<img src=\"" + imageName
1309                 + "\" border=\"0\" usemap=\"#Map\" >"
1310                 + "<map name=\"Map\">");
1311
1312         for (s = 0; s < sSize; s++)
1313         {
1314           sy = s * av.getCharHeight() + scaleHeight;
1315
1316           SequenceI seq = av.getAlignment().getSequenceAt(s);
1317           SequenceFeature[] features = seq.getDatasetSequence()
1318                   .getSequenceFeatures();
1319           SequenceGroup[] groups = av.getAlignment().findAllGroups(seq);
1320           for (res = 0; res < alwidth; res++)
1321           {
1322             text = new StringBuffer();
1323             Object obj = null;
1324             if (av.getAlignment().isNucleotide())
1325             {
1326               obj = ResidueProperties.nucleotideName.get(seq.getCharAt(res)
1327                       + "");
1328             }
1329             else
1330             {
1331               obj = ResidueProperties.aa2Triplet.get(seq.getCharAt(res)
1332                       + "");
1333             }
1334
1335             if (obj == null)
1336             {
1337               continue;
1338             }
1339
1340             String triplet = obj.toString();
1341             int alIndex = seq.findPosition(res);
1342             gSize = groups.length;
1343             for (g = 0; g < gSize; g++)
1344             {
1345               if (text.length() < 1)
1346               {
1347                 text.append("<area shape=\"rect\" coords=\""
1348                         + (idWidth + res * av.getCharWidth()) + "," + sy
1349                         + "," + (idWidth + (res + 1) * av.getCharWidth())
1350                         + ","
1351                         + (av.getCharHeight() + sy) + "\""
1352                         + " onMouseOver=\"toolTip('" + alIndex + " "
1353                         + triplet);
1354               }
1355
1356               if (groups[g].getStartRes() < res
1357                       && groups[g].getEndRes() > res)
1358               {
1359                 text.append("<br><em>" + groups[g].getName() + "</em>");
1360               }
1361             }
1362
1363             if (features != null)
1364             {
1365               if (text.length() < 1)
1366               {
1367                 text.append("<area shape=\"rect\" coords=\""
1368                         + (idWidth + res * av.getCharWidth()) + "," + sy
1369                         + "," + (idWidth + (res + 1) * av.getCharWidth())
1370                         + ","
1371                         + (av.getCharHeight() + sy) + "\""
1372                         + " onMouseOver=\"toolTip('" + alIndex + " "
1373                         + triplet);
1374               }
1375               fSize = features.length;
1376               for (f = 0; f < fSize; f++)
1377               {
1378
1379                 if ((features[f].getBegin() <= seq.findPosition(res))
1380                         && (features[f].getEnd() >= seq.findPosition(res)))
1381                 {
1382                   if (features[f].getType().equals("disulfide bond"))
1383                   {
1384                     if (features[f].getBegin() == seq.findPosition(res)
1385                             || features[f].getEnd() == seq
1386                                     .findPosition(res))
1387                     {
1388                       text.append("<br>disulfide bond "
1389                               + features[f].getBegin() + ":"
1390                               + features[f].getEnd());
1391                     }
1392                   }
1393                   else
1394                   {
1395                     text.append("<br>");
1396                     text.append(features[f].getType());
1397                     if (features[f].getDescription() != null
1398                             && !features[f].getType().equals(
1399                                     features[f].getDescription()))
1400                     {
1401                       text.append(" " + features[f].getDescription());
1402                     }
1403
1404                     if (features[f].getValue("status") != null)
1405                     {
1406                       text.append(" (" + features[f].getValue("status")
1407                               + ")");
1408                     }
1409                   }
1410                 }
1411
1412               }
1413             }
1414             if (text.length() > 1)
1415             {
1416               text.append("')\"; onMouseOut=\"toolTip()\";  href=\"#\">");
1417               out.println(text.toString());
1418             }
1419           }
1420         }
1421         out.println("</map></body></html>");
1422         out.close();
1423
1424       } catch (Exception ex)
1425       {
1426         ex.printStackTrace();
1427       }
1428     } // /////////END OF IMAGE MAP
1429
1430   }
1431
1432   int getWrappedHeight()
1433   {
1434     int seqPanelWidth = getSeqPanel().seqCanvas.getWidth();
1435
1436     if (System.getProperty("java.awt.headless") != null
1437             && System.getProperty("java.awt.headless").equals("true"))
1438     {
1439       seqPanelWidth = alignFrame.getWidth() - getVisibleIdWidth()
1440               - vscroll.getPreferredSize().width
1441               - alignFrame.getInsets().left - alignFrame.getInsets().right;
1442     }
1443
1444     int chunkWidth = getSeqPanel().seqCanvas
1445             .getWrappedCanvasWidth(seqPanelWidth);
1446
1447     int hgap = av.getCharHeight();
1448     if (av.getScaleAboveWrapped())
1449     {
1450       hgap += av.getCharHeight();
1451     }
1452
1453     int annotationHeight = 0;
1454     if (av.isShowAnnotation())
1455     {
1456       annotationHeight = getAnnotationPanel().adjustPanelHeight();
1457     }
1458
1459     int cHeight = av.getAlignment().getHeight() * av.getCharHeight() + hgap
1460             + annotationHeight;
1461
1462     int maxwidth = av.getAlignment().getWidth();
1463     if (av.hasHiddenColumns())
1464     {
1465       maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
1466     }
1467
1468     int height = ((maxwidth / chunkWidth) + 1) * cHeight;
1469
1470     return height;
1471   }
1472
1473   /**
1474    * close the panel - deregisters all listeners and nulls any references to
1475    * alignment data.
1476    */
1477   public void closePanel()
1478   {
1479     PaintRefresher.RemoveComponent(getSeqPanel().seqCanvas);
1480     PaintRefresher.RemoveComponent(getIdPanel().getIdCanvas());
1481     PaintRefresher.RemoveComponent(this);
1482     if (av != null)
1483     {
1484       jalview.structure.StructureSelectionManager ssm = av
1485               .getStructureSelectionManager();
1486       ssm.removeStructureViewerListener(getSeqPanel(), null);
1487       ssm.removeSelectionListener(getSeqPanel());
1488       av.setAlignment(null);
1489       av = null;
1490     }
1491     else
1492     {
1493       if (Cache.log.isDebugEnabled())
1494       {
1495         Cache.log.warn("Closing alignment panel which is already closed.");
1496       }
1497     }
1498   }
1499
1500   /**
1501    * hides or shows dynamic annotation rows based on groups and av state flags
1502    */
1503   public void updateAnnotation()
1504   {
1505     updateAnnotation(false, false);
1506   }
1507
1508   public void updateAnnotation(boolean applyGlobalSettings)
1509   {
1510     updateAnnotation(applyGlobalSettings, false);
1511   }
1512
1513   public void updateAnnotation(boolean applyGlobalSettings,
1514           boolean preserveNewGroupSettings)
1515   {
1516     av.updateGroupAnnotationSettings(applyGlobalSettings,
1517             preserveNewGroupSettings);
1518     adjustAnnotationHeight();
1519   }
1520
1521   @Override
1522   public AlignmentI getAlignment()
1523   {
1524     return av.getAlignment();
1525   }
1526
1527
1528   @Override
1529   public String getViewName()
1530   {
1531     return av.viewName;
1532   }
1533
1534   /**
1535    * Make/Unmake this alignment panel the current input focus
1536    * 
1537    * @param b
1538    */
1539   public void setSelected(boolean b)
1540   {
1541     try
1542     {
1543       alignFrame.setSelected(b);
1544     } catch (Exception ex)
1545     {
1546     }
1547     ;
1548
1549     if (b)
1550     {
1551       alignFrame.setDisplayedView(this);
1552     }
1553   }
1554
1555   @Override
1556   public StructureSelectionManager getStructureSelectionManager()
1557   {
1558     return av.getStructureSelectionManager();
1559   }
1560
1561   @Override
1562   public void raiseOOMWarning(String string, OutOfMemoryError error)
1563   {
1564     new OOMWarning(string, error, this);
1565   }
1566
1567   @Override
1568   public jalview.api.FeatureRenderer cloneFeatureRenderer()
1569   {
1570
1571     return new FeatureRenderer(this);
1572   }
1573   @Override 
1574   public jalview.api.FeatureRenderer getFeatureRenderer()
1575   {
1576     return seqPanel.seqCanvas.getFeatureRenderer();
1577   }
1578   public void updateFeatureRenderer(jalview.renderer.seqfeatures.FeatureRenderer fr)
1579   {
1580     fr.transferSettings(getSeqPanel().seqCanvas.getFeatureRenderer());
1581   }
1582
1583   public void updateFeatureRendererFrom(jalview.api.FeatureRenderer fr)
1584   {
1585     if (getSeqPanel().seqCanvas.getFeatureRenderer() != null)
1586     {
1587       getSeqPanel().seqCanvas.getFeatureRenderer().transferSettings(fr);
1588     }
1589   }
1590
1591   public ScalePanel getScalePanel()
1592   {
1593     return scalePanel;
1594   }
1595
1596   public void setScalePanel(ScalePanel scalePanel)
1597   {
1598     this.scalePanel = scalePanel;
1599   }
1600
1601   public SeqPanel getSeqPanel()
1602   {
1603     return seqPanel;
1604   }
1605
1606   public void setSeqPanel(SeqPanel seqPanel)
1607   {
1608     this.seqPanel = seqPanel;
1609   }
1610
1611   public AnnotationPanel getAnnotationPanel()
1612   {
1613     return annotationPanel;
1614   }
1615
1616   public void setAnnotationPanel(AnnotationPanel annotationPanel)
1617   {
1618     this.annotationPanel = annotationPanel;
1619   }
1620
1621   public AnnotationLabels getAlabels()
1622   {
1623     return alabels;
1624   }
1625
1626   public void setAlabels(AnnotationLabels alabels)
1627   {
1628     this.alabels = alabels;
1629   }
1630
1631   public IdPanel getIdPanel()
1632   {
1633     return idPanel;
1634   }
1635
1636   public void setIdPanel(IdPanel idPanel)
1637   {
1638     this.idPanel = idPanel;
1639   }
1640 }