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