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