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