1 /*
   2  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.print;
  27 
  28 import java.awt.Dimension;
  29 import java.awt.Frame;
  30 import java.awt.Graphics;
  31 import java.awt.Graphics2D;
  32 import java.awt.PrintJob;
  33 import java.awt.JobAttributes;
  34 import java.awt.JobAttributes.*;
  35 import java.awt.PageAttributes;
  36 import java.awt.PageAttributes.*;
  37 
  38 import java.awt.print.PageFormat;
  39 import java.awt.print.Paper;
  40 import java.awt.print.Printable;
  41 import java.awt.print.PrinterException;
  42 import java.awt.print.PrinterJob;
  43 
  44 import java.io.File;
  45 import java.io.FilePermission;
  46 import java.io.IOException;
  47 
  48 import java.net.URI;
  49 import java.net.URISyntaxException;
  50 
  51 import java.util.ArrayList;
  52 import java.util.Properties;
  53 
  54 import javax.print.PrintService;
  55 import javax.print.attribute.HashPrintRequestAttributeSet;
  56 import javax.print.attribute.PrintRequestAttributeSet;
  57 import javax.print.attribute.ResolutionSyntax;
  58 import javax.print.attribute.Size2DSyntax;
  59 import javax.print.attribute.standard.Chromaticity;
  60 import javax.print.attribute.standard.Copies;
  61 import javax.print.attribute.standard.Destination;
  62 import javax.print.attribute.standard.DialogTypeSelection;
  63 import javax.print.attribute.standard.JobName;
  64 import javax.print.attribute.standard.MediaSize;
  65 import javax.print.attribute.standard.PrintQuality;
  66 import javax.print.attribute.standard.PrinterResolution;
  67 import javax.print.attribute.standard.SheetCollate;
  68 import javax.print.attribute.standard.Sides;
  69 import javax.print.attribute.standard.Media;
  70 import javax.print.attribute.standard.OrientationRequested;
  71 import javax.print.attribute.standard.MediaSizeName;
  72 import javax.print.attribute.standard.PageRanges;
  73 
  74 import sun.print.SunPageSelection;
  75 import sun.print.SunMinMaxPage;
  76 
  77 /**
  78  * A class which initiates and executes a print job using
  79  * the underlying PrinterJob graphics conversions.
  80  *
  81  * @see Toolkit#getPrintJob
  82  *
  83  */
  84 public class PrintJob2D extends PrintJob implements Printable, Runnable {
  85 
  86     private static final MediaType SIZES[] = {
  87         MediaType.ISO_4A0, MediaType.ISO_2A0, MediaType.ISO_A0,
  88         MediaType.ISO_A1, MediaType.ISO_A2, MediaType.ISO_A3,
  89         MediaType.ISO_A4, MediaType.ISO_A5, MediaType.ISO_A6,
  90         MediaType.ISO_A7, MediaType.ISO_A8, MediaType.ISO_A9,
  91         MediaType.ISO_A10, MediaType.ISO_B0, MediaType.ISO_B1,
  92         MediaType.ISO_B2, MediaType.ISO_B3, MediaType.ISO_B4,
  93         MediaType.ISO_B5, MediaType.ISO_B6, MediaType.ISO_B7,
  94         MediaType.ISO_B8, MediaType.ISO_B9, MediaType.ISO_B10,
  95         MediaType.JIS_B0, MediaType.JIS_B1, MediaType.JIS_B2,
  96         MediaType.JIS_B3, MediaType.JIS_B4, MediaType.JIS_B5,
  97         MediaType.JIS_B6, MediaType.JIS_B7, MediaType.JIS_B8,
  98         MediaType.JIS_B9, MediaType.JIS_B10, MediaType.ISO_C0,
  99         MediaType.ISO_C1, MediaType.ISO_C2, MediaType.ISO_C3,
 100         MediaType.ISO_C4, MediaType.ISO_C5, MediaType.ISO_C6,
 101         MediaType.ISO_C7, MediaType.ISO_C8, MediaType.ISO_C9,
 102         MediaType.ISO_C10, MediaType.ISO_DESIGNATED_LONG,
 103         MediaType.EXECUTIVE, MediaType.FOLIO, MediaType.INVOICE,
 104         MediaType.LEDGER, MediaType.NA_LETTER, MediaType.NA_LEGAL,
 105         MediaType.QUARTO, MediaType.A, MediaType.B,
 106         MediaType.C, MediaType.D, MediaType.E,
 107         MediaType.NA_10X15_ENVELOPE, MediaType.NA_10X14_ENVELOPE,
 108         MediaType.NA_10X13_ENVELOPE, MediaType.NA_9X12_ENVELOPE,
 109         MediaType.NA_9X11_ENVELOPE, MediaType.NA_7X9_ENVELOPE,
 110         MediaType.NA_6X9_ENVELOPE, MediaType.NA_NUMBER_9_ENVELOPE,
 111         MediaType.NA_NUMBER_10_ENVELOPE, MediaType.NA_NUMBER_11_ENVELOPE,
 112         MediaType.NA_NUMBER_12_ENVELOPE, MediaType.NA_NUMBER_14_ENVELOPE,
 113         MediaType.INVITE_ENVELOPE, MediaType.ITALY_ENVELOPE,
 114         MediaType.MONARCH_ENVELOPE, MediaType.PERSONAL_ENVELOPE
 115     };
 116 
 117     /* This array maps the above array to the objects used by the
 118      * javax.print APIs
 119          */
 120     private static final MediaSizeName JAVAXSIZES[] = {
 121         null, null, MediaSizeName.ISO_A0,
 122         MediaSizeName.ISO_A1, MediaSizeName.ISO_A2, MediaSizeName.ISO_A3,
 123         MediaSizeName.ISO_A4, MediaSizeName.ISO_A5, MediaSizeName.ISO_A6,
 124         MediaSizeName.ISO_A7, MediaSizeName.ISO_A8, MediaSizeName.ISO_A9,
 125         MediaSizeName.ISO_A10, MediaSizeName.ISO_B0, MediaSizeName.ISO_B1,
 126         MediaSizeName.ISO_B2, MediaSizeName.ISO_B3, MediaSizeName.ISO_B4,
 127         MediaSizeName.ISO_B5,  MediaSizeName.ISO_B6, MediaSizeName.ISO_B7,
 128         MediaSizeName.ISO_B8, MediaSizeName.ISO_B9, MediaSizeName.ISO_B10,
 129         MediaSizeName.JIS_B0, MediaSizeName.JIS_B1, MediaSizeName.JIS_B2,
 130         MediaSizeName.JIS_B3, MediaSizeName.JIS_B4, MediaSizeName.JIS_B5,
 131         MediaSizeName.JIS_B6, MediaSizeName.JIS_B7, MediaSizeName.JIS_B8,
 132         MediaSizeName.JIS_B9, MediaSizeName.JIS_B10, MediaSizeName.ISO_C0,
 133         MediaSizeName.ISO_C1, MediaSizeName.ISO_C2, MediaSizeName.ISO_C3,
 134         MediaSizeName.ISO_C4, MediaSizeName.ISO_C5, MediaSizeName.ISO_C6,
 135         null, null, null, null,
 136         MediaSizeName.ISO_DESIGNATED_LONG, MediaSizeName.EXECUTIVE,
 137         MediaSizeName.FOLIO, MediaSizeName.INVOICE, MediaSizeName.LEDGER,
 138         MediaSizeName.NA_LETTER, MediaSizeName.NA_LEGAL,
 139         MediaSizeName.QUARTO, MediaSizeName.A, MediaSizeName.B,
 140         MediaSizeName.C, MediaSizeName.D, MediaSizeName.E,
 141         MediaSizeName.NA_10X15_ENVELOPE, MediaSizeName.NA_10X14_ENVELOPE,
 142         MediaSizeName.NA_10X13_ENVELOPE, MediaSizeName.NA_9X12_ENVELOPE,
 143         MediaSizeName.NA_9X11_ENVELOPE, MediaSizeName.NA_7X9_ENVELOPE,
 144         MediaSizeName.NA_6X9_ENVELOPE,
 145         MediaSizeName.NA_NUMBER_9_ENVELOPE,
 146         MediaSizeName.NA_NUMBER_10_ENVELOPE,
 147         MediaSizeName.NA_NUMBER_11_ENVELOPE,
 148         MediaSizeName.NA_NUMBER_12_ENVELOPE,
 149         MediaSizeName.NA_NUMBER_14_ENVELOPE,
 150         null, MediaSizeName.ITALY_ENVELOPE,
 151         MediaSizeName.MONARCH_ENVELOPE, MediaSizeName.PERSONAL_ENVELOPE,
 152     };
 153 
 154 
 155     // widths and lengths in PostScript points (1/72 in.)
 156     private static final int WIDTHS[] = {
 157         /*iso-4a0*/ 4768, /*iso-2a0*/ 3370, /*iso-a0*/ 2384, /*iso-a1*/ 1684,
 158         /*iso-a2*/ 1191, /*iso-a3*/ 842, /*iso-a4*/ 595, /*iso-a5*/ 420,
 159         /*iso-a6*/ 298, /*iso-a7*/ 210, /*iso-a8*/ 147, /*iso-a9*/ 105,
 160         /*iso-a10*/ 74, /*iso-b0*/ 2835, /*iso-b1*/ 2004, /*iso-b2*/ 1417,
 161         /*iso-b3*/ 1001, /*iso-b4*/ 709, /*iso-b5*/ 499, /*iso-b6*/ 354,
 162         /*iso-b7*/ 249, /*iso-b8*/ 176, /*iso-b9*/ 125, /*iso-b10*/ 88,
 163         /*jis-b0*/ 2920, /*jis-b1*/ 2064, /*jis-b2*/ 1460, /*jis-b3*/ 1032,
 164         /*jis-b4*/ 729, /*jis-b5*/ 516, /*jis-b6*/ 363, /*jis-b7*/ 258,
 165         /*jis-b8*/ 181, /*jis-b9*/ 128, /*jis-b10*/ 91, /*iso-c0*/ 2599,
 166         /*iso-c1*/ 1837, /*iso-c2*/ 1298, /*iso-c3*/ 918, /*iso-c4*/ 649,
 167         /*iso-c5*/ 459, /*iso-c6*/ 323, /*iso-c7*/ 230, /*iso-c8*/ 162,
 168         /*iso-c9*/ 113, /*iso-c10*/ 79, /*iso-designated-long*/ 312,
 169         /*executive*/ 522, /*folio*/ 612, /*invoice*/ 396, /*ledger*/ 792,
 170         /*na-letter*/ 612, /*na-legal*/ 612, /*quarto*/ 609, /*a*/ 612,
 171         /*b*/ 792, /*c*/ 1224, /*d*/ 1584, /*e*/ 2448,
 172         /*na-10x15-envelope*/ 720, /*na-10x14-envelope*/ 720,
 173         /*na-10x13-envelope*/ 720, /*na-9x12-envelope*/ 648,
 174         /*na-9x11-envelope*/ 648, /*na-7x9-envelope*/ 504,
 175         /*na-6x9-envelope*/ 432, /*na-number-9-envelope*/ 279,
 176         /*na-number-10-envelope*/ 297, /*na-number-11-envelope*/ 324,
 177         /*na-number-12-envelope*/ 342, /*na-number-14-envelope*/ 360,
 178         /*invite-envelope*/ 624, /*italy-envelope*/ 312,
 179         /*monarch-envelope*/ 279, /*personal-envelope*/ 261
 180     };
 181     private static final int LENGTHS[] = {
 182         /*iso-4a0*/ 6741, /*iso-2a0*/ 4768, /*iso-a0*/ 3370, /*iso-a1*/ 2384,
 183         /*iso-a2*/ 1684, /*iso-a3*/ 1191, /*iso-a4*/ 842, /*iso-a5*/ 595,
 184         /*iso-a6*/ 420, /*iso-a7*/ 298, /*iso-a8*/ 210, /*iso-a9*/ 147,
 185         /*iso-a10*/ 105, /*iso-b0*/ 4008, /*iso-b1*/ 2835, /*iso-b2*/ 2004,
 186         /*iso-b3*/ 1417, /*iso-b4*/ 1001, /*iso-b5*/ 729, /*iso-b6*/ 499,
 187         /*iso-b7*/ 354, /*iso-b8*/ 249, /*iso-b9*/ 176, /*iso-b10*/ 125,
 188         /*jis-b0*/ 4127, /*jis-b1*/ 2920, /*jis-b2*/ 2064, /*jis-b3*/ 1460,
 189         /*jis-b4*/ 1032, /*jis-b5*/ 729, /*jis-b6*/ 516, /*jis-b7*/ 363,
 190         /*jis-b8*/ 258, /*jis-b9*/ 181, /*jis-b10*/ 128, /*iso-c0*/ 3677,
 191         /*iso-c1*/ 2599, /*iso-c2*/ 1837, /*iso-c3*/ 1298, /*iso-c4*/ 918,
 192         /*iso-c5*/ 649, /*iso-c6*/ 459, /*iso-c7*/ 323, /*iso-c8*/ 230,
 193         /*iso-c9*/ 162, /*iso-c10*/ 113, /*iso-designated-long*/ 624,
 194         /*executive*/ 756, /*folio*/ 936, /*invoice*/ 612, /*ledger*/ 1224,
 195         /*na-letter*/ 792, /*na-legal*/ 1008, /*quarto*/ 780, /*a*/ 792,
 196         /*b*/ 1224, /*c*/ 1584, /*d*/ 2448, /*e*/ 3168,
 197         /*na-10x15-envelope*/ 1080, /*na-10x14-envelope*/ 1008,
 198         /*na-10x13-envelope*/ 936, /*na-9x12-envelope*/ 864,
 199         /*na-9x11-envelope*/ 792, /*na-7x9-envelope*/ 648,
 200         /*na-6x9-envelope*/ 648, /*na-number-9-envelope*/ 639,
 201         /*na-number-10-envelope*/ 684, /*na-number-11-envelope*/ 747,
 202         /*na-number-12-envelope*/ 792, /*na-number-14-envelope*/ 828,
 203         /*invite-envelope*/ 624, /*italy-envelope*/ 652,
 204         /*monarch-envelope*/ 540, /*personal-envelope*/ 468
 205     };
 206 
 207 
 208     private Frame frame;
 209     private String docTitle = "";
 210     private JobAttributes jobAttributes;
 211     private PageAttributes pageAttributes;
 212     private PrintRequestAttributeSet attributes;
 213 
 214     /*
 215      * Displays the native or cross-platform dialog and allows the
 216      * user to update job & page attributes
 217      */
 218 
 219     /**
 220      * The PrinterJob being uses to implement the PrintJob.
 221      */
 222     private PrinterJob printerJob;
 223 
 224     /**
 225      * The size of the page being used for the PrintJob.
 226      */
 227     private PageFormat pageFormat;
 228 
 229     /**
 230      * The PrinterJob and the application run on different
 231      * threads and communicate through a pair of message
 232      * queues. This queue is the list of Graphics that
 233      * the PrinterJob has requested rendering for, but
 234      * for which the application has not yet called getGraphics().
 235      * In practice the length of this message queue is always
 236      * 0 or 1.
 237      */
 238     private MessageQ graphicsToBeDrawn = new MessageQ("tobedrawn");
 239 
 240     /**
 241      * Used to communicate between the application's thread
 242      * and the PrinterJob's thread this message queue holds
 243      * the list of Graphics into which the application has
 244      * finished drawing, but that have not yet been returned
 245      * to the PrinterJob thread. Again, in practice, the
 246      * length of this message queue is always 0 or 1.
 247      */
 248     private MessageQ graphicsDrawn = new MessageQ("drawn");
 249 
 250     /**
 251      * The last Graphics returned to the application via
 252      * getGraphics. This is the Graphics into which the
 253      * application is currently drawing.
 254      */
 255     private Graphics2D currentGraphics;
 256 
 257     /**
 258      * The zero based index of the page currently being rendered
 259      * by the application.
 260      */
 261     private int pageIndex = -1;
 262 
 263     // The following Strings are maintained for backward-compatibility with
 264     // Properties based print control.
 265     private final static String DEST_PROP = "awt.print.destination";
 266     private final static String PRINTER = "printer";
 267     private final static String FILE = "file";
 268 
 269     private final static String PRINTER_PROP = "awt.print.printer";
 270 
 271     private final static String FILENAME_PROP = "awt.print.fileName";
 272 
 273     private final static String NUMCOPIES_PROP = "awt.print.numCopies";
 274 
 275     private final static String OPTIONS_PROP = "awt.print.options";
 276 
 277     private final static String ORIENT_PROP = "awt.print.orientation";
 278     private final static String PORTRAIT = "portrait";
 279     private final static String LANDSCAPE = "landscape";
 280 
 281     private final static String PAPERSIZE_PROP = "awt.print.paperSize";
 282     private final static String LETTER = "letter";
 283     private final static String LEGAL = "legal";
 284     private final static String EXECUTIVE = "executive";
 285     private final static String A4 = "a4";
 286 
 287     private Properties props;
 288 
 289     private String options = ""; // REMIND: needs implementation
 290 
 291     /**
 292      * The thread on which PrinterJob is running.
 293      * This is different than the applications thread.
 294      */
 295     private Thread printerJobThread;
 296 
 297     public PrintJob2D(Frame frame,  String doctitle,
 298                       final Properties props) {
 299         this.props = props;
 300         this.jobAttributes = new JobAttributes();
 301         this.pageAttributes = new PageAttributes();
 302         translateInputProps();
 303         initPrintJob2D(frame, doctitle,
 304                        this.jobAttributes, this.pageAttributes);
 305     }
 306 
 307     public PrintJob2D(Frame frame,  String doctitle,
 308                       JobAttributes jobAttributes,
 309                       PageAttributes pageAttributes) {
 310         initPrintJob2D(frame, doctitle, jobAttributes, pageAttributes);
 311     }
 312 
 313     private void initPrintJob2D(Frame frame,  String doctitle,
 314                                 JobAttributes jobAttributes,
 315                                 PageAttributes pageAttributes) {
 316 
 317         SecurityManager security = System.getSecurityManager();
 318         if (security != null) {
 319             security.checkPrintJobAccess();
 320         }
 321 
 322         if (frame == null &&
 323             (jobAttributes == null ||
 324              jobAttributes.getDialog() == DialogType.NATIVE)) {
 325             throw new NullPointerException("Frame must not be null");
 326         }
 327         this.frame = frame;
 328 
 329         this.docTitle = (doctitle == null) ? "" : doctitle;
 330         this.jobAttributes = (jobAttributes != null)
 331             ? jobAttributes : new JobAttributes();
 332         this.pageAttributes = (pageAttributes != null)
 333             ? pageAttributes : new PageAttributes();
 334 
 335         // Currently, we always reduce page ranges to xxx or xxx-xxx
 336         int[][] pageRanges = this.jobAttributes.getPageRanges();
 337         int first = pageRanges[0][0];
 338         int last = pageRanges[pageRanges.length - 1][1];
 339         this.jobAttributes.setPageRanges(new int[][] {
 340             new int[] { first, last }
 341         });
 342         this.jobAttributes.setToPage(last);
 343         this.jobAttributes.setFromPage(first);
 344 
 345 
 346         // Verify that the cross feed and feed resolutions are the same
 347         int[] res = this.pageAttributes.getPrinterResolution();
 348         if (res[0] != res[1]) {
 349             throw new IllegalArgumentException("Differing cross feed and feed"+
 350                                                " resolutions not supported.");
 351         }
 352 
 353         // Verify that the app has access to the file system
 354         DestinationType dest= this.jobAttributes.getDestination();
 355         if (dest == DestinationType.FILE) {
 356             throwPrintToFile();
 357 
 358             // check if given filename is valid
 359             String destStr = jobAttributes.getFileName();
 360             if ((destStr != null) &&
 361                 (jobAttributes.getDialog() == JobAttributes.DialogType.NONE)) {
 362 
 363                 File f = new File(destStr);
 364                 try {
 365                     // check if this is a new file and if filename chars are valid
 366                     // createNewFile returns false if file exists
 367                     if (f.createNewFile()) {
 368                         f.delete();
 369                     }
 370                 } catch (IOException ioe) {
 371                     throw new IllegalArgumentException("Cannot write to file:"+
 372                                                        destStr);
 373                 } catch (SecurityException se) {
 374                     //There is already file read/write access so at this point
 375                     // only delete access is denied.  Just ignore it because in
 376                     // most cases the file created in createNewFile gets overwritten
 377                     // anyway.
 378                 }
 379 
 380                  File pFile = f.getParentFile();
 381                  if ((f.exists() &&
 382                       (!f.isFile() || !f.canWrite())) ||
 383                      ((pFile != null) &&
 384                       (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) {
 385                      throw new IllegalArgumentException("Cannot write to file:"+
 386                                                         destStr);
 387                  }
 388             }
 389         }
 390     }
 391 
 392     public boolean printDialog() {
 393 
 394         boolean proceedWithPrint = false;
 395 
 396         printerJob = PrinterJob.getPrinterJob();
 397         if (printerJob == null) {
 398             return false;
 399         }
 400         DialogType d = this.jobAttributes.getDialog();
 401         PrintService pServ = printerJob.getPrintService();
 402         if ((pServ == null) &&  (d == DialogType.NONE)){
 403             return false;
 404         }
 405         copyAttributes(pServ);
 406 
 407         DefaultSelectionType select =
 408             this.jobAttributes.getDefaultSelection();
 409         if (select == DefaultSelectionType.RANGE) {
 410             attributes.add(SunPageSelection.RANGE);
 411         } else if (select == DefaultSelectionType.SELECTION) {
 412             attributes.add(SunPageSelection.SELECTION);
 413         } else {
 414             attributes.add(SunPageSelection.ALL);
 415         }
 416 
 417         if (frame != null) {
 418              attributes.add(new DialogOwner(frame));
 419          }
 420 
 421         if ( d == DialogType.NONE) {
 422             proceedWithPrint = true;
 423         } else {
 424             if (d == DialogType.NATIVE) {
 425                 attributes.add(DialogTypeSelection.NATIVE);
 426             }  else { //  (d == DialogType.COMMON)
 427                 attributes.add(DialogTypeSelection.COMMON);
 428             }
 429             if (proceedWithPrint = printerJob.printDialog(attributes)) {
 430                 if (pServ == null) {
 431                     // Windows gives an option to install a service
 432                     // when it detects there are no printers so
 433                     // we make sure we get the updated print service.
 434                     pServ = printerJob.getPrintService();
 435                     if (pServ == null) {
 436                         return false;
 437                     }
 438                 }
 439                 updateAttributes();
 440                 translateOutputProps();
 441             }
 442         }
 443 
 444         if (proceedWithPrint) {
 445 
 446             JobName jname = (JobName)attributes.get(JobName.class);
 447             if (jname != null) {
 448                 printerJob.setJobName(jname.toString());
 449             }
 450 
 451             pageFormat = new PageFormat();
 452 
 453             Media media = (Media)attributes.get(Media.class);
 454             MediaSize mediaSize =  null;
 455             if (media != null  && media instanceof MediaSizeName) {
 456                 mediaSize = MediaSize.getMediaSizeForName((MediaSizeName)media);
 457             }
 458 
 459             Paper p = pageFormat.getPaper();
 460             if (mediaSize != null) {
 461                 p.setSize(mediaSize.getX(MediaSize.INCH)*72.0,
 462                           mediaSize.getY(MediaSize.INCH)*72.0);
 463             }
 464 
 465             if (pageAttributes.getOrigin()==OriginType.PRINTABLE) {
 466                 // AWT uses 1/4" borders by default
 467                 p.setImageableArea(18.0, 18.0,
 468                                    p.getWidth()-36.0,
 469                                    p.getHeight()-36.0);
 470             } else {
 471                 p.setImageableArea(0.0,0.0,p.getWidth(),p.getHeight());
 472             }
 473 
 474             pageFormat.setPaper(p);
 475 
 476             OrientationRequested orient =
 477                (OrientationRequested)attributes.get(OrientationRequested.class);
 478             if (orient!= null &&
 479                 orient == OrientationRequested.REVERSE_LANDSCAPE) {
 480                 pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE);
 481             } else if (orient == OrientationRequested.LANDSCAPE) {
 482                 pageFormat.setOrientation(PageFormat.LANDSCAPE);
 483             } else {
 484                 pageFormat.setOrientation(PageFormat.PORTRAIT);
 485                 }
 486 
 487             printerJob.setPrintable(this, pageFormat);
 488 
 489         }
 490 
 491         return proceedWithPrint;
 492     }
 493 
 494     private void updateAttributes() {
 495         Copies c = (Copies)attributes.get(Copies.class);
 496         jobAttributes.setCopies(c.getValue());
 497 
 498         SunPageSelection sel =
 499             (SunPageSelection)attributes.get(SunPageSelection.class);
 500         if (sel == SunPageSelection.RANGE) {
 501             jobAttributes.setDefaultSelection(DefaultSelectionType.RANGE);
 502         } else if (sel == SunPageSelection.SELECTION) {
 503             jobAttributes.setDefaultSelection(DefaultSelectionType.SELECTION);
 504         } else {
 505             jobAttributes.setDefaultSelection(DefaultSelectionType.ALL);
 506         }
 507 
 508         Destination dest = (Destination)attributes.get(Destination.class);
 509         if (dest != null) {
 510             jobAttributes.setDestination(DestinationType.FILE);
 511             jobAttributes.setFileName(dest.getURI().getPath());
 512         } else {
 513             jobAttributes.setDestination(DestinationType.PRINTER);
 514         }
 515 
 516         PrintService serv = printerJob.getPrintService();
 517         if (serv != null) {
 518             jobAttributes.setPrinter(serv.getName());
 519         }
 520 
 521         PageRanges range = (PageRanges)attributes.get(PageRanges.class);
 522         int[][] members = range.getMembers();
 523         jobAttributes.setPageRanges(members);
 524 
 525         SheetCollate collation =
 526             (SheetCollate)attributes.get(SheetCollate.class);
 527         if (collation == SheetCollate.COLLATED) {
 528             jobAttributes.setMultipleDocumentHandling(
 529             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES);
 530         } else {
 531             jobAttributes.setMultipleDocumentHandling(
 532             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES);
 533         }
 534 
 535         Sides sides = (Sides)attributes.get(Sides.class);
 536         if (sides == Sides.TWO_SIDED_LONG_EDGE) {
 537             jobAttributes.setSides(SidesType.TWO_SIDED_LONG_EDGE);
 538         } else if (sides == Sides.TWO_SIDED_SHORT_EDGE) {
 539             jobAttributes.setSides(SidesType.TWO_SIDED_SHORT_EDGE);
 540         } else {
 541             jobAttributes.setSides(SidesType.ONE_SIDED);
 542         }
 543 
 544         // PageAttributes
 545 
 546         Chromaticity color =
 547             (Chromaticity)attributes.get(Chromaticity.class);
 548         if (color == Chromaticity.COLOR) {
 549             pageAttributes.setColor(ColorType.COLOR);
 550         } else {
 551             pageAttributes.setColor(ColorType.MONOCHROME);
 552         }
 553 
 554         OrientationRequested orient =
 555             (OrientationRequested)attributes.get(OrientationRequested.class);
 556         if (orient == OrientationRequested.LANDSCAPE) {
 557             pageAttributes.setOrientationRequested(
 558                                        OrientationRequestedType.LANDSCAPE);
 559         } else {
 560             pageAttributes.setOrientationRequested(
 561                                        OrientationRequestedType.PORTRAIT);
 562         }
 563 
 564         PrintQuality qual = (PrintQuality)attributes.get(PrintQuality.class);
 565         if (qual == PrintQuality.DRAFT) {
 566             pageAttributes.setPrintQuality(PrintQualityType.DRAFT);
 567         } else if (qual == PrintQuality.HIGH) {
 568             pageAttributes.setPrintQuality(PrintQualityType.HIGH);
 569         } else { // NORMAL
 570             pageAttributes.setPrintQuality(PrintQualityType.NORMAL);
 571         }
 572 
 573         Media msn = (Media)attributes.get(Media.class);
 574         if (msn != null && msn instanceof MediaSizeName) {
 575             MediaType mType = unMapMedia((MediaSizeName)msn);
 576 
 577             if (mType != null) {
 578                 pageAttributes.setMedia(mType);
 579             }
 580         }
 581         debugPrintAttributes(false, false);
 582     }
 583 
 584     private void debugPrintAttributes(boolean ja, boolean pa ) {
 585         if (ja) {
 586             System.out.println("new Attributes\ncopies = "+
 587                                jobAttributes.getCopies()+
 588                                "\nselection = "+
 589                                jobAttributes.getDefaultSelection()+
 590                                "\ndest "+jobAttributes.getDestination()+
 591                                "\nfile "+jobAttributes.getFileName()+
 592                                "\nfromPage "+jobAttributes.getFromPage()+
 593                                "\ntoPage "+jobAttributes.getToPage()+
 594                                "\ncollation "+
 595                                jobAttributes.getMultipleDocumentHandling()+
 596                                "\nPrinter "+jobAttributes.getPrinter()+
 597                                "\nSides2 "+jobAttributes.getSides()
 598                                );
 599         }
 600 
 601         if (pa) {
 602             System.out.println("new Attributes\ncolor = "+
 603                                pageAttributes.getColor()+
 604                                "\norientation = "+
 605                                pageAttributes.getOrientationRequested()+
 606                                "\nquality "+pageAttributes.getPrintQuality()+
 607                                "\nMedia2 "+pageAttributes.getMedia()
 608                                );
 609         }
 610     }
 611 
 612 
 613     /* From JobAttributes we will copy job name and duplex printing
 614      * and destination.
 615      * The majority of the rest of the attributes are reflected
 616      * attributes.
 617      *
 618      * From PageAttributes we copy color, media size, orientation,
 619      * origin type, resolution and print quality.
 620      * We use the media, orientation in creating the page format, and
 621      * the origin type to set its imageable area.
 622      *
 623      * REMIND: Interpretation of resolution, additional media sizes.
 624      */
 625     private void copyAttributes(PrintService printServ) {
 626 
 627         attributes = new HashPrintRequestAttributeSet();
 628         attributes.add(new JobName(docTitle, null));
 629         PrintService pServ = printServ;
 630 
 631         String printerName = jobAttributes.getPrinter();
 632         if (printerName != null && printerName != ""
 633             && !printerName.equals(pServ.getName())) {
 634 
 635             // Search for the given printerName in the list of PrintServices
 636             PrintService []services = PrinterJob.lookupPrintServices();
 637             try {
 638                 for (int i=0; i<services.length; i++) {
 639                     if (printerName.equals(services[i].getName())) {
 640                         printerJob.setPrintService(services[i]);
 641                         pServ = services[i];
 642                         break;
 643                     }
 644                 }
 645             } catch (PrinterException pe) {
 646             }
 647         }
 648 
 649         DestinationType dest = jobAttributes.getDestination();
 650         if (dest == DestinationType.FILE &&
 651             pServ.isAttributeCategorySupported(Destination.class)) {
 652 
 653             String fileName = jobAttributes.getFileName();
 654 
 655             Destination defaultDest;
 656             if (fileName == null && (defaultDest = (Destination)pServ.
 657                     getDefaultAttributeValue(Destination.class)) != null) {
 658                 attributes.add(defaultDest);
 659             } else {
 660                 URI uri = null;
 661                 try {
 662                     if (fileName != null) {
 663                         if (fileName.equals("")) {
 664                             fileName = ".";
 665                         }
 666                     } else {
 667                         // defaultDest should not be null.  The following code
 668                         // is only added to safeguard against a possible
 669                         // buggy implementation of a PrintService having a
 670                         // null default Destination.
 671                         fileName = "out.prn";
 672                     }
 673                     uri = (new File(fileName)).toURI();
 674                 } catch (SecurityException se) {
 675                     try {
 676                         // '\\' file separator is illegal character in opaque
 677                         // part and causes URISyntaxException, so we replace
 678                         // it with '/'
 679                         fileName = fileName.replace('\\', '/');
 680                         uri = new URI("file:"+fileName);
 681                     } catch (URISyntaxException e) {
 682                     }
 683                 }
 684                 if (uri != null) {
 685                     attributes.add(new Destination(uri));
 686                 }
 687             }
 688         }
 689         attributes.add(new SunMinMaxPage(jobAttributes.getMinPage(),
 690                                          jobAttributes.getMaxPage()));
 691         SidesType sType = jobAttributes.getSides();
 692         if (sType == SidesType.TWO_SIDED_LONG_EDGE) {
 693             attributes.add(Sides.TWO_SIDED_LONG_EDGE);
 694         } else if (sType == SidesType.TWO_SIDED_SHORT_EDGE) {
 695             attributes.add(Sides.TWO_SIDED_SHORT_EDGE);
 696         } else if (sType == SidesType.ONE_SIDED) {
 697             attributes.add(Sides.ONE_SIDED);
 698         }
 699 
 700         MultipleDocumentHandlingType hType =
 701           jobAttributes.getMultipleDocumentHandling();
 702         if (hType ==
 703             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES) {
 704           attributes.add(SheetCollate.COLLATED);
 705         } else {
 706           attributes.add(SheetCollate.UNCOLLATED);
 707         }
 708 
 709         attributes.add(new Copies(jobAttributes.getCopies()));
 710 
 711         attributes.add(new PageRanges(jobAttributes.getFromPage(),
 712                                       jobAttributes.getToPage()));
 713 
 714         if (pageAttributes.getColor() == ColorType.COLOR) {
 715             attributes.add(Chromaticity.COLOR);
 716         } else {
 717             attributes.add(Chromaticity.MONOCHROME);
 718         }
 719 
 720         pageFormat = printerJob.defaultPage();
 721         if (pageAttributes.getOrientationRequested() ==
 722             OrientationRequestedType.LANDSCAPE) {
 723             pageFormat.setOrientation(PageFormat.LANDSCAPE);
 724                 attributes.add(OrientationRequested.LANDSCAPE);
 725         } else {
 726                 pageFormat.setOrientation(PageFormat.PORTRAIT);
 727                 attributes.add(OrientationRequested.PORTRAIT);
 728         }
 729 
 730         MediaType media = pageAttributes.getMedia();
 731         MediaSizeName msn = mapMedia(media);
 732         if (msn != null) {
 733             attributes.add(msn);
 734         }
 735 
 736         PrintQualityType qType =
 737             pageAttributes.getPrintQuality();
 738         if (qType == PrintQualityType.DRAFT) {
 739             attributes.add(PrintQuality.DRAFT);
 740         } else if (qType == PrintQualityType.NORMAL) {
 741             attributes.add(PrintQuality.NORMAL);
 742         } else if (qType == PrintQualityType.HIGH) {
 743             attributes.add(PrintQuality.HIGH);
 744         }
 745     }
 746 
 747     /**
 748      * Gets a Graphics object that will draw to the next page.
 749      * The page is sent to the printer when the graphics
 750      * object is disposed.  This graphics object will also implement
 751      * the PrintGraphics interface.
 752      * @see PrintGraphics
 753      */
 754     public Graphics getGraphics() {
 755 
 756         Graphics printGraphics = null;
 757 
 758         synchronized (this) {
 759             ++pageIndex;
 760 
 761             // Thread should not be created after end has been called.
 762             // One way to detect this is if any of the graphics queue
 763             //  has been closed.
 764             if (pageIndex == 0 && !graphicsToBeDrawn.isClosed()) {
 765 
 766             /* We start a thread on which the PrinterJob will run.
 767              * The PrinterJob will ask for pages on that thread
 768              * and will use a message queue to fulfill the application's
 769              * requests for a Graphics on the application's
 770              * thread.
 771              */
 772 
 773                 startPrinterJobThread();
 774 
 775             }
 776             notify();
 777         }
 778 
 779         /* If the application has already been handed back
 780          * a graphics then we need to put that graphics into
 781          * the drawn queue so that the PrinterJob thread can
 782          * return to the print system.
 783          */
 784         if (currentGraphics != null) {
 785             graphicsDrawn.append(currentGraphics);
 786             currentGraphics = null;
 787         }
 788 
 789         /* We'll block here until a new graphics becomes
 790          * available.
 791          */
 792 
 793         currentGraphics = graphicsToBeDrawn.pop();
 794 
 795         if (currentGraphics instanceof PeekGraphics) {
 796             ( (PeekGraphics) currentGraphics).setAWTDrawingOnly();
 797             graphicsDrawn.append(currentGraphics);
 798             currentGraphics = graphicsToBeDrawn.pop();
 799         }
 800 
 801 
 802         if (currentGraphics != null) {
 803 
 804             /* In the PrintJob API, the origin is at the upper-
 805              * left of the imageable area when using the new "printable"
 806              * origin attribute, otherwise its the physical origin (for
 807              * backwards compatibility. We emulate this by createing
 808              * a PageFormat which matches and then performing the
 809              * translate to the origin. This is a no-op if physical
 810              * origin is specified.
 811              */
 812             currentGraphics.translate(pageFormat.getImageableX(),
 813                                       pageFormat.getImageableY());
 814 
 815             /* Scale to accommodate AWT's notion of printer resolution */
 816             double awtScale = 72.0/getPageResolutionInternal();
 817             currentGraphics.scale(awtScale, awtScale);
 818 
 819             /* The caller wants a Graphics instance but we do
 820              * not want them to make 2D calls. We can't hand
 821              * back a Graphics2D. The returned Graphics also
 822              * needs to implement PrintGraphics, so we wrap
 823              * the Graphics2D instance. The PrintJob API has
 824              * the application dispose of the Graphics so
 825              * we create a copy of the one returned by PrinterJob.
 826              */
 827             printGraphics = new ProxyPrintGraphics(currentGraphics.create(),
 828                                                    this);
 829 
 830         }
 831 
 832         return printGraphics;
 833     }
 834 
 835     /**
 836      * Returns the dimensions of the page in pixels.
 837      * The resolution of the page is chosen so that it
 838      * is similar to the screen resolution.
 839      * Except (since 1.3) when the application specifies a resolution.
 840      * In that case it it scaled accordingly.
 841      */
 842     public Dimension getPageDimension() {
 843         double wid, hgt, scale;
 844         if (pageAttributes != null &&
 845             pageAttributes.getOrigin()==OriginType.PRINTABLE) {
 846             wid = pageFormat.getImageableWidth();
 847             hgt = pageFormat.getImageableHeight();
 848         } else {
 849             wid = pageFormat.getWidth();
 850             hgt = pageFormat.getHeight();
 851         }
 852         scale = getPageResolutionInternal() / 72.0;
 853         return new Dimension((int)(wid * scale), (int)(hgt * scale));
 854     }
 855 
 856      private double getPageResolutionInternal() {
 857         if (pageAttributes != null) {
 858             int []res = pageAttributes.getPrinterResolution();
 859             if (res[2] == 3) {
 860                 return res[0];
 861             } else /* if (res[2] == 4) */ {
 862                 return (res[0] * 2.54);
 863             }
 864         } else {
 865             return 72.0;
 866         }
 867     }
 868 
 869     /**
 870      * Returns the resolution of the page in pixels per inch.
 871      * Note that this doesn't have to correspond to the physical
 872      * resolution of the printer.
 873      */
 874     public int getPageResolution() {
 875         return (int)getPageResolutionInternal();
 876     }
 877 
 878     /**
 879      * Returns true if the last page will be printed first.
 880      */
 881     public boolean lastPageFirst() {
 882         return false;
 883     }
 884 
 885     /**
 886      * Ends the print job and does any necessary cleanup.
 887      */
 888     public synchronized void end() {
 889 
 890         /* Prevent the PrinterJob thread from appending any more
 891          * graphics to the to-be-drawn queue
 892          */
 893         graphicsToBeDrawn.close();
 894 
 895         /* If we have a currentGraphics it was the last one returned to the
 896          * PrintJob client. Append it to the drawn queue so that print()
 897          * will return allowing the page to be flushed.
 898          * This really ought to happen in dispose() but for whatever reason
 899          * that isn't how the old PrintJob worked even though its spec
 900          * said dispose() flushed the page.
 901          */
 902         if (currentGraphics != null) {
 903             graphicsDrawn.append(currentGraphics);
 904         }
 905         graphicsDrawn.closeWhenEmpty();
 906 
 907         /* Wait for the PrinterJob.print() thread to terminate, ensuring
 908          * that RasterPrinterJob has made its end doc call, and resources
 909          * are released, files closed etc.
 910          */
 911         if( printerJobThread != null && printerJobThread.isAlive() ){
 912             try {
 913                 printerJobThread.join();
 914             } catch (InterruptedException e) {
 915             }
 916         }
 917     }
 918 
 919     /**
 920      * Ends this print job once it is no longer referenced.
 921      * @see #end
 922      */
 923     public void finalize() {
 924         end();
 925     }
 926 
 927     /**
 928      * Prints the page at the specified index into the specified
 929      * {@link Graphics} context in the specified
 930      * format.  A <code>PrinterJob</code> calls the
 931      * <code>Printable</code> interface to request that a page be
 932      * rendered into the context specified by
 933      * <code>graphics</code>.  The format of the page to be drawn is
 934      * specified by <code>pageFormat</code>.  The zero based index
 935      * of the requested page is specified by <code>pageIndex</code>.
 936      * If the requested page does not exist then this method returns
 937      * NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned.
 938      * The <code>Graphics</code> class or subclass implements the
 939      * {@link PrinterGraphics} interface to provide additional
 940      * information.  If the <code>Printable</code> object
 941      * aborts the print job then it throws a {@link PrinterException}.
 942      * @param graphics the context into which the page is drawn
 943      * @param pageFormat the size and orientation of the page being drawn
 944      * @param pageIndex the zero based index of the page to be drawn
 945      * @return PAGE_EXISTS if the page is rendered successfully
 946      *         or NO_SUCH_PAGE if <code>pageIndex</code> specifies a
 947      *         non-existent page.
 948      * @exception java.awt.print.PrinterException
 949      *         thrown when the print job is terminated.
 950      */
 951     public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
 952                  throws PrinterException {
 953 
 954         int result;
 955 
 956         /* This method will be called by the PrinterJob on a thread other
 957          * that the application's thread. We hold on to the graphics
 958          * until we can rendevous with the application's thread and
 959          * hand over the graphics. The application then does all the
 960          * drawing. When the application is done drawing we rendevous
 961          * again with the PrinterJob thread and release the Graphics
 962          * so that it knows we are done.
 963          */
 964 
 965         /* Add the graphics to the message queue of graphics to
 966          * be rendered. This is really a one slot queue. The
 967          * application's thread will come along and remove the
 968          * graphics from the queue when the app asks for a graphics.
 969          */
 970         graphicsToBeDrawn.append( (Graphics2D) graphics);
 971 
 972         /* We now wait for the app's thread to finish drawing on
 973          * the Graphics. This thread will sleep until the application
 974          * release the graphics by placing it in the graphics drawn
 975          * message queue. If the application signals that it is
 976          * finished drawing the entire document then we'll get null
 977          * returned when we try and pop a finished graphic.
 978          */
 979         if (graphicsDrawn.pop() != null) {
 980             result = PAGE_EXISTS;
 981         } else {
 982             result = NO_SUCH_PAGE;
 983         }
 984 
 985         return result;
 986     }
 987 
 988     private void startPrinterJobThread() {
 989 
 990         printerJobThread = new Thread(this, "printerJobThread");
 991         printerJobThread.start();
 992     }
 993 
 994 
 995     public void run() {
 996 
 997         try {
 998             printerJob.print(attributes);
 999         } catch (PrinterException e) {
1000             //REMIND: need to store this away and not rethrow it.
1001         }
1002 
1003         /* Close the message queues so that nobody is stuck
1004          * waiting for one.
1005          */
1006         graphicsToBeDrawn.closeWhenEmpty();
1007         graphicsDrawn.close();
1008     }
1009 
1010     private class MessageQ {
1011 
1012         private String qid="noname";
1013 
1014         private ArrayList queue = new ArrayList();
1015 
1016         MessageQ(String id) {
1017           qid = id;
1018         }
1019 
1020         synchronized void closeWhenEmpty() {
1021 
1022             while (queue != null && queue.size() > 0) {
1023                 try {
1024                     wait(1000);
1025                 } catch (InterruptedException e) {
1026                     // do nothing.
1027                 }
1028             }
1029 
1030             queue = null;
1031             notifyAll();
1032         }
1033 
1034         synchronized void close() {
1035             queue = null;
1036             notifyAll();
1037         }
1038 
1039         synchronized boolean append(Graphics2D g) {
1040 
1041             boolean queued = false;
1042 
1043             if (queue != null) {
1044                 queue.add(g);
1045                 queued = true;
1046                 notify();
1047             }
1048 
1049             return queued;
1050         }
1051 
1052         synchronized Graphics2D pop() {
1053             Graphics2D g = null;
1054 
1055             while (g == null && queue != null) {
1056 
1057                 if (queue.size() > 0) {
1058                     g = (Graphics2D) queue.remove(0);
1059                     notify();
1060 
1061                 } else {
1062                     try {
1063                         wait(2000);
1064                     } catch (InterruptedException e) {
1065                         // do nothing.
1066                     }
1067                 }
1068             }
1069 
1070             return g;
1071         }
1072 
1073         synchronized boolean isClosed() {
1074             return queue == null;
1075         }
1076 
1077     }
1078 
1079 
1080     private static int[] getSize(MediaType mType) {
1081         int []dim = new int[2];
1082         dim[0] = 612;
1083         dim[1] = 792;
1084 
1085         for (int i=0; i < SIZES.length; i++) {
1086             if (SIZES[i] == mType) {
1087                 dim[0] = WIDTHS[i];
1088                 dim[1] = LENGTHS[i];
1089                 break;
1090             }
1091         }
1092         return dim;
1093     }
1094 
1095     public static MediaSizeName mapMedia(MediaType mType) {
1096         MediaSizeName media = null;
1097 
1098         // JAVAXSIZES.length and SIZES.length must be equal!
1099         // Attempt to recover by getting the smaller size.
1100         int length = Math.min(SIZES.length, JAVAXSIZES.length);
1101 
1102         for (int i=0; i < length; i++) {
1103             if (SIZES[i] == mType) {
1104                 if ((JAVAXSIZES[i] != null) &&
1105                     MediaSize.getMediaSizeForName(JAVAXSIZES[i]) != null) {
1106                     media = JAVAXSIZES[i];
1107                     break;
1108                 } else {
1109                     /* create Custom Media */
1110                     media = new CustomMediaSizeName(SIZES[i].toString());
1111 
1112                     float w = (float)Math.rint(WIDTHS[i]  / 72.0);
1113                     float h = (float)Math.rint(LENGTHS[i] / 72.0);
1114                     if (w > 0.0 && h > 0.0) {
1115                         // add new created MediaSize to our static map
1116                         // so it will be found when we call findMedia
1117                         new MediaSize(w, h, Size2DSyntax.INCH, media);
1118                     }
1119 
1120                     break;
1121                 }
1122             }
1123         }
1124         return media;
1125     }
1126 
1127 
1128     public static MediaType unMapMedia(MediaSizeName mSize) {
1129         MediaType media = null;
1130 
1131         // JAVAXSIZES.length and SIZES.length must be equal!
1132         // Attempt to recover by getting the smaller size.
1133         int length = Math.min(SIZES.length, JAVAXSIZES.length);
1134 
1135         for (int i=0; i < length; i++) {
1136             if (JAVAXSIZES[i] == mSize) {
1137                 if (SIZES[i] != null) {
1138                     media = SIZES[i];
1139                     break;
1140                 }
1141             }
1142         }
1143         return media;
1144     }
1145 
1146     private void translateInputProps() {
1147         if (props == null) {
1148             return;
1149         }
1150 
1151         String str;
1152 
1153         str = props.getProperty(DEST_PROP);
1154         if (str != null) {
1155             if (str.equals(PRINTER)) {
1156                 jobAttributes.setDestination(DestinationType.PRINTER);
1157             } else if (str.equals(FILE)) {
1158                 jobAttributes.setDestination(DestinationType.FILE);
1159             }
1160         }
1161         str = props.getProperty(PRINTER_PROP);
1162         if (str != null) {
1163             jobAttributes.setPrinter(str);
1164         }
1165         str = props.getProperty(FILENAME_PROP);
1166         if (str != null) {
1167             jobAttributes.setFileName(str);
1168         }
1169         str = props.getProperty(NUMCOPIES_PROP);
1170         if (str != null) {
1171             jobAttributes.setCopies(Integer.parseInt(str));
1172         }
1173 
1174         this.options = props.getProperty(OPTIONS_PROP, "");
1175 
1176         str = props.getProperty(ORIENT_PROP);
1177         if (str != null) {
1178             if (str.equals(PORTRAIT)) {
1179                 pageAttributes.setOrientationRequested(
1180                                         OrientationRequestedType.PORTRAIT);
1181             } else if (str.equals(LANDSCAPE)) {
1182                 pageAttributes.setOrientationRequested(
1183                                         OrientationRequestedType.LANDSCAPE);
1184             }
1185         }
1186         str = props.getProperty(PAPERSIZE_PROP);
1187         if (str != null) {
1188             if (str.equals(LETTER)) {
1189                 pageAttributes.setMedia(SIZES[MediaType.LETTER.hashCode()]);
1190             } else if (str.equals(LEGAL)) {
1191                 pageAttributes.setMedia(SIZES[MediaType.LEGAL.hashCode()]);
1192             } else if (str.equals(EXECUTIVE)) {
1193                 pageAttributes.setMedia(SIZES[MediaType.EXECUTIVE.hashCode()]);
1194             } else if (str.equals(A4)) {
1195                 pageAttributes.setMedia(SIZES[MediaType.A4.hashCode()]);
1196             }
1197         }
1198     }
1199 
1200     private void translateOutputProps() {
1201         if (props == null) {
1202             return;
1203         }
1204 
1205         String str;
1206 
1207         props.setProperty(DEST_PROP,
1208             (jobAttributes.getDestination() == DestinationType.PRINTER) ?
1209                           PRINTER : FILE);
1210         str = jobAttributes.getPrinter();
1211         if (str != null && !str.equals("")) {
1212             props.setProperty(PRINTER_PROP, str);
1213         }
1214         str = jobAttributes.getFileName();
1215         if (str != null && !str.equals("")) {
1216             props.setProperty(FILENAME_PROP, str);
1217         }
1218         int copies = jobAttributes.getCopies();
1219         if (copies > 0) {
1220             props.setProperty(NUMCOPIES_PROP, "" + copies);
1221         }
1222         str = this.options;
1223         if (str != null && !str.equals("")) {
1224             props.setProperty(OPTIONS_PROP, str);
1225         }
1226         props.setProperty(ORIENT_PROP,
1227             (pageAttributes.getOrientationRequested() ==
1228              OrientationRequestedType.PORTRAIT)
1229                           ? PORTRAIT : LANDSCAPE);
1230         MediaType media = SIZES[pageAttributes.getMedia().hashCode()];
1231         if (media == MediaType.LETTER) {
1232             str = LETTER;
1233         } else if (media == MediaType.LEGAL) {
1234             str = LEGAL;
1235         } else if (media == MediaType.EXECUTIVE) {
1236             str = EXECUTIVE;
1237         } else if (media == MediaType.A4) {
1238             str = A4;
1239         } else {
1240             str = media.toString();
1241         }
1242         props.setProperty(PAPERSIZE_PROP, str);
1243     }
1244 
1245     private void throwPrintToFile() {
1246         SecurityManager security = System.getSecurityManager();
1247         FilePermission printToFilePermission = null;
1248         if (security != null) {
1249             if (printToFilePermission == null) {
1250                 printToFilePermission =
1251                     new FilePermission("<<ALL FILES>>", "read,write");
1252             }
1253             security.checkPermission(printToFilePermission);
1254         }
1255     }
1256 
1257 }