/* * @(#)PrintFileAction.java * * Copyright (c) 1996-2010 The authors and contributors of JHotDraw. * You may not use, copy or modify this file, except in compliance with the * accompanying license terms. */ package org.jhotdraw.app.action.file; import edu.umd.cs.findbugs.annotations.Nullable; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.awt.print.*; import javax.print.attribute.*; import javax.print.attribute.standard.*; import javax.swing.*; import org.jhotdraw.app.*; import org.jhotdraw.app.action.AbstractViewAction; import org.jhotdraw.gui.*; import org.jhotdraw.util.*; /** * Presents a printer chooser to the user and then prints the * {@link org.jhotdraw.app.View}. * <p> * This action requires that the view implements the {@link PrintableView} * interface. * <p> * This action is called when the user selects the Print item in the File * menu. The menu item is automatically created by the application. * <p> * If you want this behavior in your application, you have to create it * and put it in your {@code ApplicationModel} in method * {@link org.jhotdraw.app.ApplicationModel#initApplication}. * <p> * You should also create a {@link PrintFileAction} when you create this action. * <hr> * <b>Design Patterns</b> * * <p><em>Framework</em><br> * The interfaces and classes listed below define together the contracts * of a smaller framework inside of the JHotDraw framework for document oriented * applications.<br> * Contract: {@link PrintableView}.<br> * Client: {@link org.jhotdraw.app.action.file.PrintFileAction}. * <hr> * * @author Werner Randelshofer * @version $Id$ */ public class PrintFileAction extends AbstractViewAction { private static final long serialVersionUID = 1L; public static final String ID = "file.print"; /** Creates a new instance. */ public PrintFileAction(Application app, @Nullable View view) { super(app, view); ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.app.Labels"); labels.configureAction(this, ID); } @Override public void actionPerformed(ActionEvent evt) { PrintableView view = (PrintableView)getActiveView(); view.setEnabled(false); if ("true".equals(System.getProperty("apple.awt.graphics.UseQuartz", "false"))) { printQuartz(view); } else { printJava2D(view); } view.setEnabled(true); } /* * This prints at 72 DPI only. We might need this for some JVM versions on * Mac OS X.*/ public void printJava2D(PrintableView v) { Pageable pageable = v.createPageable(); if (pageable == null) { throw new InternalError("View does not have a method named java.awt.Pageable createPageable()"); } try { PrinterJob job = PrinterJob.getPrinterJob(); // FIXME - PrintRequestAttributeSet should be retrieved from View PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet(); attr.add(new PrinterResolution(300, 300, PrinterResolution.DPI)); job.setPageable(pageable); if (job.printDialog()) { try { job.print(); } catch (PrinterException e) { String message = (e.getMessage() == null) ? e.toString() : e.getMessage(); View view = getActiveView(); ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.app.Labels"); JSheet.showMessageSheet(view.getComponent(), "<html>" + UIManager.getString("OptionPane.css") + "<b>" + labels.getString("couldntPrint") + "</b><br>" + ((message == null) ? "" : message)); } } else { System.out.println("JOB ABORTED!"); } } catch (Throwable t) { t.printStackTrace(); } } /* * This prints at 72 DPI only. We might need this for some JVM versions on * Mac OS X.*/ public void printJava2DAlternative(PrintableView v) { Pageable pageable = v.createPageable(); if (pageable == null) { throw new InternalError("View does not have a method named java.awt.Pageable createPageable()"); } try { final PrinterJob job = PrinterJob.getPrinterJob(); PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet(); attr.add(new PrinterResolution(300, 300, PrinterResolution.DPI)); job.setPageable(pageable); if (job.printDialog(attr)) { try { job.print(); } catch (PrinterException e) { ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.app.Labels"); JSheet.showMessageSheet(getActiveView().getComponent(), labels.getFormatted("couldntPrint", e)); } } else { System.out.println("JOB ABORTED!"); } } catch (Throwable t) { t.printStackTrace(); } } /** * On Mac OS X with the Quartz rendering engine, the following code achieves * the best results. */ public void printQuartz(PrintableView v) { Frame frame = (Frame) SwingUtilities.getWindowAncestor(v.getComponent()); final Pageable pageable = v.createPageable(); final double resolution = 300d; JobAttributes jobAttr = new JobAttributes(); // FIXME - PageAttributes should be retrieved from View PageAttributes pageAttr = new PageAttributes(); pageAttr.setMedia(PageAttributes.MediaType.A4); pageAttr.setPrinterResolution((int) resolution); final PrintJob pj = frame.getToolkit().getPrintJob( frame, "Job Title", jobAttr, pageAttr); getActiveView().setEnabled(false); new BackgroundTask() { @Override protected void construct() throws PrinterException { // Compute page format from settings of the print job Paper paper = new Paper(); paper.setSize( pj.getPageDimension().width / resolution * 72d, pj.getPageDimension().height / resolution * 72d); paper.setImageableArea(64d, 32d, paper.getWidth() - 96d, paper.getHeight() - 64); PageFormat pageFormat = new PageFormat(); pageFormat.setPaper(paper); // Print the job try { for (int i = 0, n = pageable.getNumberOfPages(); i < n; i++) { PageFormat pf = pageable.getPageFormat(i); pf = pageFormat; Graphics g = pj.getGraphics(); if (g instanceof Graphics2D) { pageable.getPrintable(i).print(g, pf, i); } else { BufferedImage buf = new BufferedImage( (int) (pf.getImageableWidth() * resolution / 72d), (int) (pf.getImageableHeight() * resolution / 72d), BufferedImage.TYPE_INT_RGB); Graphics2D bufG = buf.createGraphics(); bufG.setBackground(Color.WHITE); bufG.fillRect(0, 0, buf.getWidth(), buf.getHeight()); bufG.scale(resolution / 72d, resolution / 72d); bufG.translate(-pf.getImageableX(), -pf.getImageableY()); pageable.getPrintable(i).print(bufG, pf, i); bufG.dispose(); g.drawImage(buf, (int) (pf.getImageableX() * resolution / 72d), (int) (pf.getImageableY() * resolution / 72d), null); buf.flush(); } g.dispose(); } } finally { pj.end(); } } @Override protected void failed(Throwable error) { error.printStackTrace(); } @Override protected void finished() { getActiveView().setEnabled(true); } }.start(); } /** * Returns true if the action is enabled. * The enabled state of the action depends on the state that has been set * using setEnabled() and on the enabled state of the application. * * @return true if the action is enabled, false otherwise * @see Action#isEnabled */ @Override public boolean isEnabled() { return super.isEnabled() && (getActiveView() instanceof PrintableView); } }