add fastPaint boolean
[jalview.git] / src / jalview / gui / AlignmentPanel.java
1 package jalview.gui;\r
2 \r
3 import jalview.jbgui.GAlignmentPanel;\r
4 import jalview.schemes.*;\r
5 import jalview.analysis.*;\r
6 import jalview.datamodel.*;\r
7 import java.awt.*;\r
8 import java.awt.event.*;\r
9 import java.awt.print.*;\r
10 import java.io.*;\r
11 import java.awt.image.*;\r
12 import org.jibble.epsgraphics.*;\r
13 import javax.imageio.*;\r
14 \r
15 \r
16 \r
17 public class AlignmentPanel extends GAlignmentPanel implements AdjustmentListener, Printable\r
18 {\r
19 \r
20   AlignViewport     av;\r
21   OverviewPanel overviewPanel;\r
22   SeqPanel   seqPanel;\r
23   IdPanel    idPanel;\r
24   IdwidthAdjuster idwidthAdjuster;\r
25   public AlignFrame alignFrame;\r
26   ScalePanel scalePanel;\r
27   AnnotationPanel annotationPanel;\r
28   AnnotationLabels alabels;\r
29 \r
30   // this value is set false when selection area being dragged\r
31   boolean fastPaint = true;\r
32 \r
33   public AlignmentPanel(AlignFrame af, final AlignViewport av)\r
34   {\r
35     alignFrame = af;\r
36     this.av         = av;\r
37     seqPanel        = new SeqPanel  (av, this);\r
38     idPanel         = new IdPanel   (av, this);\r
39 \r
40     scalePanel = new ScalePanel(av, this);\r
41 \r
42     idPanelHolder.add(idPanel, BorderLayout.CENTER);\r
43     idwidthAdjuster = new IdwidthAdjuster(this);\r
44     idSpaceFillerPanel1.add(idwidthAdjuster, BorderLayout.CENTER);\r
45 \r
46     annotationPanel = new AnnotationPanel(this);\r
47     alabels = new AnnotationLabels(this);\r
48 \r
49     annotationSpaceFillerHolder.setPreferredSize(annotationPanel.getPreferredSize());\r
50     annotationScroller.setPreferredSize(annotationPanel.getPreferredSize());\r
51     annotationScroller.setViewportView(annotationPanel);\r
52     annotationSpaceFillerHolder.add(alabels, BorderLayout.CENTER);\r
53 \r
54     Dimension d = calculateIdWidth();\r
55     d.setSize( d.width+4, d.height);\r
56     idPanel.idCanvas.setPreferredSize( d );\r
57     hscrollFillerPanel.setPreferredSize( d );\r
58 \r
59     scalePanelHolder.add(scalePanel, BorderLayout.CENTER);\r
60     seqPanelHolder.add(seqPanel, BorderLayout.CENTER);\r
61 \r
62 \r
63     if(seqPanel.seqCanvas.getWidth()==0)\r
64     javax.swing.SwingUtilities.invokeLater(new Runnable()\r
65      {\r
66        public void run()\r
67        {\r
68          setScrollValues(0,0);\r
69          Dimension d = calculateIdWidth();\r
70          d.setSize( d.width+4, d.height);\r
71          idPanel.idCanvas.setPreferredSize( d );\r
72          RefreshPanels();\r
73        }\r
74     });\r
75 \r
76 \r
77     hscroll.addAdjustmentListener(this);\r
78     vscroll.addAdjustmentListener(this);\r
79 \r
80     addComponentListener(new ComponentAdapter()\r
81    {\r
82      public void componentResized(ComponentEvent evt)\r
83      {\r
84           RefreshPanels();\r
85      }\r
86    });\r
87 \r
88    setFocusable(true);\r
89    addKeyListener(new KeyAdapter()\r
90    {\r
91      public void keyPressed(KeyEvent evt)\r
92      {\r
93        switch(evt.getKeyCode())\r
94        {\r
95          case  27: // escape key\r
96            av.setSelectionGroup(null);\r
97            RefreshPanels();\r
98            break;\r
99          case KeyEvent.VK_X:\r
100            if(evt.isControlDown())\r
101            alignFrame.cut_actionPerformed(null);\r
102            break;\r
103          case KeyEvent.VK_C:\r
104          if(evt.isControlDown())\r
105            alignFrame.copy_actionPerformed(null);\r
106            break;\r
107          case KeyEvent.VK_V:\r
108           if(evt.isControlDown())\r
109            alignFrame.paste(true);\r
110            break;\r
111          case KeyEvent.VK_A:\r
112          if(evt.isControlDown())\r
113            alignFrame.selectAllSequenceMenuItem_actionPerformed(null);\r
114            break;\r
115         case KeyEvent.VK_DOWN:\r
116           alignFrame.moveSelectedSequences(false);\r
117           break;\r
118         case KeyEvent.VK_UP:\r
119           alignFrame.moveSelectedSequences(true);\r
120           break;\r
121         case KeyEvent.VK_F:\r
122          if(evt.isControlDown())\r
123           alignFrame.findMenuItem_actionPerformed(null);\r
124           break;\r
125        }\r
126      }\r
127    });\r
128   }\r
129 \r
130   Dimension calculateIdWidth()\r
131   {\r
132     Graphics g = this.getGraphics();\r
133     if(g==null)\r
134     {\r
135       javax.swing.JFrame f = new javax.swing.JFrame();\r
136       f.addNotify();\r
137       g = f.getGraphics();\r
138     }\r
139 \r
140     FontMetrics fm = g.getFontMetrics(av.font);\r
141     AlignmentI al = av.getAlignment();\r
142 \r
143        int i   = 0;\r
144        int idWidth = 0;\r
145        String id;\r
146        while (i < al.getHeight() && al.getSequenceAt(i) != null)\r
147        {\r
148          SequenceI s   = al.getSequenceAt(i);\r
149          if(av.getShowFullId())\r
150            id   = s.getDisplayId();\r
151          else\r
152            id = s.getName();\r
153 \r
154          if (fm.stringWidth(id) > idWidth)\r
155            idWidth = fm.stringWidth(id);\r
156          i++;\r
157        }\r
158 \r
159        return new Dimension(idWidth, 12);\r
160   }\r
161 \r
162 \r
163  public void highlightSearchResults(int [] results)\r
164  {\r
165    seqPanel.seqCanvas.highlightSearchResults( results );\r
166 \r
167    // do we need to scroll the panel?\r
168    if(results!=null && (av.getStartSeq()>results[0]\r
169                         || av.getEndSeq()<results[0]\r
170                         || av.getStartRes()>results[1]\r
171                         || av.getEndRes()<results[2]))\r
172        setScrollValues(results[1], results[0]);\r
173 \r
174 \r
175  }\r
176 \r
177 \r
178  public OverviewPanel getOverviewPanel()\r
179  {\r
180    return overviewPanel;\r
181  }\r
182 \r
183  public void setOverviewPanel(OverviewPanel op)\r
184  {\r
185    overviewPanel = op;\r
186  }\r
187 \r
188 \r
189   public void setAnnotationVisible(boolean b)\r
190   {\r
191     annotationSpaceFillerHolder.setVisible(b);\r
192     annotationScroller.setVisible(b);\r
193     javax.swing.SwingUtilities.invokeLater(new Runnable()\r
194      {\r
195        public void run()\r
196        {\r
197          RefreshPanels();\r
198        }\r
199     });\r
200 \r
201   }\r
202 \r
203 \r
204   public void setWrapAlignment(boolean wrap)\r
205   {\r
206     scalePanelHolder.setVisible(!wrap);\r
207     hscroll.setVisible(!wrap);\r
208     idwidthAdjuster.setVisible(!wrap);\r
209 \r
210     av.setShowAnnotation(!wrap);\r
211     annotationScroller.setVisible(!wrap);\r
212     annotationSpaceFillerHolder.setVisible(!wrap);\r
213     idSpaceFillerPanel1.setVisible(!wrap);\r
214 \r
215     RefreshPanels();\r
216 \r
217   }\r
218 \r
219 \r
220   public void setColourScheme()\r
221   {\r
222     ColourSchemeI cs = av.getGlobalColourScheme();\r
223 \r
224     if(av.getConservationSelected())\r
225     {\r
226 \r
227        Alignment al = (Alignment)av.getAlignment();\r
228        Conservation c = new Conservation("All",\r
229                             ResidueProperties.propHash, 3, al.getSequences(), 0,\r
230                             al.getWidth() );\r
231 \r
232        c.calculate();\r
233        c.verdict(false, 100);\r
234        ConservationColourScheme ccs = new ConservationColourScheme(c, cs);\r
235 \r
236        av.setGlobalColourScheme( ccs );\r
237 \r
238     }\r
239 \r
240     RefreshPanels();\r
241   }\r
242 \r
243 \r
244   public void RefreshPanels()\r
245   {\r
246     requestFocus();\r
247     invalidate();\r
248 \r
249     Dimension d = idPanel.idCanvas.getPreferredSize();\r
250     idPanelHolder.setPreferredSize(d);\r
251     hscrollFillerPanel.setPreferredSize(new Dimension(d.width, 12));\r
252 \r
253     if (av.getWrapAlignment())\r
254     {\r
255       int max = av.alignment.getWidth() /\r
256           (seqPanel.seqCanvas.getWidth() / av.charWidth) + 1;\r
257       vscroll.setValues(0, 1, 0, max);\r
258     }\r
259     else\r
260     {\r
261       if (overviewPanel != null)\r
262         overviewPanel.updateOverviewImage();\r
263       setScrollValues(av.getStartRes(), av.getStartSeq());\r
264     }\r
265 \r
266     validate();\r
267     repaint();\r
268   }\r
269 \r
270   int hextent = 0;\r
271   int vextent = 0;\r
272 \r
273   // return value is true if the scroll is valid\r
274   public boolean scrollUp(boolean up)\r
275   {\r
276     if(up)\r
277     {\r
278       if(vscroll.getValue()<1)\r
279         return false;\r
280       fastPaint  = false;\r
281       vscroll.setValue(vscroll.getValue() - 1);\r
282     }\r
283     else\r
284     {\r
285      if(vextent+vscroll.getValue() >= av.getAlignment().getHeight())\r
286        return false;\r
287       fastPaint  = false;\r
288       vscroll.setValue(vscroll.getValue() + 1);\r
289     }\r
290     fastPaint = true;\r
291     return true;\r
292   }\r
293 \r
294   public boolean scrollRight(boolean right)\r
295   {\r
296 \r
297     if (right)\r
298     {\r
299       if (hscroll.getValue() < 1)\r
300         return false;\r
301       fastPaint = false;\r
302       hscroll.setValue(hscroll.getValue() - 1);\r
303     }\r
304     else\r
305     {\r
306       if (hextent + hscroll.getValue() >= av.getAlignment().getWidth())\r
307         return false;\r
308       fastPaint = false;\r
309       hscroll.setValue(hscroll.getValue() + 1);\r
310     }\r
311     fastPaint = true;\r
312     return true;\r
313   }\r
314 \r
315 \r
316   public void setScrollValues(int x, int y)\r
317   {\r
318     hextent = seqPanel.seqCanvas.getWidth()/av.charWidth;\r
319     vextent = seqPanel.seqCanvas.getHeight()/av.charHeight;\r
320 \r
321     if(hextent > av.alignment.getWidth())\r
322       hextent = av.alignment.getWidth();\r
323     if(vextent > av.alignment.getHeight())\r
324       vextent = av.alignment.getHeight();\r
325 \r
326     if(hextent+x  >  av.getAlignment().getWidth())\r
327       x =  av.getAlignment().getWidth()- hextent;\r
328 \r
329     if(vextent+y > av.getAlignment().getHeight())\r
330       y = av.getAlignment().getHeight() - vextent;\r
331 \r
332     if(y<0)\r
333       y = 0;\r
334 \r
335     if(x<0)\r
336       x=0;\r
337 \r
338     hscroll.setValues(x,hextent,0,av.getAlignment().getWidth());\r
339     vscroll.setValues(y,vextent,0,av.getAlignment().getHeight() );\r
340 \r
341   }\r
342 \r
343 \r
344   public void adjustmentValueChanged(AdjustmentEvent evt)\r
345   {\r
346     int oldX = av.getStartRes();\r
347     int oldY = av.getStartSeq();\r
348 \r
349     if (evt.getSource() == hscroll)\r
350     {\r
351       int x = hscroll.getValue();\r
352       av.setStartRes(x);\r
353       av.setEndRes(x + seqPanel.seqCanvas.getWidth()/av.getCharWidth()-1);\r
354     }\r
355 \r
356     if (evt.getSource() == vscroll)\r
357     {\r
358       int offy = vscroll.getValue();\r
359       if (av.getWrapAlignment())\r
360       {\r
361         av.setStartRes( vscroll.getValue() * av.getChunkWidth());\r
362       }\r
363       else\r
364       {\r
365         av.setStartSeq(offy);\r
366         av.setEndSeq(offy + seqPanel.seqCanvas.getHeight() / av.getCharHeight());\r
367       }\r
368     }\r
369 \r
370 \r
371     if(overviewPanel!=null)\r
372       overviewPanel.setBoxPosition();\r
373 \r
374     if(av.getWrapAlignment() || !fastPaint)\r
375       repaint();\r
376     else\r
377     {\r
378       seqPanel.seqCanvas.fastPaint(av.getStartRes() - oldX,\r
379                                    av.getStartSeq() - oldY);\r
380       idPanel.idCanvas.fastPaint(av.getStartSeq() - oldY);\r
381       scalePanel.repaint();\r
382       if (av.getShowAnnotation())\r
383         annotationPanel.fastPaint(av.getStartRes() - oldX);\r
384     }\r
385 \r
386   }\r
387 \r
388   public int print(Graphics pg, PageFormat pf, int pi) throws PrinterException\r
389   {\r
390     pg.translate((int)pf.getImageableX(), (int)pf.getImageableY());\r
391 \r
392     int pwidth = (int) pf.getImageableWidth();\r
393     int pheight = (int) pf.getImageableHeight();\r
394 \r
395     if (av.getWrapAlignment())\r
396       return printWrappedAlignment(pg, pwidth,pheight, pi);\r
397     else\r
398       return printUnwrapped(pg,pwidth, pheight,pi);\r
399   }\r
400 \r
401   public int printUnwrapped(Graphics pg, int pwidth, int pheight, int pi) throws PrinterException\r
402   {\r
403 \r
404     int idWidth = calculateIdWidth().width + 4;\r
405 \r
406 \r
407     pg.setColor(Color.white);\r
408     pg.fillRect(0,0,pwidth, pheight);\r
409     pg.setFont( av.getFont() );\r
410 \r
411     ////////////////////////////////////\r
412     /// How many sequences and residues can we fit on a printable page?\r
413     int totalRes = (pwidth - idWidth)/av.getCharWidth();\r
414     int totalSeq = (int)((pheight - 30)/av.getCharHeight())-1;\r
415     int pagesWide = av.getAlignment().getWidth() / totalRes +1;\r
416     int pagesHigh = av.getAlignment().getHeight() / totalSeq +1;\r
417 \r
418     if (pi >= pagesWide*pagesHigh)\r
419      return Printable.NO_SUCH_PAGE;\r
420 \r
421     /////////////////////////////\r
422     /// Only print these sequences and residues on this page\r
423     int startRes, endRes, startSeq, endSeq;\r
424     startRes = (pi % pagesWide) * totalRes;\r
425     endRes = startRes + totalRes-1;\r
426     if(endRes>av.getAlignment().getWidth())\r
427       endRes = av.getAlignment().getWidth();\r
428 \r
429      startSeq = (pi / pagesWide) * totalSeq;\r
430      endSeq = startSeq + totalSeq;\r
431      if(endSeq > av.getAlignment().getHeight())\r
432        endSeq = av.getAlignment().getHeight();\r
433 \r
434 \r
435     ////////////////\r
436     //draw Scale\r
437     pg.translate(idWidth,0);\r
438     scalePanel.drawScale(pg, startRes, endRes, pwidth-idWidth);\r
439 \r
440     pg.translate(-idWidth, 30);\r
441     ////////////////\r
442     // Draw the ids\r
443     Color currentColor=null;\r
444     Color currentTextColor=null;\r
445     for(int i=startSeq; i<endSeq; i++)\r
446     {\r
447       if (av.getSelectionGroup()!=null && av.getSelectionGroup().sequences.contains(av.getAlignment().getSequenceAt(i)))\r
448       {\r
449         currentColor = Color.gray;\r
450         currentTextColor = Color.black;\r
451       }\r
452       else\r
453       {\r
454         currentColor = av.getAlignment().getSequenceAt(i).getColor();\r
455         currentTextColor = Color.black;\r
456       }\r
457 \r
458       pg.setColor(currentColor);\r
459       pg.fillRect(0,  jalview.analysis.AlignmentUtil.getPixelHeight(startSeq, i, av.getCharHeight()),\r
460                               idWidth,\r
461                               av.getCharHeight());\r
462 \r
463       pg.setColor(currentTextColor);\r
464 \r
465       String string = av.getAlignment().getSequenceAt(i).getName();\r
466       if(av.getShowFullId())\r
467         string = av.getAlignment().getSequenceAt(i).getDisplayId();\r
468 \r
469       pg.drawString(string, 0,  jalview.analysis.AlignmentUtil.getPixelHeight\r
470                     (startSeq, i, av.getCharHeight()) + av.getCharHeight() - (av.getCharHeight() / 5));\r
471     }\r
472 \r
473     // draw main sequence panel\r
474     pg.translate(idWidth,0);\r
475     seqPanel.seqCanvas.drawPanel(pg,startRes,endRes,startSeq,endSeq,startRes,startSeq,0);\r
476 \r
477 \r
478     if(av.getShowAnnotation())\r
479       {\r
480         pg.translate(-idWidth,(endSeq-startSeq)*av.charHeight);\r
481         alabels.drawComponent((Graphics2D)pg);\r
482         pg.translate(idWidth,0);\r
483         annotationPanel.drawComponent((Graphics2D) pg, startRes, endRes+1);\r
484       }\r
485 \r
486     return Printable.PAGE_EXISTS;\r
487   }\r
488 \r
489 \r
490   public int printWrappedAlignment(Graphics pg, int pwidth, int pheight, int pi) throws PrinterException\r
491   {\r
492 \r
493     int idWidth = calculateIdWidth().width+4;\r
494 \r
495     if( seqPanel.seqCanvas.getWidth() < pwidth-idWidth)\r
496       pwidth = seqPanel.seqCanvas.getWidth() + idWidth;\r
497 \r
498 \r
499     pg.setColor(Color.white);\r
500     pg.fillRect(0,0,pwidth, pheight);\r
501     pg.setFont( av.getFont() );\r
502 \r
503     ////////////////////////////////////\r
504     /// How many sequences and residues can we fit on a printable page?\r
505     AlignmentI da = av.alignment;\r
506     int endy   = da.getHeight();\r
507     int chunkHeight =  (da.getHeight() + 2)*av.charHeight;\r
508     int chunkWidth  =   (pwidth-idWidth)/av.charWidth;\r
509 \r
510     int noChunksOnPage = pheight / chunkHeight;\r
511     int totalChunks = da.getWidth() / chunkWidth;\r
512 \r
513     if ( pi*noChunksOnPage > totalChunks )\r
514      return Printable.NO_SUCH_PAGE;\r
515 \r
516     ////////////////\r
517     // Draw the ids\r
518     pg.setClip(0,0,pwidth, noChunksOnPage*chunkHeight);\r
519 \r
520     int row = pi*noChunksOnPage;\r
521     pg.setColor(Color.black);\r
522     for(int ypos=2*av.charHeight;\r
523         ypos <= pheight && row*chunkWidth<da.getWidth();\r
524         ypos += chunkHeight, row++ )\r
525     {\r
526       for (int i = 0; i < endy; i++)\r
527       {\r
528         SequenceI s = da.getSequenceAt(i);\r
529         String string = s.getName();\r
530         if (av.getShowFullId())\r
531           string = s.getDisplayId();\r
532 \r
533         pg.drawString(string, 0,\r
534                       AlignmentUtil.getPixelHeight(0, i, av.charHeight) + ypos +\r
535                       av.charHeight - (av.charHeight / 5));\r
536       }\r
537     }\r
538 \r
539     // draw main sequence panel\r
540     pg.translate(idWidth,0);\r
541     seqPanel.seqCanvas.drawWrappedPanel(pg, pwidth-idWidth, pheight, pi*noChunksOnPage*chunkWidth);\r
542 \r
543 \r
544     return Printable.PAGE_EXISTS;\r
545 \r
546   }\r
547 \r
548 \r
549   public void makeEPS()\r
550   {\r
551     int height = (av.alignment.getWidth() / av.getChunkWidth() +1) * av.chunkHeight;\r
552     int width = seqPanel.getWidth() + idPanel.getWidth();\r
553 \r
554     if (!av.getWrapAlignment())\r
555     {\r
556       height = (av.alignment.getHeight()+1) * av.charHeight + 30;\r
557       width = idPanel.getWidth() + av.alignment.getWidth() * av.charWidth;\r
558     }\r
559     if(av.getShowAnnotation())\r
560    {\r
561      height += annotationPanel.getPreferredSize().height;\r
562    }\r
563 \r
564     try\r
565     {\r
566       jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(jalview.bin.Cache.getProperty(\r
567           "LAST_DIRECTORY"), new String[]{"eps"}, "Encapsulated Postscript");\r
568       chooser.setFileView(new jalview.io.JalviewFileView());\r
569       chooser.setDialogTitle("Create EPS file from alignment");\r
570       chooser.setToolTipText("Save");\r
571 \r
572       int value = chooser.showSaveDialog(this);\r
573       if (value != jalview.io.JalviewFileChooser.APPROVE_OPTION)\r
574         return;\r
575 \r
576       jalview.bin.Cache.setProperty("LAST_DIRECTORY",chooser.getSelectedFile().getPath());\r
577       FileOutputStream out = new FileOutputStream(chooser.getSelectedFile());\r
578       EpsGraphics2D pg = new EpsGraphics2D("Example", out, 0, 0, width, height);\r
579 \r
580         if (av.getWrapAlignment())\r
581           printWrappedAlignment(pg, width, height, 0);\r
582         else\r
583           printUnwrapped(pg, width, height, 0);\r
584 \r
585 \r
586         pg.flush();\r
587         pg.close();\r
588     }\r
589     catch (Exception ex)\r
590     {\r
591       ex.printStackTrace();\r
592     }\r
593   }\r
594 \r
595   public void makePNG()\r
596   {\r
597       int height = (av.alignment.getWidth() / av.getChunkWidth() +1) * av.chunkHeight;\r
598       int width = seqPanel.getWidth() + idPanel.getWidth();\r
599 \r
600       if (!av.getWrapAlignment())\r
601       {\r
602         height = (av.alignment.getHeight()+1) * av.charHeight + 30;\r
603         width = idPanel.getWidth() + av.alignment.getWidth() * av.charWidth;\r
604       }\r
605 \r
606       if(av.getShowAnnotation())\r
607       {\r
608         height += annotationPanel.getPreferredSize().height;\r
609       }\r
610 \r
611 \r
612 System.out.println(width +" "+height);\r
613 \r
614     try\r
615     {\r
616       jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(jalview.bin.Cache.getProperty(\r
617           "LAST_DIRECTORY"), new String[]{"png"}, "Portable network graphics");\r
618       chooser.setFileView(new jalview.io.JalviewFileView());\r
619       chooser.setDialogTitle("Create EPS file from alignment");\r
620       chooser.setToolTipText("Save");\r
621 \r
622       int value = chooser.showSaveDialog(this);\r
623       if (value != jalview.io.JalviewFileChooser.APPROVE_OPTION)\r
624         return;\r
625 \r
626       jalview.bin.Cache.setProperty("LAST_DIRECTORY",chooser.getSelectedFile().getPath());\r
627       FileOutputStream out = new FileOutputStream(chooser.getSelectedFile());\r
628 \r
629       BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\r
630       Graphics png = bi.getGraphics();\r
631 \r
632 \r
633         if (av.getWrapAlignment())\r
634           printWrappedAlignment(png, width, height, 0);\r
635         else\r
636           printUnwrapped(png, width, height, 0);\r
637 \r
638         ImageIO.write(bi, "png", out);\r
639         out.close();\r
640     }\r
641     catch (Exception ex)\r
642     {\r
643       ex.printStackTrace();\r
644     }\r
645   }\r
646 \r
647 }\r
648 \r
649 \r
650 \r
651 \r