use OOMwarning to warn user when out of Memory occurs
[jalview.git] / src / jalview / gui / AlignmentPanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3  * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.gui;
20
21 import java.beans.*;
22 import java.io.*;
23
24 import java.awt.*;
25 import java.awt.event.*;
26 import java.awt.print.*;
27 import javax.swing.*;
28
29 import jalview.datamodel.*;
30 import jalview.jbgui.*;
31 import jalview.schemes.*;
32
33 /**
34  * DOCUMENT ME!
35  *
36  * @author $author$
37  * @version $Revision$
38  */
39 public class AlignmentPanel
40     extends GAlignmentPanel implements AdjustmentListener, Printable
41 {
42   public AlignViewport av;
43   OverviewPanel overviewPanel;
44   SeqPanel seqPanel;
45   IdPanel idPanel;
46   IdwidthAdjuster idwidthAdjuster;
47
48   /** DOCUMENT ME!! */
49   public AlignFrame alignFrame;
50   ScalePanel scalePanel;
51   AnnotationPanel annotationPanel;
52   AnnotationLabels alabels;
53
54   // this value is set false when selection area being dragged
55   boolean fastPaint = true;
56   int hextent = 0;
57   int vextent = 0;
58
59   /**
60    * Creates a new AlignmentPanel object.
61    *
62    * @param af DOCUMENT ME!
63    * @param av DOCUMENT ME!
64    */
65   public AlignmentPanel(AlignFrame af, final AlignViewport av)
66   {
67     alignFrame = af;
68     this.av = av;
69     seqPanel = new SeqPanel(av, this);
70     idPanel = new IdPanel(av, this);
71
72     scalePanel = new ScalePanel(av, this);
73
74     idPanelHolder.add(idPanel, BorderLayout.CENTER);
75     idwidthAdjuster = new IdwidthAdjuster(this);
76     idSpaceFillerPanel1.add(idwidthAdjuster, BorderLayout.CENTER);
77
78     annotationPanel = new AnnotationPanel(this);
79     alabels = new AnnotationLabels(this);
80
81     annotationScroller.setViewportView(annotationPanel);
82     annotationSpaceFillerHolder.add(alabels, BorderLayout.CENTER);
83
84     scalePanelHolder.add(scalePanel, BorderLayout.CENTER);
85     seqPanelHolder.add(seqPanel, BorderLayout.CENTER);
86
87     setScrollValues(0, 0);
88
89     setAnnotationVisible(av.getShowAnnotation());
90
91     hscroll.addAdjustmentListener(this);
92     vscroll.addAdjustmentListener(this);
93
94     final AlignmentPanel ap = this;
95     av.addPropertyChangeListener(new PropertyChangeListener()
96     {
97       public void propertyChange(PropertyChangeEvent evt)
98       {
99         if (evt.getPropertyName().equals("alignment"))
100         {
101           PaintRefresher.Refresh(ap,
102                                  av.getSequenceSetId(),
103                                  true,
104                                  true);
105           alignmentChanged();
106         }
107       }
108     });
109
110     fontChanged();
111     adjustAnnotationHeight();
112
113   }
114
115   public void alignmentChanged()
116   {
117     av.alignmentChanged(this);
118
119     alignFrame.updateEditMenuBar();
120
121     paintAlignment(true);
122
123   }
124
125   /**
126    * DOCUMENT ME!
127    */
128   public void fontChanged()
129   {
130     // set idCanvas bufferedImage to null
131     // to prevent drawing old image
132     FontMetrics fm = getFontMetrics(av.getFont());
133
134     scalePanelHolder.setPreferredSize(new Dimension(10,
135         av.charHeight + fm.getDescent()));
136     idSpaceFillerPanel1.setPreferredSize(new Dimension(10,
137         av.charHeight + fm.getDescent()));
138
139     idPanel.idCanvas.gg = null;
140     seqPanel.seqCanvas.img = null;
141     annotationPanel.adjustPanelHeight();
142
143     Dimension d = calculateIdWidth();
144     d.setSize(d.width + 4, d.height);
145     idPanel.idCanvas.setPreferredSize(d);
146     hscrollFillerPanel.setPreferredSize(d);
147
148     if (overviewPanel != null)
149     {
150       overviewPanel.setBoxPosition();
151     }
152
153     repaint();
154   }
155
156   /**
157    * Calculate the width of the alignment labels based on the displayed names and any bounds on label width set in preferences.
158    *
159    * @return Dimension giving the maximum width of the alignment label panel that should be used.
160    */
161   public Dimension calculateIdWidth()
162   {
163     Container c = new Container();
164
165     FontMetrics fm = c.getFontMetrics(
166         new Font(av.font.getName(), Font.ITALIC, av.font.getSize()));
167
168     AlignmentI al = av.getAlignment();
169     int afwidth = (alignFrame!=null ? alignFrame.getWidth() : 300); 
170     int maxwidth = Math.max(20,Math.min(afwidth-200,(int) 2*afwidth/3));  
171     int i = 0;
172     int idWidth = 0;
173     String id;
174
175     while ( (i < al.getHeight()) && (al.getSequenceAt(i) != null))
176     {
177       SequenceI s = al.getSequenceAt(i);
178
179       id = s.getDisplayId(av.getShowJVSuffix());
180
181       if (fm.stringWidth(id) > idWidth)
182       {
183         idWidth = fm.stringWidth(id);
184       }
185
186       i++;
187     }
188
189     // Also check annotation label widths
190     i = 0;
191
192     if (al.getAlignmentAnnotation() != null)
193     {
194       fm = c.getFontMetrics(alabels.getFont());
195
196       while (i < al.getAlignmentAnnotation().length)
197       {
198         String label = al.getAlignmentAnnotation()[i].label;
199
200         if (fm.stringWidth(label) > idWidth)
201         {
202           idWidth = fm.stringWidth(label);
203         }
204
205         i++;
206       }
207     }
208
209     return new Dimension(Math.min(maxwidth, idWidth), 12);
210   }
211
212   /**
213    * DOCUMENT ME!
214    *
215    * @param results DOCUMENT ME!
216    */
217   public void highlightSearchResults(SearchResults results)
218   {
219     seqPanel.seqCanvas.highlightSearchResults(results);
220
221     // do we need to scroll the panel?
222     if (results != null)
223     {
224       SequenceI seq = results.getResultSequence(0);
225       int seqIndex = av.alignment.findIndex(seq);
226       int start = seq.findIndex(results.getResultStart(0)) - 1;
227       int end = seq.findIndex(results.getResultEnd(0)) - 1;
228
229       if (!av.wrapAlignment)
230       {
231         if ( (av.getStartRes() > end) || (av.getEndRes() < start) ||
232             ( (av.getStartSeq() > seqIndex) || (av.getEndSeq() < seqIndex)))
233         {
234           setScrollValues(start, seqIndex);
235         }
236       }
237       else
238       {
239         scrollToWrappedVisible(start);
240       }
241     }
242
243     paintAlignment(true);
244   }
245
246   void scrollToWrappedVisible(int res)
247   {
248     int cwidth = seqPanel.seqCanvas.getWrappedCanvasWidth(seqPanel.seqCanvas.
249         getWidth());
250     if (res <= av.getStartRes() || res >= (av.getStartRes() + cwidth))
251     {
252       vscroll.setValue(res / cwidth);
253       av.startRes = vscroll.getValue() * cwidth;
254     }
255   }
256
257   /**
258    * DOCUMENT ME!
259    *
260    * @return DOCUMENT ME!
261    */
262   public OverviewPanel getOverviewPanel()
263   {
264     return overviewPanel;
265   }
266
267   /**
268    * DOCUMENT ME!
269    *
270    * @param op DOCUMENT ME!
271    */
272   public void setOverviewPanel(OverviewPanel op)
273   {
274     overviewPanel = op;
275   }
276
277   /**
278    * DOCUMENT ME!
279    *
280    * @param b DOCUMENT ME!
281    */
282   public void setAnnotationVisible(boolean b)
283   {
284     if (!av.wrapAlignment)
285     {
286       annotationSpaceFillerHolder.setVisible(b);
287       annotationScroller.setVisible(b);
288     }
289     repaint();
290   }
291
292   public void adjustAnnotationHeight()
293   {
294     //TODO: display vertical annotation scrollbar if necessary 
295     // this is called after loading new annotation onto alignment
296     if (alignFrame.getHeight() == 0)
297     {
298       System.out.println("NEEDS FIXING");
299     }
300
301     int height = annotationPanel.adjustPanelHeight();
302
303     if (hscroll.isVisible())
304     {
305       height += hscroll.getPreferredSize().height;
306     }
307     if (height > alignFrame.getHeight() / 2)
308     {
309       height = alignFrame.getHeight() / 2;
310     }
311
312     hscroll.addNotify();
313
314     annotationScroller.setPreferredSize(
315         new Dimension(annotationScroller.getWidth(), height));
316
317
318     annotationSpaceFillerHolder.setPreferredSize(new Dimension(
319         annotationSpaceFillerHolder.getWidth(),
320         height));
321     annotationScroller.validate();// repaint();
322     repaint();
323   }
324
325   /**
326    * DOCUMENT ME!
327    *
328    * @param wrap DOCUMENT ME!
329    */
330   public void setWrapAlignment(boolean wrap)
331   {
332     av.startSeq = 0;
333     scalePanelHolder.setVisible(!wrap);
334     hscroll.setVisible(!wrap);
335     idwidthAdjuster.setVisible(!wrap);
336
337     if (wrap)
338     {
339       annotationScroller.setVisible(false);
340       annotationSpaceFillerHolder.setVisible(false);
341     }
342     else if (av.showAnnotation)
343     {
344       annotationScroller.setVisible(true);
345       annotationSpaceFillerHolder.setVisible(true);
346     }
347
348     idSpaceFillerPanel1.setVisible(!wrap);
349
350     repaint();
351   }
352
353   // return value is true if the scroll is valid
354   public boolean scrollUp(boolean up)
355   {
356     if (up)
357     {
358       if (vscroll.getValue() < 1)
359       {
360         return false;
361       }
362
363       fastPaint = false;
364       vscroll.setValue(vscroll.getValue() - 1);
365     }
366     else
367     {
368       if ( (vextent + vscroll.getValue()) >= av.getAlignment().getHeight())
369       {
370         return false;
371       }
372
373       fastPaint = false;
374       vscroll.setValue(vscroll.getValue() + 1);
375     }
376
377     fastPaint = true;
378
379     return true;
380   }
381
382   /**
383    * DOCUMENT ME!
384    *
385    * @param right DOCUMENT ME!
386    *
387    * @return DOCUMENT ME!
388    */
389   public boolean scrollRight(boolean right)
390   {
391     if (!right)
392     {
393       if (hscroll.getValue() < 1)
394       {
395         return false;
396       }
397
398       fastPaint = false;
399       hscroll.setValue(hscroll.getValue() - 1);
400     }
401     else
402     {
403       if ( (hextent + hscroll.getValue()) >= av.getAlignment().getWidth())
404       {
405         return false;
406       }
407
408       fastPaint = false;
409       hscroll.setValue(hscroll.getValue() + 1);
410     }
411
412     fastPaint = true;
413
414     return true;
415   }
416
417   /**
418    * DOCUMENT ME!
419    *
420    * @param x DOCUMENT ME!
421    * @param y DOCUMENT ME!
422    */
423   public void setScrollValues(int x, int y)
424   {
425
426     int width = av.alignment.getWidth();
427     int height = av.alignment.getHeight();
428
429     if (av.hasHiddenColumns)
430     {
431       width = av.getColumnSelection().findColumnPosition(width);
432     }
433
434     av.setEndRes( (x + (seqPanel.seqCanvas.getWidth() / av.charWidth)) - 1);
435
436     hextent = seqPanel.seqCanvas.getWidth() / av.charWidth;
437     vextent = seqPanel.seqCanvas.getHeight() / av.charHeight;
438
439     if (hextent > width)
440     {
441       hextent = width;
442     }
443
444     if (vextent > height)
445     {
446       vextent = height;
447     }
448
449     if ( (hextent + x) > width)
450     {
451       x = width - hextent;
452     }
453
454     if ( (vextent + y) > height)
455     {
456       y = height - vextent;
457     }
458
459     if (y < 0)
460     {
461       y = 0;
462     }
463
464     if (x < 0)
465     {
466       x = 0;
467     }
468
469     hscroll.setValues(x, hextent, 0, width);
470     vscroll.setValues(y, vextent, 0, height);
471   }
472
473   /**
474    * DOCUMENT ME!
475    *
476    * @param evt DOCUMENT ME!
477    */
478   public void adjustmentValueChanged(AdjustmentEvent evt)
479   {
480
481     int oldX = av.getStartRes();
482     int oldY = av.getStartSeq();
483
484     if (evt.getSource() == hscroll)
485     {
486       int x = hscroll.getValue();
487       av.setStartRes(x);
488       av.setEndRes( (x +
489                      (seqPanel.seqCanvas.getWidth() / av.getCharWidth())) - 1);
490     }
491
492     if (evt.getSource() == vscroll)
493     {
494       int offy = vscroll.getValue();
495
496       if (av.getWrapAlignment())
497       {
498         if (offy > -1)
499         {
500           int rowSize = seqPanel.seqCanvas.getWrappedCanvasWidth(seqPanel.
501               seqCanvas.getWidth());
502           av.setStartRes(offy * rowSize);
503           av.setEndRes( (offy + 1) * rowSize);
504         }
505         else
506         {
507           //This is only called if file loaded is a jar file that
508           //was wrapped when saved and user has wrap alignment true
509           //as preference setting
510           SwingUtilities.invokeLater(new Runnable()
511           {
512             public void run()
513             {
514               setScrollValues(av.getStartRes(), av.getStartSeq());
515             }
516           });
517         }
518       }
519       else
520       {
521         av.setStartSeq(offy);
522         av.setEndSeq(offy +
523                      (seqPanel.seqCanvas.getHeight() / av.getCharHeight()));
524       }
525     }
526
527     if (overviewPanel != null)
528     {
529       overviewPanel.setBoxPosition();
530     }
531
532     int scrollX = av.startRes - oldX;
533     int scrollY = av.startSeq - oldY;
534
535     if (av.getWrapAlignment() || !fastPaint)
536     {
537       repaint();
538     }
539     else
540     {
541       // Make sure we're not trying to draw a panel
542       // larger than the visible window
543       if (scrollX > av.endRes - av.startRes)
544       {
545         scrollX = av.endRes - av.startRes;
546       }
547       else if (scrollX < av.startRes - av.endRes)
548       {
549         scrollX = av.startRes - av.endRes;
550       }
551
552       if (scrollX != 0 || scrollY != 0)
553       {
554         idPanel.idCanvas.fastPaint(scrollY);
555         seqPanel.seqCanvas.fastPaint(scrollX,
556                                      scrollY);
557         scalePanel.repaint();
558
559         if (av.getShowAnnotation())
560         {
561           annotationPanel.fastPaint(scrollX);
562         }
563       }
564     }
565   }
566
567   public void paintAlignment(boolean updateOverview)
568   {
569     repaint();
570
571     if(updateOverview)
572     {
573       jalview.structure.StructureSelectionManager.getStructureSelectionManager()
574           .sequenceColoursChanged(this);
575
576       if (overviewPanel != null)
577       {
578         overviewPanel.updateOverviewImage();
579       }
580     }
581   }
582
583   /**
584    * DOCUMENT ME!
585    *
586    * @param g DOCUMENT ME!
587    */
588   public void paintComponent(Graphics g)
589   {
590     invalidate();
591
592     Dimension d = idPanel.idCanvas.getPreferredSize();
593     idPanelHolder.setPreferredSize(d);
594     hscrollFillerPanel.setPreferredSize(new Dimension(d.width, 12));
595     validate();
596
597     if (av.getWrapAlignment())
598     {
599       int maxwidth = av.alignment.getWidth();
600
601       if (av.hasHiddenColumns)
602       {
603         maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
604       }
605
606       int canvasWidth = seqPanel.seqCanvas.getWrappedCanvasWidth(seqPanel.
607           seqCanvas.getWidth());
608       if (canvasWidth > 0)
609       {
610         int max = maxwidth /
611             seqPanel.seqCanvas.getWrappedCanvasWidth(seqPanel.seqCanvas.
612             getWidth()) +
613             1;
614         vscroll.setMaximum(max);
615         vscroll.setUnitIncrement(1);
616         vscroll.setVisibleAmount(1);
617       }
618     }
619     else
620     {
621       setScrollValues(av.getStartRes(), av.getStartSeq());
622     }
623   }
624
625   /**
626    * DOCUMENT ME!
627    *
628    * @param pg DOCUMENT ME!
629    * @param pf DOCUMENT ME!
630    * @param pi DOCUMENT ME!
631    *
632    * @return DOCUMENT ME!
633    *
634    * @throws PrinterException DOCUMENT ME!
635    */
636   public int print(Graphics pg, PageFormat pf, int pi)
637       throws PrinterException
638   {
639     pg.translate( (int) pf.getImageableX(), (int) pf.getImageableY());
640
641     int pwidth = (int) pf.getImageableWidth();
642     int pheight = (int) pf.getImageableHeight();
643
644     if (av.getWrapAlignment())
645     {
646       return printWrappedAlignment(pg, pwidth, pheight, pi);
647     }
648     else
649     {
650       return printUnwrapped(pg, pwidth, pheight, pi);
651     }
652   }
653
654   /**
655    * DOCUMENT ME!
656    *
657    * @param pg DOCUMENT ME!
658    * @param pwidth DOCUMENT ME!
659    * @param pheight DOCUMENT ME!
660    * @param pi DOCUMENT ME!
661    *
662    * @return DOCUMENT ME!
663    *
664    * @throws PrinterException DOCUMENT ME!
665    */
666   public int printUnwrapped(Graphics pg, int pwidth, int pheight, int pi)
667       throws PrinterException
668   {
669     int idWidth = getVisibleIdWidth();
670     FontMetrics fm = getFontMetrics(av.getFont());
671     int scaleHeight = av.charHeight + fm.getDescent();
672
673     pg.setColor(Color.white);
674     pg.fillRect(0, 0, pwidth, pheight);
675     pg.setFont(av.getFont());
676
677     ////////////////////////////////////
678     /// How many sequences and residues can we fit on a printable page?
679     int totalRes = (pwidth - idWidth) / av.getCharWidth();
680
681     int totalSeq = (int) ( (pheight - scaleHeight) / av.getCharHeight()) -
682         1;
683
684     int pagesWide = (av.getAlignment().getWidth() / totalRes) + 1;
685
686     /////////////////////////////
687     /// Only print these sequences and residues on this page
688     int startRes;
689
690     /////////////////////////////
691     /// Only print these sequences and residues on this page
692     int endRes;
693
694     /////////////////////////////
695     /// Only print these sequences and residues on this page
696     int startSeq;
697
698     /////////////////////////////
699     /// Only print these sequences and residues on this page
700     int endSeq;
701     startRes = (pi % pagesWide) * totalRes;
702     endRes = (startRes + totalRes) - 1;
703
704     if (endRes > (av.getAlignment().getWidth() - 1))
705     {
706       endRes = av.getAlignment().getWidth() - 1;
707     }
708
709     startSeq = (pi / pagesWide) * totalSeq;
710     endSeq = startSeq + totalSeq;
711
712     if (endSeq > av.getAlignment().getHeight())
713     {
714       endSeq = av.getAlignment().getHeight();
715     }
716
717     int pagesHigh = ( (av.alignment.getHeight() / totalSeq) + 1) * pheight;
718
719     if (av.showAnnotation)
720     {
721       pagesHigh += annotationPanel.adjustPanelHeight() + 3;
722     }
723
724     pagesHigh /= pheight;
725
726     if (pi >= (pagesWide * pagesHigh))
727     {
728       return Printable.NO_SUCH_PAGE;
729     }
730
731     //draw Scale
732     pg.translate(idWidth, 0);
733     scalePanel.drawScale(pg, startRes, endRes, pwidth - idWidth, scaleHeight);
734     pg.translate( -idWidth, scaleHeight);
735
736     ////////////////
737     // Draw the ids
738     Color currentColor = null;
739     Color currentTextColor = null;
740
741     pg.setFont(idPanel.idCanvas.idfont);
742
743     SequenceI seq;
744     for (int i = startSeq; i < endSeq; i++)
745     {
746       seq = av.getAlignment().getSequenceAt(i);
747       if ( (av.getSelectionGroup() != null) &&
748           av.getSelectionGroup().getSequences(null).contains(seq))
749       {
750         currentColor = Color.gray;
751         currentTextColor = Color.black;
752       }
753       else
754       {
755         currentColor = av.getSequenceColour(seq);
756         currentTextColor = Color.black;
757       }
758
759       pg.setColor(currentColor);
760       pg.fillRect(0, (i - startSeq) * av.charHeight, idWidth,
761                   av.getCharHeight());
762
763       pg.setColor(currentTextColor);
764
765       int xPos = 0;
766       if (av.rightAlignIds)
767       {
768         fm = pg.getFontMetrics();
769         xPos = idWidth - fm.stringWidth(
770             seq.getDisplayId(av.getShowJVSuffix())
771             ) - 4;
772       }
773
774       pg.drawString(seq.getDisplayId(av.getShowJVSuffix()),
775                     xPos,
776                     ( ( (i - startSeq) * av.charHeight) + av.getCharHeight()) -
777                     (av.getCharHeight() / 5));
778     }
779
780     pg.setFont(av.getFont());
781
782     // draw main sequence panel
783     pg.translate(idWidth, 0);
784     seqPanel.seqCanvas.drawPanel(pg, startRes, endRes, startSeq, endSeq, 0);
785
786     if (av.showAnnotation && (endSeq == av.alignment.getHeight()))
787     {
788       pg.translate( -idWidth - 3, (endSeq - startSeq) * av.charHeight + 3);
789       alabels.drawComponent( (Graphics2D) pg, idWidth);
790       pg.translate(idWidth + 3, 0);
791       annotationPanel.drawComponent( (Graphics2D) pg, startRes, endRes +
792                                     1);
793     }
794
795     return Printable.PAGE_EXISTS;
796   }
797
798   /**
799    * DOCUMENT ME!
800    *
801    * @param pg DOCUMENT ME!
802    * @param pwidth DOCUMENT ME!
803    * @param pheight DOCUMENT ME!
804    * @param pi DOCUMENT ME!
805    *
806    * @return DOCUMENT ME!
807    *
808    * @throws PrinterException DOCUMENT ME!
809    */
810   public int printWrappedAlignment(Graphics pg, int pwidth, int pheight,
811                                    int pi)
812       throws PrinterException
813   {
814
815     int annotationHeight = 0;
816     AnnotationLabels labels = null;
817     if (av.showAnnotation)
818     {
819       annotationHeight = annotationPanel.adjustPanelHeight();
820       labels = new AnnotationLabels(av);
821     }
822
823     int hgap = av.charHeight;
824     if (av.scaleAboveWrapped)
825     {
826       hgap += av.charHeight;
827     }
828
829     int cHeight = av.getAlignment().getHeight() * av.charHeight
830         + hgap
831         + annotationHeight;
832
833     int idWidth = getVisibleIdWidth();
834
835     int maxwidth = av.alignment.getWidth();
836     if (av.hasHiddenColumns)
837     {
838       maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
839     }
840
841     int resWidth = seqPanel.seqCanvas.getWrappedCanvasWidth(pwidth -
842         idWidth);
843
844     int totalHeight = cHeight * (maxwidth / resWidth + 1);
845
846     pg.setColor(Color.white);
847     pg.fillRect(0, 0, pwidth, pheight);
848     pg.setFont(av.getFont());
849
850     ////////////////
851     // Draw the ids
852     pg.setColor(Color.black);
853
854     pg.translate(0, -pi * pheight);
855
856     pg.setClip(0, pi * pheight, pwidth, pheight);
857
858     int ypos = hgap;
859
860     do
861     {
862       for (int i = 0; i < av.alignment.getHeight(); i++)
863       {
864         pg.setFont(idPanel.idCanvas.idfont);
865         SequenceI s = av.alignment.getSequenceAt(i);
866         String string = s.getDisplayId(av.getShowJVSuffix());
867         int xPos = 0;
868         if (av.rightAlignIds)
869         {
870           FontMetrics fm = pg.getFontMetrics();
871           xPos = idWidth - fm.stringWidth(string) - 4;
872         }
873         pg.drawString(string, xPos,
874                       ( (i * av.charHeight) + ypos + av.charHeight) -
875                       (av.charHeight / 5));
876       }
877       if (labels != null)
878       {
879         pg.translate( -3,
880                      ypos +
881                      (av.getAlignment().getHeight() * av.charHeight));
882
883         pg.setFont(av.getFont());
884         labels.drawComponent(pg, idWidth);
885         pg.translate( +3,
886                      -ypos -
887                      (av.getAlignment().getHeight() * av.charHeight));
888       }
889
890       ypos += cHeight;
891     }
892     while (ypos < totalHeight);
893
894     pg.translate(idWidth, 0);
895
896     seqPanel.seqCanvas.drawWrappedPanel(pg, pwidth - idWidth, totalHeight, 0);
897
898     if ( (pi * pheight) < totalHeight)
899     {
900       return Printable.PAGE_EXISTS;
901
902     }
903     else
904     {
905       return Printable.NO_SUCH_PAGE;
906     }
907   }
908
909   int getVisibleIdWidth()
910   {
911     return
912         idPanel.getWidth() > 0 ? idPanel.getWidth() :
913         calculateIdWidth().width + 4;
914   }
915
916   void makeAlignmentImage(int type, File file)
917   {
918     int maxwidth = av.alignment.getWidth();
919     if (av.hasHiddenColumns)
920     {
921       maxwidth = av.getColumnSelection().findColumnPosition(maxwidth);
922     }
923
924     int height = ( (av.alignment.getHeight() + 1) * av.charHeight)
925         + scalePanel.getHeight();
926     int width = getVisibleIdWidth() + (maxwidth * av.charWidth);
927
928     if (av.getWrapAlignment())
929     {
930       height = getWrappedHeight();
931       if (System.getProperty("java.awt.headless") != null
932           && System.getProperty("java.awt.headless").equals("true"))
933       {
934         width = alignFrame.getWidth()
935             - vscroll.getPreferredSize().width
936             - alignFrame.getInsets().left
937             - alignFrame.getInsets().right;
938       }
939       else
940       {
941         width = seqPanel.getWidth() + getVisibleIdWidth();
942       }
943
944     }
945     else if (av.getShowAnnotation())
946     {
947       height += annotationPanel.adjustPanelHeight() + 3;
948     }
949
950     try
951     {
952
953       jalview.util.ImageMaker im;
954       if (type == jalview.util.ImageMaker.PNG)
955       {
956         im = new jalview.util.ImageMaker(this,
957                                          jalview.util.ImageMaker.PNG,
958                                          "Create PNG image from alignment",
959                                          width, height, file, null);
960       }
961       else
962       {
963         im = new jalview.util.ImageMaker(this,
964                                          jalview.util.ImageMaker.EPS,
965                                          "Create EPS file from alignment",
966                                          width, height, file,
967                                          alignFrame.getTitle());
968       }
969
970       if (av.getWrapAlignment())
971       {
972         if (im.getGraphics() != null)
973         {
974           printWrappedAlignment(im.getGraphics(), width, height, 0);
975           im.writeImage();
976         }
977       }
978       else
979       {
980         if (im.getGraphics() != null)
981         {
982           printUnwrapped(im.getGraphics(), width, height, 0);
983           im.writeImage();
984         }
985       }
986     }
987     catch (OutOfMemoryError err)
988     {
989       // Be noisy here.
990       System.out.println("########################\n"
991                          + "OUT OF MEMORY " + file + "\n"
992                          + "########################");
993       new OOMWarning("Creating Image for "+file,err);
994       // System.out.println("Create IMAGE: " + err);
995     }
996     catch (Exception ex)
997     {
998       ex.printStackTrace();
999     }
1000   }
1001
1002   /**
1003    * DOCUMENT ME!
1004    */
1005   public void makeEPS(File epsFile)
1006   {
1007     makeAlignmentImage(jalview.util.ImageMaker.EPS, epsFile);
1008   }
1009
1010   /**
1011    * DOCUMENT ME!
1012    */
1013   public void makePNG(File pngFile)
1014   {
1015     makeAlignmentImage(jalview.util.ImageMaker.PNG, pngFile);
1016   }
1017
1018   public void makePNGImageMap(File imgMapFile, String imageName)
1019   {
1020     ///////ONLY WORKS WITH NONE WRAPPED ALIGNMENTS
1021     //////////////////////////////////////////////
1022     int idWidth = getVisibleIdWidth();
1023     FontMetrics fm = getFontMetrics(av.getFont());
1024     int scaleHeight = av.charHeight + fm.getDescent();
1025
1026     // Gen image map
1027     //////////////////////////////////
1028     if (imgMapFile != null)
1029     {
1030       try
1031       {
1032         int s, sSize = av.alignment.getHeight(),
1033             res, alwidth = av.alignment.getWidth(), g, gSize, f, fSize, sy;
1034         StringBuffer text = new StringBuffer();
1035         PrintWriter out = new PrintWriter(new FileWriter(imgMapFile));
1036         out.println(jalview.io.HTMLOutput.getImageMapHTML());
1037         out.println("<img src=\"" + imageName +
1038                     "\" border=\"0\" usemap=\"#Map\" >"
1039                     + "<map name=\"Map\">");
1040
1041         for (s = 0; s < sSize; s++)
1042         {
1043           sy = s * av.charHeight + scaleHeight;
1044
1045           SequenceI seq = av.alignment.getSequenceAt(s);
1046           SequenceFeature[] features = seq.getDatasetSequence().
1047               getSequenceFeatures();
1048           SequenceGroup[] groups = av.alignment.findAllGroups(seq);
1049           for (res = 0; res < alwidth; res++)
1050           {
1051             text = new StringBuffer();
1052             Object obj = null;
1053             if (av.alignment.isNucleotide())
1054             {
1055               obj = ResidueProperties.nucleotideName.get(seq.getCharAt(res) +
1056                   "");
1057             }
1058             else
1059             {
1060               obj = ResidueProperties.aa2Triplet.get(
1061                   seq.getCharAt(res) + "");
1062             }
1063
1064             if (obj == null)
1065             {
1066               continue;
1067             }
1068
1069             String triplet = obj.toString();
1070             int alIndex = seq.findPosition(res);
1071             gSize = groups.length;
1072             for (g = 0; g < gSize; g++)
1073             {
1074               if (text.length() < 1)
1075               {
1076                 text.append("<area shape=\"rect\" coords=\""
1077                             + (idWidth + res * av.charWidth) + ","
1078                             + sy + ","
1079                             + (idWidth + (res + 1) * av.charWidth) + ","
1080                             + (av.charHeight + sy) + "\""
1081                             + " onMouseOver=\"toolTip('"
1082                             + alIndex + " " + triplet);
1083               }
1084
1085               if (groups[g].getStartRes() < res && groups[g].getEndRes() > res)
1086               {
1087                 text.append("<br><em>" + groups[g].getName() + "</em>");
1088               }
1089             }
1090
1091             if (features != null)
1092             {
1093               if (text.length() < 1)
1094               {
1095                 text.append("<area shape=\"rect\" coords=\""
1096                             + (idWidth + res * av.charWidth) + ","
1097                             + sy + ","
1098                             + (idWidth + (res + 1) * av.charWidth) + ","
1099                             + (av.charHeight + sy) + "\""
1100                             + " onMouseOver=\"toolTip('"
1101                             + alIndex + " " + triplet);
1102               }
1103               fSize = features.length;
1104               for (f = 0; f < fSize; f++)
1105               {
1106
1107                 if ( (features[f].getBegin() <= seq.findPosition(res)) &&
1108                     (features[f].getEnd() >= seq.findPosition(res)))
1109                 {
1110                   if (features[f].getType().equals("disulfide bond"))
1111                   {
1112                     if (features[f].getBegin() == seq.findPosition(res)
1113                         || features[f].getEnd() == seq.findPosition(res))
1114                     {
1115                       text.append("<br>disulfide bond " + features[f].getBegin() +
1116                                   ":" +
1117                                   features[f].getEnd());
1118                     }
1119                   }
1120                   else
1121                   {
1122                     text.append("<br>");
1123                     text.append(features[f].getType());
1124                     if (features[f].getDescription() != null &&
1125                         !features[f].
1126                         getType().equals(features[f].getDescription()))
1127                     {
1128                       text.append(" " + features[f].getDescription());
1129                     }
1130
1131                     if (features[f].getValue("status") != null)
1132                     {
1133                       text.append(" (" + features[f].getValue("status") + ")");
1134                     }
1135                   }
1136                 }
1137
1138               }
1139             }
1140             if (text.length() > 1)
1141             {
1142               text.append("')\"; onMouseOut=\"toolTip()\";  href=\"#\">");
1143               out.println(text.toString());
1144             }
1145           }
1146         }
1147         out.println("</map></body></html>");
1148         out.close();
1149
1150       }
1151       catch (Exception ex)
1152       {
1153         ex.printStackTrace();
1154       }
1155     } ///////////END OF IMAGE MAP
1156
1157   }
1158
1159   int getWrappedHeight()
1160   {
1161     int seqPanelWidth = seqPanel.seqCanvas.getWidth();
1162
1163     if (System.getProperty("java.awt.headless") != null
1164         && System.getProperty("java.awt.headless").equals("true"))
1165     {
1166       seqPanelWidth = alignFrame.getWidth()
1167           - getVisibleIdWidth()
1168           - vscroll.getPreferredSize().width
1169           - alignFrame.getInsets().left
1170           - alignFrame.getInsets().right;
1171     }
1172
1173     int chunkWidth = seqPanel.seqCanvas.getWrappedCanvasWidth(
1174         seqPanelWidth
1175         );
1176
1177     int hgap = av.charHeight;
1178     if (av.scaleAboveWrapped)
1179     {
1180       hgap += av.charHeight;
1181     }
1182
1183     int annotationHeight = 0;
1184     if (av.showAnnotation)
1185     {
1186       annotationHeight = annotationPanel.adjustPanelHeight();
1187     }
1188
1189     int cHeight = av.getAlignment().getHeight() * av.charHeight
1190         + hgap
1191         + annotationHeight;
1192
1193     int maxwidth = av.alignment.getWidth();
1194     if (av.hasHiddenColumns)
1195     {
1196       maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1;
1197     }
1198
1199     int height = ( (maxwidth / chunkWidth) + 1) * cHeight;
1200
1201     return height;
1202   }
1203 }