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