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