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