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