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