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