/* * This file is modified by Ivan Maidanski * Project name: JCGO-SUNAWT (http://www.ivmaisoft.com/jcgo/) */ /* * @(#)PrintJob2D.java 1.13 03/01/23 * * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * Copyright 1998, 1999, 2000 Sun Microsystems, Inc. All Rights Reserved. * * This software is the proprietary information of Sun Microsystems, Inc. * Use is subject to license terms. */ package sun.print; import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.JobAttributes; import java.awt.PrintJob; import java.awt.PageAttributes; import java.awt.print.PageFormat; import java.awt.print.Paper; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.File; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Properties; import javax.print.PrintService; import javax.print.attribute.HashPrintRequestAttributeSet; import javax.print.attribute.PrintRequestAttributeSet; import javax.print.attribute.ResolutionSyntax; import javax.print.attribute.Size2DSyntax; import javax.print.attribute.standard.Chromaticity; import javax.print.attribute.standard.Copies; import javax.print.attribute.standard.Destination; import javax.print.attribute.standard.JobName; import javax.print.attribute.standard.MediaSize; import javax.print.attribute.standard.PrintQuality; import javax.print.attribute.standard.PrinterResolution; import javax.print.attribute.standard.SheetCollate; import javax.print.attribute.standard.Sides; import sun.awt.print.PrintDialog; import sun.awt.print.AwtPrintControl; /** * A class which initiates and executes a print job using * the underlying PrinterJob graphics conversions. * * @see Toolkit#getPrintJob * */ public class PrintJob2D extends PrintJob implements Printable, Runnable { private Frame frame; private String docTitle = ""; private JobAttributes jobAttributes; private PageAttributes pageAttributes; private PrintRequestAttributeSet attributes; /* * Displays the native or cross-platform dialog and allows the * user to update job & page attributes */ private AwtPrintControl printControl; /** * The PrinterJob being uses to implement the PrintJob. */ private PrinterJob printerJob; /** * The size of the page being used for the PrintJob. */ private PageFormat pageFormat; /** * The PrinterJob and the application run on different * threads and communicate through a pair of message * queues. This queue is the list of Graphics that * the PrinterJob has requested rendering for, but * for which the application has not yet called getGraphics(). * In practice the length of this message queue is always * 0 or 1. */ private MessageQ graphicsToBeDrawn = new MessageQ("tobedrawn"); /** * Used to communicate between the application's thread * and the PrinterJob's thread this message queue holds * the list of Graphics into which the application has * finished drawing, but that have not yet been returned * to the PrinterJob thread. Again, in practice, the * length of this message queue is always 0 or 1. */ private final MessageQ graphicsDrawn = new MessageQ("drawn"); /** * The last Graphics returned to the application via * getGraphics. This is the Graphics into which the * application is currently drawing. */ private Graphics2D currentGraphics; /** * The zero based index of the page currently being rendered * by the application. */ private int pageIndex = -1; /** * The thread on which PrinterJob is running. * This is different than the applications thread. */ private Thread printerJobThread; public PrintJob2D(Frame frame, String doctitle, final Properties props) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPrintJobAccess(); } if (frame == null) { throw new NullPointerException("Frame must not be null"); } this.docTitle = (doctitle == null) ? "" : docTitle; printControl = new AwtPrintControl(frame, doctitle, props); } public PrintJob2D(Frame frame, String doctitle, JobAttributes jobAttributes, PageAttributes pageAttributes) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPrintJobAccess(); } if (frame == null && (jobAttributes == null || jobAttributes.getDialog() == JobAttributes.DialogType.NATIVE)) { throw new NullPointerException("Frame must not be null"); } this.docTitle = (doctitle == null) ? "" : docTitle; this.jobAttributes = jobAttributes; this.pageAttributes = pageAttributes; printControl = new AwtPrintControl(frame, doctitle, jobAttributes, pageAttributes); } public boolean printDialog() { boolean proceedWithPrint = printControl.displayDialog(); if (proceedWithPrint) { jobAttributes = printControl.getJobAttributes(); pageAttributes = printControl.getPageAttributes(); printerJob = PrinterJob.getPrinterJob(); if (printerJob == null) { return false; } copyAttributes(); if (pageFormat == null) { pageFormat = printerJob.defaultPage(); } printerJob.setPrintable(this, pageFormat); } return proceedWithPrint; } private PrintService findNamedPrintService(String printerName) { PrintService service = printerJob.getPrintService(); if (service != null && printerName.equals(service.getName())) { return service; } else { PrintService []services = PrinterJob.lookupPrintServices(); for (int i=0; iPrinterJob calls the * Printable interface to request that a page be * rendered into the context specified by * graphics. The format of the page to be drawn is * specified by pageFormat. The zero based index * of the requested page is specified by pageIndex. * If the requested page does not exist then this method returns * NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned. * The Graphics class or subclass implements the * {@link PrinterGraphics} interface to provide additional * information. If the Printable object * aborts the print job then it throws a {@link PrinterException}. * @param graphics the context into which the page is drawn * @param pageFormat the size and orientation of the page being drawn * @param pageIndex the zero based index of the page to be drawn * @return PAGE_EXISTS if the page is rendered successfully * or NO_SUCH_PAGE if pageIndex specifies a * non-existent page. * @exception java.awt.print.PrinterException * thrown when the print job is terminated. */ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { int result; /* This method will be called by the PrinterJob on a thread other * that the application's thread. We hold on to the graphics * until we can rendevous with the application's thread and * hand over the graphics. The application then does all the * drawing. When the application is done drawing we rendevous * again with the PrinterJob thread and release the Graphics * so that it knows we are done. */ /* Add the graphics to the message queue of graphics to * be rendered. This is really a one slot queue. The * application's thread will come along and remove the * graphics from the queue when the app asks for a graphics. */ graphicsToBeDrawn.append( (Graphics2D) graphics); /* We now wait for the app's thread to finish drawing on * the Graphics. This thread will sleep until the application * release the graphics by placing it in the graphics drawn * message queue. If the application signals that it is * finished drawing the entire document then we'll get null * returned when we try and pop a finished graphic. */ if (graphicsDrawn.pop() != null) { result = PAGE_EXISTS; } else { result = NO_SUCH_PAGE; } return result; } private void startPrinterJobThread() { printerJobThread = new Thread(this, "printerJobThread"); printerJobThread.start(); } public void run() { try { printerJob.print(attributes); } catch (PrinterException e) { //REMIND: need to store this away and not rethrow it. } /* Close the message queues so that nobody is stuck * waiting for one. */ graphicsToBeDrawn.closeWhenEmpty(); graphicsDrawn.close(); } private class MessageQ { private String qid="noname"; private ArrayList queue = new ArrayList(); MessageQ(String id) { qid = id; } synchronized void closeWhenEmpty() { while (queue != null && queue.size() > 0) { try { wait(1000); } catch (InterruptedException e) { // do nothing. } } queue = null; notifyAll(); } synchronized void close() { queue = null; notifyAll(); } synchronized boolean append(Graphics2D g) { boolean queued = false; if (queue != null) { queue.add(g); queued = true; notify(); } return queued; } synchronized Graphics2D pop() { Graphics2D g = null; while (g == null && queue != null) { if (queue.size() > 0) { g = (Graphics2D) queue.remove(0); notify(); } else { try { wait(2000); } catch (InterruptedException e) { // do nothing. } } } return g; } } }