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