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