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