/* ****************************************************************************** * * Copyright 2008-2010 Hans Dijkema * * JRichTextEditor is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * JRichTextEditor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with JRichTextEditor. If not, see <http://www.gnu.org/licenses/>. * * ******************************************************************************/ package nl.dykema.jxmlnote.report.viewers; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.HeadlessException; import java.awt.Point; import java.awt.Rectangle; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.geom.AffineTransform; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; import java.util.Date; import javax.print.attribute.HashPrintRequestAttributeSet; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.filechooser.FileFilter; import nl.dykema.jxmlnote.exceptions.DefaultXMLNoteErrorHandler; import nl.dykema.jxmlnote.interfaces.XMLNotePreferences; import nl.dykema.jxmlnote.internationalization.DefaultXMLNoteTranslator; import nl.dykema.jxmlnote.internationalization.XMLNoteTranslator; import nl.dykema.jxmlnote.report.viewers.PdfPagePanel.ZoomListener; import nl.dykema.jxmlnote.toolbar.JXMLNoteIcon; import nl.dykema.jxmlnote.toolbar.JXMLNoteToolBar; import nl.dykema.jxmlnote.widgets.JPrintPreferences; import nl.dykema.jxmlnote.widgets.JRecentlyUsedMenu; import nl.dykema.jxmlnote.widgets.JXMLNoteSwingUtils; import com.sun.pdfview.PDFFile; import com.sun.pdfview.PDFPage; import com.sun.pdfview.PDFRenderer; /** * With this class it is possible to view- and print a PDF File. This can be used to view the output * of XMLNoteToPdf. This class * * @author Hans Dijkema * */ public class PdfViewer extends JDialog implements Printable, ActionListener { private static final long serialVersionUID = 1L; private XMLNoteTranslator _tr; private JXMLNoteToolBar _toolbar; private JMenuBar _bar; private RandomAccessFile _raf; private FileChannel _channel; private PDFFile _pdffile; private PdfPagePanel _pdfpanel; private int _pageNr; private JLabel _pagesLabel; private JLabel _pageNrLabel; private JLabel _zoomLabel; private PageFormat _pageFormat; private double _zoom=1.0; private int _mode; private XMLNotePreferences _preferences; private File _fileToView; private File _tmpFileToView; private boolean _closed; private static int _scrollUnitIncrement=16; private class StatusBar extends JPanel { private static final long serialVersionUID = 1L; public StatusBar() { super.setLayout(new FlowLayout(FlowLayout.RIGHT)); super.setBorder(BorderFactory.createEtchedBorder()); } } private void setZoom(double z) { _zoom=z; _zoomLabel.setText(String.format("%.1f%%", _zoom*100.0)); } private double getZoom() { return _zoom; } public void actionPerformed(ActionEvent e) { String c=e.getActionCommand(); if (c.equals(JXMLNoteToolBar.ACTION_NEXT)) { _pageNr+=1; if (_pageNr>_pdffile.getNumPages()) { _pageNr-=1; } } else if (c.equals(JXMLNoteToolBar.ACTION_PREVIOUS)) { _pageNr-=1; if (_pageNr<1) { _pageNr+=1; } } else if (c.equals(JXMLNoteToolBar.ACTION_FIRST)) { _pageNr=1; } else if (c.equals(JXMLNoteToolBar.ACTION_LAST)) { _pageNr=_pdffile.getNumPages(); } else if (c.equals(JXMLNoteToolBar.ACTION_PRINT)) { doPrint(); } else if (c.equals(JXMLNoteToolBar.ACTION_PRINT_PREFS)) { pageSettings(); } else if (c.equals(JXMLNoteToolBar.ACTION_ZOOM_FIT_WIDTH)) { _pdfpanel.zoomFitWidth(new ZoomListener() { public void zoomed(double z) { setZoom(z); } }); _mode=PdfPagePanel.PAGE_FIT_WIDTH; } else if (c.equals(JXMLNoteToolBar.ACTION_ZOOM_FIT_HEIGHT)) { _pdfpanel.zoomFitHeight(new ZoomListener() { public void zoomed(double z) { setZoom(z); } }); _mode=PdfPagePanel.PAGE_FIT_HEIGHT; } else if (c.equals(JXMLNoteToolBar.ACTION_ZOOM_100)) { setZoom(1.0); _pdfpanel.zoomFitNone(getZoom()); _mode=PdfPagePanel.PAGE_FIT_NONE; } else if (c.equals(JXMLNoteToolBar.ACTION_ZOOM_MORE)) { setZoom(getZoom()*1.1); _pdfpanel.zoomFitNone(getZoom()); _mode=PdfPagePanel.PAGE_FIT_NONE; } else if (c.equals(JXMLNoteToolBar.ACTION_ZOOM_LESS)) { setZoom(getZoom()/1.1); _pdfpanel.zoomFitNone(getZoom()); _mode=PdfPagePanel.PAGE_FIT_NONE; } else if (c.equals(JXMLNoteToolBar.ACTION_CLOSE)) { storePrefs(); try { closePdf(); } catch (IOException e1) { DefaultXMLNoteErrorHandler.exception(e1); } super.setVisible(false); } else if (c.equals(JXMLNoteToolBar.ACTION_SAVE)) { save(); } if (_pdfpanel.getPage().getPageNumber()!=(_pageNr)) { _pdfpanel.showPage(_pdffile.getPage(_pageNr)); } _pageNrLabel.setText(Integer.toString(_pageNr)); _pagesLabel.setText(Integer.toString(_pdffile.getNumPages())); } private void storePrefs() { Point p=this.getLocation(); Dimension s=this.getSize(); _preferences.put("pdfviewer.x", p.x); _preferences.put("pdfviewer.y", p.y); _preferences.put("pdfviewer.w", s.width); _preferences.put("pdfviewer.h", s.height); _preferences.put("pdfviewer.mode", _mode); _preferences.put("pdfviewer.zoom", (int) (getZoom()*10000.0)); } private void applyPreferences() { Point p=new Point(_preferences.getInt("pdfviewer.x", -1),_preferences.getInt("pdfviewer.y", -1)); Dimension s=new Dimension(_preferences.getInt("pdfviewer.w", 500),_preferences.getInt("pdfviewer.h", 700)); if (p.x<0 || p.y<0) { // do nothing } else { this.setLocation(p); } this.setPreferredSize(s); _mode=_preferences.getInt("pdfviewer.mode", PdfPagePanel.PAGE_FIT_NONE); _zoom=(double) (_preferences.getInt("pdfviewer.zoom", 10000)/10000.0); if (_zoom<0.2) { _zoom=0.2; } if (_mode==PdfPagePanel.PAGE_FIT_WIDTH) { _pdfpanel.zoomFitWidth(new ZoomListener() { public void zoomed(double z) { setZoom(z); } }); } else if (_mode==PdfPagePanel.PAGE_FIT_HEIGHT) { _pdfpanel.zoomFitHeight(new ZoomListener() { public void zoomed(double z) { setZoom(z); } }); } else if (_mode==PdfPagePanel.PAGE_FIT_NONE) { _pdfpanel.zoomFitNone(_zoom); } } public JXMLNoteToolBar toolbar() { return _toolbar; } public void save() { class MyFileChooser extends JFileChooser { private static final long serialVersionUID = 1L; public MyFileChooser(String dir) { super(dir); } protected JDialog createDialog(Component parent) throws HeadlessException { JDialog dlg=super.createDialog(parent); if (parent instanceof Window) { JXMLNoteSwingUtils.centerOnParent((Window) parent, dlg); } else { JXMLNoteSwingUtils.centerOnParent(SwingUtilities.getWindowAncestor(parent), dlg); } return dlg; } } String prevDir=_preferences.getString("previousSaveDir", System.getProperty("user.dir")); JFileChooser dlg=new MyFileChooser(prevDir); dlg.setFileFilter(new FileFilter() { public boolean accept(File f) { return f.getName().toLowerCase().endsWith(".pdf"); } public String getDescription() { return _tr._(".pdf - PDF files"); } }); int result=dlg.showSaveDialog(this); if (result==JFileChooser.APPROVE_OPTION) { File copyTo=dlg.getSelectedFile(); if (!copyTo.getName().toLowerCase().endsWith(".pdf")) { String f=copyTo.getAbsolutePath()+".pdf"; copyTo=new File(f); } try { byte[] buf=new byte[8192]; //InputStream in=new FileInputStream(_fileToView); long seek=_raf.getFilePointer(); // we already have the pdf open OutputStream out=new FileOutputStream(copyTo); int len; _raf.seek(0); while ((len=_raf.read(buf))>0) { out.write(buf,0, len); } out.close(); _raf.seek(seek); String parent=copyTo.getParent(); if (parent!=null) { _preferences.put("previousSaveDir",parent); } } catch (Exception e) { DefaultXMLNoteErrorHandler.exception(e); } } } public int print (Graphics g, PageFormat format, int index) throws PrinterException { int pagenum = index+1; if (pagenum < 1 || pagenum > _pdffile.getNumPages ()) { return NO_SUCH_PAGE; } Graphics2D g2d = (Graphics2D) g; AffineTransform at = g2d.getTransform (); PDFPage pdfPage = _pdffile.getPage (pagenum); Dimension dim; dim = pdfPage.getUnstretchedSize ((int) format.getImageableWidth (), (int) format.getImageableHeight (), pdfPage.getBBox ()); Rectangle bounds = new Rectangle ((int) format.getImageableX (), (int) format.getImageableY (), dim.width, dim.height); PDFRenderer rend = new PDFRenderer (pdfPage, (Graphics2D) g, bounds,null, null); try { pdfPage.waitForFinish (); rend.run (); } catch (InterruptedException ie) { JOptionPane.showMessageDialog (this, ie.getMessage ()); } /*g2d.setTransform (at); g2d.draw (new Rectangle2D.Double (format.getImageableX (), format.getImageableY (), format.getImageableWidth (), format.getImageableHeight ()));*/ return PAGE_EXISTS; } private void pageSettings() { JPrintPreferences prefs=new JPrintPreferences(this,_preferences); prefs.pageDialog(); } private void doPrint() { // TODO: Hier iets met landscape/rotation doen. PrinterJob job = PrinterJob.getPrinterJob (); JPrintPreferences prefs=new JPrintPreferences(this,_preferences); HashPrintRequestAttributeSet set=new HashPrintRequestAttributeSet(); prefs.fromPrefs(set); job.setPrintable (this); Date dt=new Date(); SimpleDateFormat format=new SimpleDateFormat("yy-mm-dd HH:MM:SS"); job.setJobName(format.format(dt)+" - "+_fileToView.getName()); try { /*PrintService service=job.getPrintService(); DocFlavor flavor=DocFlavor.SERVICE_FORMATTED.PAGEABLE; final GraphicsConfiguration gc =GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); JDialog dlg=new ServiceDialog(gc,10,10,service,flavor,set,this); dlg.setModal(true); dlg.setVisible(true);*/ if (job.printDialog (set)) { prefs.toPrefs(set); job.print(set); } } catch (PrinterException pe) { JOptionPane.showMessageDialog (this, pe.getMessage ()); } } static public void setScrollUnitIncrement(int pixels) { _scrollUnitIncrement=pixels; } static public int getScrollUnitIncrement() { return _scrollUnitIncrement; } static public void showPdfViewer(JComponent parent,String title,File pdfFile,XMLNotePreferences prefs) throws IOException { showPdfViewer(SwingUtilities.getWindowAncestor(parent),parent,title,pdfFile,prefs); } static public void showPdfViewer(Window parent,String title,File pdfFile,XMLNotePreferences prefs) throws IOException { showPdfViewer(parent,null,title,pdfFile,prefs); } public void closePdf() throws IOException { if (!_closed) { this._channel.close(); this._raf.close(); _closed=true; } } static public void showPdfViewer(Window parent,Component relativeTo,String title,File pdfFile,XMLNotePreferences prefs) throws IOException { PdfViewer viewer=createPdfViewer(parent,relativeTo,title,pdfFile,prefs); viewer.setVisible(true); viewer.dispose(); } public static PdfViewer createPdfViewer(Window parent,Component relativeTo,String title,File pdfFile,XMLNotePreferences prefs) throws IOException { final PdfViewer viewer=new PdfViewer(parent,title,true,pdfFile,prefs); viewer.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); setScrollUnitIncrement(getScrollUnitIncrement()); if (relativeTo!=null) { viewer.setLocationRelativeTo(relativeTo); } viewer.pack(); // Sizes are known now. PDFPage page = viewer._pdffile.getPage(0); viewer._pdfpanel.showPage(page); return viewer; } private void copyFile(File from,File to) throws IOException { InputStream in = new FileInputStream(from); OutputStream out = new FileOutputStream(to); // Transfer bytes from in to out byte[] buf = new byte[8192]; int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } in.close(); out.close(); } protected PdfViewer(Window frame,String title,boolean modal,File fileToView,XMLNotePreferences prefs) throws IOException { super(frame,title); super.setModal(true); _fileToView=fileToView; _tmpFileToView=File.createTempFile("HOD",".pdf"); _tmpFileToView.deleteOnExit(); copyFile(_fileToView,_tmpFileToView); //int format=PageFormat.PORTRAIT; //format=PageFormat.LANDSCAPE; //PrinterJob.getPrinterJob().defaultPage().setOrientation(PageFormat.LANDSCAPE); _pageFormat = PrinterJob.getPrinterJob().defaultPage(); //_pageFormat.setOrientation(format); //_pageFormat.setOrientation(PageFormat.LANDSCAPE); _tr=new DefaultXMLNoteTranslator(); _toolbar=new JXMLNoteToolBar(this,null); _toolbar.setButtonSize(24); _toolbar.removeAllSections(); _toolbar.addSection("file",_tr._("Save PDF document")); _toolbar.add("file",JXMLNoteToolBar.ACTION_SAVE,_tr._("save PDF document"),this); _toolbar.addSection("navigating", _tr._("Navigate the PDF document")); _toolbar.add("navigating", JXMLNoteToolBar.ACTION_FIRST, _tr._("First page"), this); _toolbar.add("navigating", JXMLNoteToolBar.ACTION_PREVIOUS, _tr._("Previous page"), this); _toolbar.add("navigating", JXMLNoteToolBar.ACTION_NEXT, _tr._("Next page"), this); _toolbar.add("navigating", JXMLNoteToolBar.ACTION_LAST, _tr._("Last page"), this); _toolbar.addSection("zooming", _tr._("Zooming")); _toolbar.add("zooming", JXMLNoteToolBar.ACTION_ZOOM_FIT_WIDTH, _tr._("Fit Width"), this); _toolbar.add("zooming", JXMLNoteToolBar.ACTION_ZOOM_FIT_HEIGHT, _tr._("Fit Height"), this); _toolbar.add("zooming", JXMLNoteToolBar.ACTION_ZOOM_100, _tr._("100%"), this); _toolbar.add("zooming", JXMLNoteToolBar.ACTION_ZOOM_LESS, _tr._("10% less"), this); _toolbar.add("zooming", JXMLNoteToolBar.ACTION_ZOOM_MORE, _tr._("10% more"), this); _toolbar.addSection("printing", _tr._("Printing")); _toolbar.add("printing",JXMLNoteToolBar.ACTION_PRINT,_tr._("Print this document"),this); _toolbar.add("printing",JXMLNoteToolBar.ACTION_PRINT_PREFS,_tr._("Printer preferences"),this); _toolbar.initToolBar(); _bar=new JMenuBar(); JMenu window=JRecentlyUsedMenu.makeMenu(_tr._("_Window")); JXMLNoteIcon icn=new JXMLNoteIcon(JXMLNoteToolBar.ACTION_CLOSE); JMenuItem close=JRecentlyUsedMenu.makeMenuItem(_tr._("_Close"), icn, JXMLNoteToolBar.ACTION_CLOSE, this); _bar.add(window); window.add(close); JPanel mb=new JPanel(new BorderLayout()); mb.add(_bar,BorderLayout.NORTH); JPanel view=new JPanel(new BorderLayout()); view.add(_toolbar,BorderLayout.NORTH); _pdfpanel=new PdfPagePanel(_pageFormat); //_scrollpane=new JScrollPane(_pdfpanel,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); view.add(_pdfpanel,BorderLayout.CENTER); mb.add(view,BorderLayout.CENTER); StatusBar sbar=new StatusBar(); _zoomLabel=new JLabel(); _pageNrLabel=new JLabel(); _pagesLabel=new JLabel(); sbar.add(_zoomLabel); sbar.add(new JLabel("|")); sbar.add(_pageNrLabel); //sbar.add(new JSeparator(JSeparator.VERTICAL)); sbar.add(new JLabel("/")); sbar.add(_pagesLabel); mb.add(sbar,BorderLayout.SOUTH); this.add(mb); _raf = new RandomAccessFile(_tmpFileToView, "r"); _channel = _raf.getChannel(); ByteBuffer buf = _channel.map(FileChannel.MapMode.READ_ONLY,0, _channel.size()); _pdffile = new PDFFile(buf); _closed=false; _pageNr=1; _pageNrLabel.setText(Integer.toString(_pageNr)); _pagesLabel.setText(Integer.toString(_pdffile.getNumPages())); _preferences=prefs; applyPreferences(); this.addWindowListener(new WindowListener() { public void windowActivated(WindowEvent arg0) { } public void windowClosed(WindowEvent arg0) { } public void windowDeactivated(WindowEvent arg0) { } public void windowDeiconified(WindowEvent arg0) {} public void windowIconified(WindowEvent arg0) {} public void windowOpened(WindowEvent arg0) {} public void windowClosing(WindowEvent arg0) { storePrefs(); try { closePdf(); } catch (IOException e) { DefaultXMLNoteErrorHandler.exception(e); } } }); } }