/* * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.print; import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.PrintJob; import java.awt.JobAttributes; import java.awt.JobAttributes.*; import java.awt.PageAttributes; 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.io.FilePermission; import java.io.IOException; 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.DialogTypeSelection; 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 javax.print.attribute.standard.Media; import javax.print.attribute.standard.OrientationRequested; import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.PageRanges; import sun.print.SunPageSelection; import sun.print.SunMinMaxPage; /** * 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 static final MediaType SIZES[] = { MediaType.ISO_4A0, MediaType.ISO_2A0, MediaType.ISO_A0, MediaType.ISO_A1, MediaType.ISO_A2, MediaType.ISO_A3, MediaType.ISO_A4, MediaType.ISO_A5, MediaType.ISO_A6, MediaType.ISO_A7, MediaType.ISO_A8, MediaType.ISO_A9, MediaType.ISO_A10, MediaType.ISO_B0, MediaType.ISO_B1, MediaType.ISO_B2, MediaType.ISO_B3, MediaType.ISO_B4, MediaType.ISO_B5, MediaType.ISO_B6, MediaType.ISO_B7, MediaType.ISO_B8, MediaType.ISO_B9, MediaType.ISO_B10, MediaType.JIS_B0, MediaType.JIS_B1, MediaType.JIS_B2, MediaType.JIS_B3, MediaType.JIS_B4, MediaType.JIS_B5, MediaType.JIS_B6, MediaType.JIS_B7, MediaType.JIS_B8, MediaType.JIS_B9, MediaType.JIS_B10, MediaType.ISO_C0, MediaType.ISO_C1, MediaType.ISO_C2, MediaType.ISO_C3, MediaType.ISO_C4, MediaType.ISO_C5, MediaType.ISO_C6, MediaType.ISO_C7, MediaType.ISO_C8, MediaType.ISO_C9, MediaType.ISO_C10, MediaType.ISO_DESIGNATED_LONG, MediaType.EXECUTIVE, MediaType.FOLIO, MediaType.INVOICE, MediaType.LEDGER, MediaType.NA_LETTER, MediaType.NA_LEGAL, MediaType.QUARTO, MediaType.A, MediaType.B, MediaType.C, MediaType.D, MediaType.E, MediaType.NA_10X15_ENVELOPE, MediaType.NA_10X14_ENVELOPE, MediaType.NA_10X13_ENVELOPE, MediaType.NA_9X12_ENVELOPE, MediaType.NA_9X11_ENVELOPE, MediaType.NA_7X9_ENVELOPE, MediaType.NA_6X9_ENVELOPE, MediaType.NA_NUMBER_9_ENVELOPE, MediaType.NA_NUMBER_10_ENVELOPE, MediaType.NA_NUMBER_11_ENVELOPE, MediaType.NA_NUMBER_12_ENVELOPE, MediaType.NA_NUMBER_14_ENVELOPE, MediaType.INVITE_ENVELOPE, MediaType.ITALY_ENVELOPE, MediaType.MONARCH_ENVELOPE, MediaType.PERSONAL_ENVELOPE }; /* This array maps the above array to the objects used by the * javax.print APIs */ private static final MediaSizeName JAVAXSIZES[] = { null, null, MediaSizeName.ISO_A0, MediaSizeName.ISO_A1, MediaSizeName.ISO_A2, MediaSizeName.ISO_A3, MediaSizeName.ISO_A4, MediaSizeName.ISO_A5, MediaSizeName.ISO_A6, MediaSizeName.ISO_A7, MediaSizeName.ISO_A8, MediaSizeName.ISO_A9, MediaSizeName.ISO_A10, MediaSizeName.ISO_B0, MediaSizeName.ISO_B1, MediaSizeName.ISO_B2, MediaSizeName.ISO_B3, MediaSizeName.ISO_B4, MediaSizeName.ISO_B5, MediaSizeName.ISO_B6, MediaSizeName.ISO_B7, MediaSizeName.ISO_B8, MediaSizeName.ISO_B9, MediaSizeName.ISO_B10, MediaSizeName.JIS_B0, MediaSizeName.JIS_B1, MediaSizeName.JIS_B2, MediaSizeName.JIS_B3, MediaSizeName.JIS_B4, MediaSizeName.JIS_B5, MediaSizeName.JIS_B6, MediaSizeName.JIS_B7, MediaSizeName.JIS_B8, MediaSizeName.JIS_B9, MediaSizeName.JIS_B10, MediaSizeName.ISO_C0, MediaSizeName.ISO_C1, MediaSizeName.ISO_C2, MediaSizeName.ISO_C3, MediaSizeName.ISO_C4, MediaSizeName.ISO_C5, MediaSizeName.ISO_C6, null, null, null, null, MediaSizeName.ISO_DESIGNATED_LONG, MediaSizeName.EXECUTIVE, MediaSizeName.FOLIO, MediaSizeName.INVOICE, MediaSizeName.LEDGER, MediaSizeName.NA_LETTER, MediaSizeName.NA_LEGAL, MediaSizeName.QUARTO, MediaSizeName.A, MediaSizeName.B, MediaSizeName.C, MediaSizeName.D, MediaSizeName.E, MediaSizeName.NA_10X15_ENVELOPE, MediaSizeName.NA_10X14_ENVELOPE, MediaSizeName.NA_10X13_ENVELOPE, MediaSizeName.NA_9X12_ENVELOPE, MediaSizeName.NA_9X11_ENVELOPE, MediaSizeName.NA_7X9_ENVELOPE, MediaSizeName.NA_6X9_ENVELOPE, MediaSizeName.NA_NUMBER_9_ENVELOPE, MediaSizeName.NA_NUMBER_10_ENVELOPE, MediaSizeName.NA_NUMBER_11_ENVELOPE, MediaSizeName.NA_NUMBER_12_ENVELOPE, MediaSizeName.NA_NUMBER_14_ENVELOPE, null, MediaSizeName.ITALY_ENVELOPE, MediaSizeName.MONARCH_ENVELOPE, MediaSizeName.PERSONAL_ENVELOPE, }; // widths and lengths in PostScript points (1/72 in.) private static final int WIDTHS[] = { /*iso-4a0*/ 4768, /*iso-2a0*/ 3370, /*iso-a0*/ 2384, /*iso-a1*/ 1684, /*iso-a2*/ 1191, /*iso-a3*/ 842, /*iso-a4*/ 595, /*iso-a5*/ 420, /*iso-a6*/ 298, /*iso-a7*/ 210, /*iso-a8*/ 147, /*iso-a9*/ 105, /*iso-a10*/ 74, /*iso-b0*/ 2835, /*iso-b1*/ 2004, /*iso-b2*/ 1417, /*iso-b3*/ 1001, /*iso-b4*/ 709, /*iso-b5*/ 499, /*iso-b6*/ 354, /*iso-b7*/ 249, /*iso-b8*/ 176, /*iso-b9*/ 125, /*iso-b10*/ 88, /*jis-b0*/ 2920, /*jis-b1*/ 2064, /*jis-b2*/ 1460, /*jis-b3*/ 1032, /*jis-b4*/ 729, /*jis-b5*/ 516, /*jis-b6*/ 363, /*jis-b7*/ 258, /*jis-b8*/ 181, /*jis-b9*/ 128, /*jis-b10*/ 91, /*iso-c0*/ 2599, /*iso-c1*/ 1837, /*iso-c2*/ 1298, /*iso-c3*/ 918, /*iso-c4*/ 649, /*iso-c5*/ 459, /*iso-c6*/ 323, /*iso-c7*/ 230, /*iso-c8*/ 162, /*iso-c9*/ 113, /*iso-c10*/ 79, /*iso-designated-long*/ 312, /*executive*/ 522, /*folio*/ 612, /*invoice*/ 396, /*ledger*/ 792, /*na-letter*/ 612, /*na-legal*/ 612, /*quarto*/ 609, /*a*/ 612, /*b*/ 792, /*c*/ 1224, /*d*/ 1584, /*e*/ 2448, /*na-10x15-envelope*/ 720, /*na-10x14-envelope*/ 720, /*na-10x13-envelope*/ 720, /*na-9x12-envelope*/ 648, /*na-9x11-envelope*/ 648, /*na-7x9-envelope*/ 504, /*na-6x9-envelope*/ 432, /*na-number-9-envelope*/ 279, /*na-number-10-envelope*/ 297, /*na-number-11-envelope*/ 324, /*na-number-12-envelope*/ 342, /*na-number-14-envelope*/ 360, /*invite-envelope*/ 624, /*italy-envelope*/ 312, /*monarch-envelope*/ 279, /*personal-envelope*/ 261 }; private static final int LENGTHS[] = { /*iso-4a0*/ 6741, /*iso-2a0*/ 4768, /*iso-a0*/ 3370, /*iso-a1*/ 2384, /*iso-a2*/ 1684, /*iso-a3*/ 1191, /*iso-a4*/ 842, /*iso-a5*/ 595, /*iso-a6*/ 420, /*iso-a7*/ 298, /*iso-a8*/ 210, /*iso-a9*/ 147, /*iso-a10*/ 105, /*iso-b0*/ 4008, /*iso-b1*/ 2835, /*iso-b2*/ 2004, /*iso-b3*/ 1417, /*iso-b4*/ 1001, /*iso-b5*/ 729, /*iso-b6*/ 499, /*iso-b7*/ 354, /*iso-b8*/ 249, /*iso-b9*/ 176, /*iso-b10*/ 125, /*jis-b0*/ 4127, /*jis-b1*/ 2920, /*jis-b2*/ 2064, /*jis-b3*/ 1460, /*jis-b4*/ 1032, /*jis-b5*/ 729, /*jis-b6*/ 516, /*jis-b7*/ 363, /*jis-b8*/ 258, /*jis-b9*/ 181, /*jis-b10*/ 128, /*iso-c0*/ 3677, /*iso-c1*/ 2599, /*iso-c2*/ 1837, /*iso-c3*/ 1298, /*iso-c4*/ 918, /*iso-c5*/ 649, /*iso-c6*/ 459, /*iso-c7*/ 323, /*iso-c8*/ 230, /*iso-c9*/ 162, /*iso-c10*/ 113, /*iso-designated-long*/ 624, /*executive*/ 756, /*folio*/ 936, /*invoice*/ 612, /*ledger*/ 1224, /*na-letter*/ 792, /*na-legal*/ 1008, /*quarto*/ 780, /*a*/ 792, /*b*/ 1224, /*c*/ 1584, /*d*/ 2448, /*e*/ 3168, /*na-10x15-envelope*/ 1080, /*na-10x14-envelope*/ 1008, /*na-10x13-envelope*/ 936, /*na-9x12-envelope*/ 864, /*na-9x11-envelope*/ 792, /*na-7x9-envelope*/ 648, /*na-6x9-envelope*/ 648, /*na-number-9-envelope*/ 639, /*na-number-10-envelope*/ 684, /*na-number-11-envelope*/ 747, /*na-number-12-envelope*/ 792, /*na-number-14-envelope*/ 828, /*invite-envelope*/ 624, /*italy-envelope*/ 652, /*monarch-envelope*/ 540, /*personal-envelope*/ 468 }; 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 */ /** * 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 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 following Strings are maintained for backward-compatibility with // Properties based print control. private final static String DEST_PROP = "awt.print.destination"; private final static String PRINTER = "printer"; private final static String FILE = "file"; private final static String PRINTER_PROP = "awt.print.printer"; private final static String FILENAME_PROP = "awt.print.fileName"; private final static String NUMCOPIES_PROP = "awt.print.numCopies"; private final static String OPTIONS_PROP = "awt.print.options"; private final static String ORIENT_PROP = "awt.print.orientation"; private final static String PORTRAIT = "portrait"; private final static String LANDSCAPE = "landscape"; private final static String PAPERSIZE_PROP = "awt.print.paperSize"; private final static String LETTER = "letter"; private final static String LEGAL = "legal"; private final static String EXECUTIVE = "executive"; private final static String A4 = "a4"; private Properties props; private String options = ""; // REMIND: needs implementation /** * 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) { this.props = props; this.jobAttributes = new JobAttributes(); this.pageAttributes = new PageAttributes(); translateInputProps(); initPrintJob2D(frame, doctitle, this.jobAttributes, this.pageAttributes); } public PrintJob2D(Frame frame, String doctitle, JobAttributes jobAttributes, PageAttributes pageAttributes) { initPrintJob2D(frame, doctitle, jobAttributes, pageAttributes); } private void initPrintJob2D(Frame frame, String doctitle, JobAttributes jobAttributes, PageAttributes pageAttributes) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPrintJobAccess(); } if (frame == null && (jobAttributes == null || jobAttributes.getDialog() == DialogType.NATIVE)) { throw new NullPointerException("Frame must not be null"); } this.frame = frame; this.docTitle = (doctitle == null) ? "" : doctitle; this.jobAttributes = (jobAttributes != null) ? jobAttributes : new JobAttributes(); this.pageAttributes = (pageAttributes != null) ? pageAttributes : new PageAttributes(); // Currently, we always reduce page ranges to xxx or xxx-xxx int[][] pageRanges = this.jobAttributes.getPageRanges(); int first = pageRanges[0][0]; int last = pageRanges[pageRanges.length - 1][1]; this.jobAttributes.setPageRanges(new int[][] { new int[] { first, last } }); this.jobAttributes.setToPage(last); this.jobAttributes.setFromPage(first); // Verify that the cross feed and feed resolutions are the same int[] res = this.pageAttributes.getPrinterResolution(); if (res[0] != res[1]) { throw new IllegalArgumentException("Differing cross feed and feed"+ " resolutions not supported."); } // Verify that the app has access to the file system DestinationType dest= this.jobAttributes.getDestination(); if (dest == DestinationType.FILE) { throwPrintToFile(); // check if given filename is valid String destStr = jobAttributes.getFileName(); if ((destStr != null) && (jobAttributes.getDialog() == JobAttributes.DialogType.NONE)) { File f = new File(destStr); try { // check if this is a new file and if filename chars are valid // createNewFile returns false if file exists if (f.createNewFile()) { f.delete(); } } catch (IOException ioe) { throw new IllegalArgumentException("Cannot write to file:"+ destStr); } catch (SecurityException se) { //There is already file read/write access so at this point // only delete access is denied. Just ignore it because in // most cases the file created in createNewFile gets overwritten // anyway. } File pFile = f.getParentFile(); if ((f.exists() && (!f.isFile() || !f.canWrite())) || ((pFile != null) && (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) { throw new IllegalArgumentException("Cannot write to file:"+ destStr); } } } } public boolean printDialog() { boolean proceedWithPrint = false; printerJob = PrinterJob.getPrinterJob(); if (printerJob == null) { return false; } DialogType d = this.jobAttributes.getDialog(); PrintService pServ = printerJob.getPrintService(); if ((pServ == null) && (d == DialogType.NONE)){ return false; } copyAttributes(pServ); DefaultSelectionType select = this.jobAttributes.getDefaultSelection(); if (select == DefaultSelectionType.RANGE) { attributes.add(SunPageSelection.RANGE); } else if (select == DefaultSelectionType.SELECTION) { attributes.add(SunPageSelection.SELECTION); } else { attributes.add(SunPageSelection.ALL); } if (frame != null) { attributes.add(new DialogOwner(frame)); } if ( d == DialogType.NONE) { proceedWithPrint = true; } else { if (d == DialogType.NATIVE) { attributes.add(DialogTypeSelection.NATIVE); } else { // (d == DialogType.COMMON) attributes.add(DialogTypeSelection.COMMON); } if (proceedWithPrint = printerJob.printDialog(attributes)) { if (pServ == null) { // Windows gives an option to install a service // when it detects there are no printers so // we make sure we get the updated print service. pServ = printerJob.getPrintService(); if (pServ == null) { return false; } } updateAttributes(); translateOutputProps(); } } if (proceedWithPrint) { JobName jname = (JobName)attributes.get(JobName.class); if (jname != null) { printerJob.setJobName(jname.toString()); } pageFormat = new PageFormat(); Media media = (Media)attributes.get(Media.class); MediaSize mediaSize = null; if (media != null && media instanceof MediaSizeName) { mediaSize = MediaSize.getMediaSizeForName((MediaSizeName)media); } Paper p = pageFormat.getPaper(); if (mediaSize != null) { p.setSize(mediaSize.getX(MediaSize.INCH)*72.0, mediaSize.getY(MediaSize.INCH)*72.0); } if (pageAttributes.getOrigin()==OriginType.PRINTABLE) { // AWT uses 1/4" borders by default p.setImageableArea(18.0, 18.0, p.getWidth()-36.0, p.getHeight()-36.0); } else { p.setImageableArea(0.0,0.0,p.getWidth(),p.getHeight()); } pageFormat.setPaper(p); OrientationRequested orient = (OrientationRequested)attributes.get(OrientationRequested.class); if (orient!= null && orient == OrientationRequested.REVERSE_LANDSCAPE) { pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE); } else if (orient == OrientationRequested.LANDSCAPE) { pageFormat.setOrientation(PageFormat.LANDSCAPE); } else { pageFormat.setOrientation(PageFormat.PORTRAIT); } printerJob.setPrintable(this, pageFormat); } return proceedWithPrint; } private void updateAttributes() { Copies c = (Copies)attributes.get(Copies.class); jobAttributes.setCopies(c.getValue()); SunPageSelection sel = (SunPageSelection)attributes.get(SunPageSelection.class); if (sel == SunPageSelection.RANGE) { jobAttributes.setDefaultSelection(DefaultSelectionType.RANGE); } else if (sel == SunPageSelection.SELECTION) { jobAttributes.setDefaultSelection(DefaultSelectionType.SELECTION); } else { jobAttributes.setDefaultSelection(DefaultSelectionType.ALL); } Destination dest = (Destination)attributes.get(Destination.class); if (dest != null) { jobAttributes.setDestination(DestinationType.FILE); jobAttributes.setFileName(dest.getURI().getPath()); } else { jobAttributes.setDestination(DestinationType.PRINTER); } PrintService serv = printerJob.getPrintService(); if (serv != null) { jobAttributes.setPrinter(serv.getName()); } PageRanges range = (PageRanges)attributes.get(PageRanges.class); int[][] members = range.getMembers(); jobAttributes.setPageRanges(members); SheetCollate collation = (SheetCollate)attributes.get(SheetCollate.class); if (collation == SheetCollate.COLLATED) { jobAttributes.setMultipleDocumentHandling( MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES); } else { jobAttributes.setMultipleDocumentHandling( MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES); } Sides sides = (Sides)attributes.get(Sides.class); if (sides == Sides.TWO_SIDED_LONG_EDGE) { jobAttributes.setSides(SidesType.TWO_SIDED_LONG_EDGE); } else if (sides == Sides.TWO_SIDED_SHORT_EDGE) { jobAttributes.setSides(SidesType.TWO_SIDED_SHORT_EDGE); } else { jobAttributes.setSides(SidesType.ONE_SIDED); } // PageAttributes Chromaticity color = (Chromaticity)attributes.get(Chromaticity.class); if (color == Chromaticity.COLOR) { pageAttributes.setColor(ColorType.COLOR); } else { pageAttributes.setColor(ColorType.MONOCHROME); } OrientationRequested orient = (OrientationRequested)attributes.get(OrientationRequested.class); if (orient == OrientationRequested.LANDSCAPE) { pageAttributes.setOrientationRequested( OrientationRequestedType.LANDSCAPE); } else { pageAttributes.setOrientationRequested( OrientationRequestedType.PORTRAIT); } PrintQuality qual = (PrintQuality)attributes.get(PrintQuality.class); if (qual == PrintQuality.DRAFT) { pageAttributes.setPrintQuality(PrintQualityType.DRAFT); } else if (qual == PrintQuality.HIGH) { pageAttributes.setPrintQuality(PrintQualityType.HIGH); } else { // NORMAL pageAttributes.setPrintQuality(PrintQualityType.NORMAL); } Media msn = (Media)attributes.get(Media.class); if (msn != null && msn instanceof MediaSizeName) { MediaType mType = unMapMedia((MediaSizeName)msn); if (mType != null) { pageAttributes.setMedia(mType); } } debugPrintAttributes(false, false); } private void debugPrintAttributes(boolean ja, boolean pa ) { if (ja) { System.out.println("new Attributes\ncopies = "+ jobAttributes.getCopies()+ "\nselection = "+ jobAttributes.getDefaultSelection()+ "\ndest "+jobAttributes.getDestination()+ "\nfile "+jobAttributes.getFileName()+ "\nfromPage "+jobAttributes.getFromPage()+ "\ntoPage "+jobAttributes.getToPage()+ "\ncollation "+ jobAttributes.getMultipleDocumentHandling()+ "\nPrinter "+jobAttributes.getPrinter()+ "\nSides2 "+jobAttributes.getSides() ); } if (pa) { System.out.println("new Attributes\ncolor = "+ pageAttributes.getColor()+ "\norientation = "+ pageAttributes.getOrientationRequested()+ "\nquality "+pageAttributes.getPrintQuality()+ "\nMedia2 "+pageAttributes.getMedia() ); } } /* From JobAttributes we will copy job name and duplex printing * and destination. * The majority of the rest of the attributes are reflected * attributes. * * From PageAttributes we copy color, media size, orientation, * origin type, resolution and print quality. * We use the media, orientation in creating the page format, and * the origin type to set its imageable area. * * REMIND: Interpretation of resolution, additional media sizes. */ private void copyAttributes(PrintService printServ) { attributes = new HashPrintRequestAttributeSet(); attributes.add(new JobName(docTitle, null)); PrintService pServ = printServ; String printerName = jobAttributes.getPrinter(); if (printerName != null && printerName != "" && !printerName.equals(pServ.getName())) { // Search for the given printerName in the list of PrintServices PrintService []services = PrinterJob.lookupPrintServices(); try { 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 = queue.remove(0); notify(); } else { try { wait(2000); } catch (InterruptedException e) { // do nothing. } } } return g; } synchronized boolean isClosed() { return queue == null; } } private static int[] getSize(MediaType mType) { int []dim = new int[2]; dim[0] = 612; dim[1] = 792; for (int i=0; i < SIZES.length; i++) { if (SIZES[i] == mType) { dim[0] = WIDTHS[i]; dim[1] = LENGTHS[i]; break; } } return dim; } public static MediaSizeName mapMedia(MediaType mType) { MediaSizeName media = null; // JAVAXSIZES.length and SIZES.length must be equal! // Attempt to recover by getting the smaller size. int length = Math.min(SIZES.length, JAVAXSIZES.length); for (int i=0; i < length; i++) { if (SIZES[i] == mType) { if ((JAVAXSIZES[i] != null) && MediaSize.getMediaSizeForName(JAVAXSIZES[i]) != null) { media = JAVAXSIZES[i]; break; } else { /* create Custom Media */ media = new CustomMediaSizeName(SIZES[i].toString()); float w = (float)Math.rint(WIDTHS[i] / 72.0); float h = (float)Math.rint(LENGTHS[i] / 72.0); if (w > 0.0 && h > 0.0) { // add new created MediaSize to our static map // so it will be found when we call findMedia new MediaSize(w, h, Size2DSyntax.INCH, media); } break; } } } return media; } public static MediaType unMapMedia(MediaSizeName mSize) { MediaType media = null; // JAVAXSIZES.length and SIZES.length must be equal! // Attempt to recover by getting the smaller size. int length = Math.min(SIZES.length, JAVAXSIZES.length); for (int i=0; i < length; i++) { if (JAVAXSIZES[i] == mSize) { if (SIZES[i] != null) { media = SIZES[i]; break; } } } return media; } private void translateInputProps() { if (props == null) { return; } String str; str = props.getProperty(DEST_PROP); if (str != null) { if (str.equals(PRINTER)) { jobAttributes.setDestination(DestinationType.PRINTER); } else if (str.equals(FILE)) { jobAttributes.setDestination(DestinationType.FILE); } } str = props.getProperty(PRINTER_PROP); if (str != null) { jobAttributes.setPrinter(str); } str = props.getProperty(FILENAME_PROP); if (str != null) { jobAttributes.setFileName(str); } str = props.getProperty(NUMCOPIES_PROP); if (str != null) { jobAttributes.setCopies(Integer.parseInt(str)); } this.options = props.getProperty(OPTIONS_PROP, ""); str = props.getProperty(ORIENT_PROP); if (str != null) { if (str.equals(PORTRAIT)) { pageAttributes.setOrientationRequested( OrientationRequestedType.PORTRAIT); } else if (str.equals(LANDSCAPE)) { pageAttributes.setOrientationRequested( OrientationRequestedType.LANDSCAPE); } } str = props.getProperty(PAPERSIZE_PROP); if (str != null) { if (str.equals(LETTER)) { pageAttributes.setMedia(SIZES[MediaType.LETTER.hashCode()]); } else if (str.equals(LEGAL)) { pageAttributes.setMedia(SIZES[MediaType.LEGAL.hashCode()]); } else if (str.equals(EXECUTIVE)) { pageAttributes.setMedia(SIZES[MediaType.EXECUTIVE.hashCode()]); } else if (str.equals(A4)) { pageAttributes.setMedia(SIZES[MediaType.A4.hashCode()]); } } } private void translateOutputProps() { if (props == null) { return; } String str; props.setProperty(DEST_PROP, (jobAttributes.getDestination() == DestinationType.PRINTER) ? PRINTER : FILE); str = jobAttributes.getPrinter(); if (str != null && !str.equals("")) { props.setProperty(PRINTER_PROP, str); } str = jobAttributes.getFileName(); if (str != null && !str.equals("")) { props.setProperty(FILENAME_PROP, str); } int copies = jobAttributes.getCopies(); if (copies > 0) { props.setProperty(NUMCOPIES_PROP, "" + copies); } str = this.options; if (str != null && !str.equals("")) { props.setProperty(OPTIONS_PROP, str); } props.setProperty(ORIENT_PROP, (pageAttributes.getOrientationRequested() == OrientationRequestedType.PORTRAIT) ? PORTRAIT : LANDSCAPE); MediaType media = SIZES[pageAttributes.getMedia().hashCode()]; if (media == MediaType.LETTER) { str = LETTER; } else if (media == MediaType.LEGAL) { str = LEGAL; } else if (media == MediaType.EXECUTIVE) { str = EXECUTIVE; } else if (media == MediaType.A4) { str = A4; } else { str = media.toString(); } props.setProperty(PAPERSIZE_PROP, str); } private void throwPrintToFile() { SecurityManager security = System.getSecurityManager(); FilePermission printToFilePermission = null; if (security != null) { if (printToFilePermission == null) { printToFilePermission = new FilePermission("<>", "read,write"); } security.checkPermission(printToFilePermission); } } }