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