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