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