package org.freehep.application; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dialog; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Shape; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Rectangle2D.Double; import java.awt.image.BufferedImage; import java.awt.print.PageFormat; import java.awt.print.Pageable; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.util.Properties; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JToolBar; import javax.swing.SwingUtilities; import org.freehep.swing.layout.FlowScrollLayout; import org.freehep.swing.popup.PopupListener; import org.freehep.util.images.ImageHandler; /** * This class can be used to add print preview capabilities to an application. * Originally taken from the book <a href="http://manning.spindoczine.com/sbe/">Swing</a> by * Matthew Robinson and Pavel Vorobiev, Ph.D. * * @author Tony Johnson * @version $Id: PrintPreview.java 8584 2006-08-10 23:06:37Z duns $ */ public class PrintPreview extends JPanel { private Pageable m_pageable; private JPanel m_preview; private Properties m_props; private int m_scale = 10; /** * Create an empty PrintPreview */ public PrintPreview() { Application app = Application.getApplication(); if (app != null) { m_props = app.getUserProperties(); m_scale = PropertyUtilities.getInteger(m_props,"printPreviewScale",10); } setLayout(new BorderLayout()); setPreferredSize(new Dimension(600, 400)); add(createToolBar(), BorderLayout.NORTH); JScrollPane ps = new JScrollPane(); FlowScrollLayout layout = new FlowScrollLayout(ps); layout.setAlignment(FlowLayout.LEFT); m_preview = new JPanel(layout); m_preview.addMouseListener(new PopupListener(createPopupMenu())); ps.setViewportView(m_preview); add(ps, BorderLayout.CENTER); } /** * Set a target Printable using the default PageFormat. * Printables are only suitable for printing a small number of pages, for more * pages use a Pageable instead. * @param target The Printable to preview * @throws PrinterException If an exception occurs while trying to figure out how many pages are available */ public void setPrintable(Printable target) throws PrinterException { setPrintable(target,PrinterJob.getPrinterJob().defaultPage()); } /** * Set a target Printable. * Printables are only suitable for printing a small number of pages, for more * pages use a Pageable instead. * @param target The Printable to preview * @param pf The PageFormat to use for the pages * @throws PrinterException If an exception occurs while trying to figure out how many pages are available */ public void setPrintable(Printable target, PageFormat pf) throws PrinterException { setPageable(new PageableFromPrintable(target,pf)); } /** * Set a target Pageable. * @param target The Pageable to preview */ public void setPageable(Pageable target) { m_pageable = target; m_preview.removeAll(); for (int i=0; i<target.getNumberOfPages(); i++) { m_preview.add(new PagePreview(100/m_scale,i)); } } private void setScale(int i) { if (m_props != null) PropertyUtilities.setInteger(m_props,"printPreviewScale",i); Component[] comps = m_preview.getComponents(); for (int k=0; k<comps.length; k++) { if (!(comps[k] instanceof PagePreview))continue; PagePreview pp = (PagePreview)comps[k]; pp.setScale(100/i); } m_preview.revalidate(); } /** * Create a standard dialog that wraps the PrintPreview * @param owner The owner of the dialog */ public JDialog createDialog(Component owner) { return createDialog(owner,"Print Preview"); } /** * Create a standard dialog that wraps the PrintPreview * @param owner The owner of the dialog * @param title The title of the dialog */ public JDialog createDialog(Component owner, String title) { Window w = (Window) SwingUtilities.getAncestorOfClass(Window.class,owner); JDialog dlg = w instanceof Frame ? new JDialog((Frame) w, title, true) : new JDialog((Dialog) w, title, true); dlg.setContentPane(this); dlg.setDefaultCloseOperation(dlg.DISPOSE_ON_CLOSE); return dlg; } /** * Called if the user chooses Print. Override for custom printing. * @return true if printing was completed, false if cancelled by user */ protected boolean onPrint(Pageable document) throws PrinterException { PrinterJob pj = PrinterJob.getPrinterJob(); pj.setPageable(document); pj.print(); return true; } protected void onError(PrinterException x) { JOptionPane.showMessageDialog(this,"Print Error: "+x.getMessage(),"Print Error...",JOptionPane.ERROR_MESSAGE); } protected JPopupMenu createPopupMenu() { JPopupMenu menu = new JPopupMenu(); menu.add(getPrintAction()); menu.add(getCloseAction()); return menu; } /** * Called to create the toolbar. Override to customize the toolbar. */ protected JToolBar createToolBar() { JToolBar tb = new JToolBar(); tb.add(createCloseButton()); tb.add(createPrintButton()); tb.addSeparator(); tb.add(createScaleChooser()); tb.setFloatable(false); // Doesn't work in a dialog tb.setRollover(true); return tb; } private void done() { // If we are in a Dialog, dispose the dialog JDialog dlg = (JDialog) SwingUtilities.getAncestorOfClass(JDialog.class,this); dlg.dispose(); } public Action getCloseAction() { return new AbstractAction("Close") { public void actionPerformed(ActionEvent e) { done(); } }; } public Action getPrintAction() { return new AbstractAction("Print",ImageHandler.getIcon("/toolbarButtonGraphics/general/Print16.gif",getClass())) { public void actionPerformed(ActionEvent e) { Cursor oldCursor = getCursor(); try { setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); if (onPrint(m_pageable)) done(); } catch (PrinterException ex) { onError(ex); } finally { setCursor(oldCursor); } } }; } /** * Creates the Close button */ protected JComponent createCloseButton() { return new JButton(getCloseAction()); } /** * Creates the Print Button */ protected JComponent createPrintButton() { return new JButton(getPrintAction()); } /** * Create the Scale chooser */ protected JComponent createScaleChooser() { String[] scales = { "10 %", "25 %", "50 %", "100 %" }; final JComboBox m_cbScale = new JComboBox(scales); m_cbScale.setMaximumSize(m_cbScale.getPreferredSize()); m_cbScale.setEditable(true); m_cbScale.setSelectedItem(m_scale+" %"); m_cbScale.addActionListener(new ActionListener() { private boolean isRentrant = false; public void actionPerformed(ActionEvent e) { if (isRentrant) return; try { isRentrant = true; String str = m_cbScale.getSelectedItem().toString(); if (str.endsWith("%")) str = str.substring(0, str.length()-1); str = str.trim(); int scale = 0; try { scale = Integer.parseInt(str); if (scale <= 0) scale = 10; else if (scale > 100) scale = 100; } catch (NumberFormatException ex) { scale = 10; } String scaleString = scale+" %"; if (!scaleString.equals(str)) m_cbScale.setSelectedItem(scaleString); setScale(scale); } finally { isRentrant = false; } } }); return m_cbScale; } private class PagePreview extends JPanel { private int m_page, m_scale, m_h, m_w; public PagePreview(int scale, int page) { m_page = page; m_scale = scale; PageFormat pf = m_pageable.getPageFormat(page); m_w = (int)(pf.getWidth()/scale); m_h = (int)(pf.getHeight()/scale); setBorder(BorderFactory.createLineBorder(Color.black)); } public void setScale(int scale) { m_scale = scale; PageFormat pf = m_pageable.getPageFormat(m_page); m_w = (int)(pf.getWidth()/scale); m_h = (int)(pf.getHeight()/scale); repaint(); } public Dimension getPreferredSize() { Insets ins = getInsets(); return new Dimension(m_w+ins.left+ins.right,m_h+ins.top+ins.bottom); } public Dimension getMaximumSize() { return getPreferredSize(); } public Dimension getMinimumSize() { return getPreferredSize(); } public void paint(Graphics g) { g.setColor(Color.white); g.fillRect(0, 0, getWidth(), getHeight()); paintBorder(g); Printable print = m_pageable.getPrintable(m_page); PageFormat pf = m_pageable.getPageFormat(m_page); try { Graphics2D g2 = (Graphics2D) g; Shape clip = new Double(pf.getImageableX(),pf.getImageableY(),pf.getImageableWidth(),pf.getImageableHeight()); //g2.addRenderingHints(new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, // RenderingHints.VALUE_TEXT_ANTIALIAS_ON )); g2.scale(1./m_scale,1./m_scale); g2.clip(clip); print.print(g,pf,m_page); } catch (PrinterException x) {}; } } private class PageableFromPrintable implements Pageable { PageableFromPrintable(Printable input, PageFormat pf) throws PrinterException { this.pf = pf; this.printable = input; // We create a 1 pixel buffered image, just so we can loop over // the pages to find out how many there are BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); Graphics g = img.getGraphics(); for (nPages = 0;;nPages++) { if (input.print(g, pf, nPages) != Printable.PAGE_EXISTS) break; } } private Printable printable; private PageFormat pf; private int nPages; public int getNumberOfPages() { return nPages; } public PageFormat getPageFormat(int pages) { return pf; } public Printable getPrintable(int page) { return printable; } } }