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