1 /* 2 * Copyright (c) 1997, 2014, 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 java.awt.print; 27 28 import java.awt.AWTError; 29 import java.awt.HeadlessException; 30 import java.util.Enumeration; 31 32 import javax.print.DocFlavor; 33 import javax.print.PrintService; 34 import javax.print.PrintServiceLookup; 35 import javax.print.StreamPrintServiceFactory; 36 import javax.print.attribute.PrintRequestAttributeSet; 37 import javax.print.attribute.standard.Media; 38 import javax.print.attribute.standard.MediaPrintableArea; 39 import javax.print.attribute.standard.MediaSize; 40 import javax.print.attribute.standard.MediaSizeName; 41 import javax.print.attribute.standard.OrientationRequested; 42 43 import sun.security.action.GetPropertyAction; 44 45 /** 46 * The {@code PrinterJob} class is the principal class that controls 47 * printing. An application calls methods in this class to set up a job, 48 * optionally to invoke a print dialog with the user, and then to print 49 * the pages of the job. 50 */ 51 public abstract class PrinterJob { 52 53 /* Public Class Methods */ 54 55 /** 56 * Creates and returns a {@code PrinterJob} which is initially 57 * associated with the default printer. 58 * If no printers are available on the system, a PrinterJob will still 59 * be returned from this method, but {@code getPrintService()} 60 * will return {@code null}, and calling 61 * {@link #print() print} with this {@code PrinterJob} might 62 * generate an exception. Applications that need to determine if 63 * there are suitable printers before creating a {@code PrinterJob} 64 * should ensure that the array returned from 65 * {@link #lookupPrintServices() lookupPrintServices} is not empty. 66 * @return a new {@code PrinterJob}. 67 * 68 * @throws SecurityException if a security manager exists and its 69 * {@link java.lang.SecurityManager#checkPrintJobAccess} 70 * method disallows this thread from creating a print job request 71 */ 72 public static PrinterJob getPrinterJob() { 73 SecurityManager security = System.getSecurityManager(); 74 if (security != null) { 75 security.checkPrintJobAccess(); 76 } 77 return java.security.AccessController.doPrivileged( 78 new java.security.PrivilegedAction<PrinterJob>() { 79 public PrinterJob run() { 80 String nm = System.getProperty("java.awt.printerjob", null); 81 try { 82 return (PrinterJob)Class.forName(nm). 83 getConstructor().newInstance(); 84 } catch (ClassNotFoundException e) { 85 throw new AWTError("PrinterJob not found: " + nm); 86 } catch (ReflectiveOperationException e) { 87 throw new AWTError("Could not instantiate PrinterJob: " + nm); 88 } 89 } 90 }); 91 } 92 93 /** 94 * A convenience method which looks up 2D print services. 95 * Services returned from this method may be installed on 96 * {@code PrinterJob}s which support print services. 97 * Calling this method is equivalent to calling 98 * {@link javax.print.PrintServiceLookup#lookupPrintServices( 99 * DocFlavor, AttributeSet) 100 * PrintServiceLookup.lookupPrintServices()} 101 * and specifying a Pageable DocFlavor. 102 * @return a possibly empty array of 2D print services. 103 * @since 1.4 104 */ 105 public static PrintService[] lookupPrintServices() { 106 return PrintServiceLookup. 107 lookupPrintServices(DocFlavor.SERVICE_FORMATTED.PAGEABLE, null); 108 } 109 110 111 /** 112 * A convenience method which locates factories for stream print 113 * services which can image 2D graphics. 114 * Sample usage : 115 * <pre>{@code 116 * FileOutputStream outstream; 117 * StreamPrintService psPrinter; 118 * String psMimeType = "application/postscript"; 119 * PrinterJob pj = PrinterJob.getPrinterJob(); 120 * 121 * StreamPrintServiceFactory[] factories = 122 * PrinterJob.lookupStreamPrintServices(psMimeType); 123 * if (factories.length > 0) { 124 * try { 125 * outstream = new File("out.ps"); 126 * psPrinter = factories[0].getPrintService(outstream); 127 * // psPrinter can now be set as the service on a PrinterJob 128 * pj.setPrintService(psPrinter) 129 * } catch (Exception e) { 130 * e.printStackTrace(); 131 * } 132 * } 133 * }</pre> 134 * Services returned from this method may be installed on 135 * {@code PrinterJob} instances which support print services. 136 * Calling this method is equivalent to calling 137 * {@link javax.print.StreamPrintServiceFactory#lookupStreamPrintServiceFactories(DocFlavor, String) 138 * StreamPrintServiceFactory.lookupStreamPrintServiceFactories() 139 * } and specifying a Pageable DocFlavor. 140 * 141 * @param mimeType the required output format, or null to mean any format. 142 * @return a possibly empty array of 2D stream print service factories. 143 * @since 1.4 144 */ 145 public static StreamPrintServiceFactory[] 146 lookupStreamPrintServices(String mimeType) { 147 return StreamPrintServiceFactory.lookupStreamPrintServiceFactories( 148 DocFlavor.SERVICE_FORMATTED.PAGEABLE, 149 mimeType); 150 } 151 152 153 /* Public Methods */ 154 155 /** 156 * A {@code PrinterJob} object should be created using the 157 * static {@link #getPrinterJob() getPrinterJob} method. 158 */ 159 public PrinterJob() { 160 } 161 162 /** 163 * Returns the service (printer) for this printer job. 164 * Implementations of this class which do not support print services 165 * may return null. null will also be returned if no printers are 166 * available. 167 * @return the service for this printer job. 168 * @see #setPrintService(PrintService) 169 * @see #getPrinterJob() 170 * @since 1.4 171 */ 172 public PrintService getPrintService() { 173 return null; 174 } 175 176 /** 177 * Associate this PrinterJob with a new PrintService. 178 * This method is overridden by subclasses which support 179 * specifying a Print Service. 180 * 181 * Throws {@code PrinterException} if the specified service 182 * cannot support the {@code Pageable} and 183 * {@code Printable} interfaces necessary to support 2D printing. 184 * @param service a print service that supports 2D printing 185 * @exception PrinterException if the specified service does not support 186 * 2D printing, or this PrinterJob class does not support 187 * setting a 2D print service, or the specified service is 188 * otherwise not a valid print service. 189 * @see #getPrintService 190 * @since 1.4 191 */ 192 public void setPrintService(PrintService service) 193 throws PrinterException { 194 throw new PrinterException( 195 "Setting a service is not supported on this class"); 196 } 197 198 /** 199 * Calls {@code painter} to render the pages. The pages in the 200 * document to be printed by this 201 * {@code PrinterJob} are rendered by the {@link Printable} 202 * object, {@code painter}. The {@link PageFormat} for each page 203 * is the default page format. 204 * @param painter the {@code Printable} that renders each page of 205 * the document. 206 */ 207 public abstract void setPrintable(Printable painter); 208 209 /** 210 * Calls {@code painter} to render the pages in the specified 211 * {@code format}. The pages in the document to be printed by 212 * this {@code PrinterJob} are rendered by the 213 * {@code Printable} object, {@code painter}. The 214 * {@code PageFormat} of each page is {@code format}. 215 * @param painter the {@code Printable} called to render 216 * each page of the document 217 * @param format the size and orientation of each page to 218 * be printed 219 */ 220 public abstract void setPrintable(Printable painter, PageFormat format); 221 222 /** 223 * Queries {@code document} for the number of pages and 224 * the {@code PageFormat} and {@code Printable} for each 225 * page held in the {@code Pageable} instance, 226 * {@code document}. 227 * @param document the pages to be printed. It can not be 228 * {@code null}. 229 * @exception NullPointerException the {@code Pageable} passed in 230 * was {@code null}. 231 * @see PageFormat 232 * @see Printable 233 */ 234 public abstract void setPageable(Pageable document) 235 throws NullPointerException; 236 237 /** 238 * Presents a dialog to the user for changing the properties of 239 * the print job. 240 * This method will display a native dialog if a native print 241 * service is selected, and user choice of printers will be restricted 242 * to these native print services. 243 * To present the cross platform print dialog for all services, 244 * including native ones instead use 245 * {@code printDialog(PrintRequestAttributeSet)}. 246 * <p> 247 * PrinterJob implementations which can use PrintService's will update 248 * the PrintService for this PrinterJob to reflect the new service 249 * selected by the user. 250 * @return {@code true} if the user does not cancel the dialog; 251 * {@code false} otherwise. 252 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 253 * returns true. 254 * @see java.awt.GraphicsEnvironment#isHeadless 255 */ 256 public abstract boolean printDialog() throws HeadlessException; 257 258 /** 259 * A convenience method which displays a cross-platform print dialog 260 * for all services which are capable of printing 2D graphics using the 261 * {@code Pageable} interface. The selected printer when the 262 * dialog is initially displayed will reflect the print service currently 263 * attached to this print job. 264 * If the user changes the print service, the PrinterJob will be 265 * updated to reflect this, unless the user cancels the dialog. 266 * As well as allowing the user to select the destination printer, 267 * the user can also select values of various print request attributes. 268 * <p> 269 * The attributes parameter on input will reflect the applications 270 * required initial selections in the user dialog. Attributes not 271 * specified display using the default for the service. On return it 272 * will reflect the user's choices. Selections may be updated by 273 * the implementation to be consistent with the supported values 274 * for the currently selected print service. 275 * <p> 276 * As the user scrolls to a new print service selection, the values 277 * copied are based on the settings for the previous service, together 278 * with any user changes. The values are not based on the original 279 * settings supplied by the client. 280 * <p> 281 * With the exception of selected printer, the PrinterJob state is 282 * not updated to reflect the user's changes. 283 * For the selections to affect a printer job, the attributes must 284 * be specified in the call to the 285 * {@code print(PrintRequestAttributeSet)} method. If using 286 * the Pageable interface, clients which intend to use media selected 287 * by the user must create a PageFormat derived from the user's 288 * selections. 289 * If the user cancels the dialog, the attributes will not reflect 290 * any changes made by the user. 291 * @param attributes on input is application supplied attributes, 292 * on output the contents are updated to reflect user choices. 293 * This parameter may not be null. 294 * @return {@code true} if the user does not cancel the dialog; 295 * {@code false} otherwise. 296 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 297 * returns true. 298 * @exception NullPointerException if {@code attributes} parameter 299 * is null. 300 * @see java.awt.GraphicsEnvironment#isHeadless 301 * @since 1.4 302 * 303 */ 304 public boolean printDialog(PrintRequestAttributeSet attributes) 305 throws HeadlessException { 306 307 if (attributes == null) { 308 throw new NullPointerException("attributes"); 309 } 310 return printDialog(); 311 } 312 313 /** 314 * Displays a dialog that allows modification of a 315 * {@code PageFormat} instance. 316 * The {@code page} argument is used to initialize controls 317 * in the page setup dialog. 318 * If the user cancels the dialog then this method returns the 319 * original {@code page} object unmodified. 320 * If the user okays the dialog then this method returns a new 321 * {@code PageFormat} object with the indicated changes. 322 * In either case, the original {@code page} object is 323 * not modified. 324 * @param page the default {@code PageFormat} presented to the 325 * user for modification 326 * @return the original {@code page} object if the dialog 327 * is cancelled; a new {@code PageFormat} object 328 * containing the format indicated by the user if the 329 * dialog is acknowledged. 330 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 331 * returns true. 332 * @see java.awt.GraphicsEnvironment#isHeadless 333 * @since 1.2 334 */ 335 public abstract PageFormat pageDialog(PageFormat page) 336 throws HeadlessException; 337 338 /** 339 * A convenience method which displays a cross-platform page setup dialog. 340 * The choices available will reflect the print service currently 341 * set on this PrinterJob. 342 * <p> 343 * The attributes parameter on input will reflect the client's 344 * required initial selections in the user dialog. Attributes which are 345 * not specified display using the default for the service. On return it 346 * will reflect the user's choices. Selections may be updated by 347 * the implementation to be consistent with the supported values 348 * for the currently selected print service. 349 * <p> 350 * The return value will be a PageFormat equivalent to the 351 * selections in the PrintRequestAttributeSet. 352 * If the user cancels the dialog, the attributes will not reflect 353 * any changes made by the user, and the return value will be null. 354 * @param attributes on input is application supplied attributes, 355 * on output the contents are updated to reflect user choices. 356 * This parameter may not be null. 357 * @return a page format if the user does not cancel the dialog; 358 * {@code null} otherwise. 359 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 360 * returns true. 361 * @exception NullPointerException if {@code attributes} parameter 362 * is null. 363 * @see java.awt.GraphicsEnvironment#isHeadless 364 * @since 1.4 365 * 366 */ 367 public PageFormat pageDialog(PrintRequestAttributeSet attributes) 368 throws HeadlessException { 369 370 if (attributes == null) { 371 throw new NullPointerException("attributes"); 372 } 373 return pageDialog(defaultPage()); 374 } 375 376 /** 377 * Clones the {@code PageFormat} argument and alters the 378 * clone to describe a default page size and orientation. 379 * @param page the {@code PageFormat} to be cloned and altered 380 * @return clone of {@code page}, altered to describe a default 381 * {@code PageFormat}. 382 */ 383 public abstract PageFormat defaultPage(PageFormat page); 384 385 /** 386 * Creates a new {@code PageFormat} instance and 387 * sets it to a default size and orientation. 388 * @return a {@code PageFormat} set to a default size and 389 * orientation. 390 */ 391 public PageFormat defaultPage() { 392 return defaultPage(new PageFormat()); 393 } 394 395 /** 396 * Calculates a {@code PageFormat} with values consistent with those 397 * supported by the current {@code PrintService} for this job 398 * (ie the value returned by {@code getPrintService()}) and media, 399 * printable area and orientation contained in {@code attributes}. 400 * <p> 401 * Calling this method does not update the job. 402 * It is useful for clients that have a set of attributes obtained from 403 * {@code printDialog(PrintRequestAttributeSet attributes)} 404 * and need a PageFormat to print a Pageable object. 405 * @param attributes a set of printing attributes, for example obtained 406 * from calling printDialog. If {@code attributes} is null a default 407 * PageFormat is returned. 408 * @return a {@code PageFormat} whose settings conform with 409 * those of the current service and the specified attributes. 410 * @since 1.6 411 */ 412 public PageFormat getPageFormat(PrintRequestAttributeSet attributes) { 413 414 PrintService service = getPrintService(); 415 PageFormat pf = defaultPage(); 416 417 if (service == null || attributes == null) { 418 return pf; 419 } 420 421 Media media = (Media)attributes.get(Media.class); 422 MediaPrintableArea mpa = 423 (MediaPrintableArea)attributes.get(MediaPrintableArea.class); 424 OrientationRequested orientReq = 425 (OrientationRequested)attributes.get(OrientationRequested.class); 426 427 if (media == null && mpa == null && orientReq == null) { 428 return pf; 429 } 430 Paper paper = pf.getPaper(); 431 432 /* If there's a media but no media printable area, we can try 433 * to retrieve the default value for mpa and use that. 434 */ 435 if (mpa == null && media != null && 436 service.isAttributeCategorySupported(MediaPrintableArea.class)) { 437 Object mpaVals = 438 service.getSupportedAttributeValues(MediaPrintableArea.class, 439 null, attributes); 440 if (mpaVals instanceof MediaPrintableArea[] && 441 ((MediaPrintableArea[])mpaVals).length > 0) { 442 mpa = ((MediaPrintableArea[])mpaVals)[0]; 443 } 444 } 445 446 if (media != null && 447 service.isAttributeValueSupported(media, null, attributes)) { 448 if (media instanceof MediaSizeName) { 449 MediaSizeName msn = (MediaSizeName)media; 450 MediaSize msz = MediaSize.getMediaSizeForName(msn); 451 if (msz != null) { 452 double inch = 72.0; 453 double paperWid = msz.getX(MediaSize.INCH) * inch; 454 double paperHgt = msz.getY(MediaSize.INCH) * inch; 455 paper.setSize(paperWid, paperHgt); 456 if (mpa == null) { 457 paper.setImageableArea(inch, inch, 458 paperWid-2*inch, 459 paperHgt-2*inch); 460 } 461 } 462 } 463 } 464 465 if (mpa != null && 466 service.isAttributeValueSupported(mpa, null, attributes)) { 467 float [] printableArea = 468 mpa.getPrintableArea(MediaPrintableArea.INCH); 469 for (int i=0; i < printableArea.length; i++) { 470 printableArea[i] = printableArea[i]*72.0f; 471 } 472 paper.setImageableArea(printableArea[0], printableArea[1], 473 printableArea[2], printableArea[3]); 474 } 475 476 if (orientReq != null && 477 service.isAttributeValueSupported(orientReq, null, attributes)) { 478 int orient; 479 if (orientReq.equals(OrientationRequested.REVERSE_LANDSCAPE)) { 480 orient = PageFormat.REVERSE_LANDSCAPE; 481 } else if (orientReq.equals(OrientationRequested.LANDSCAPE)) { 482 orient = PageFormat.LANDSCAPE; 483 } else { 484 orient = PageFormat.PORTRAIT; 485 } 486 pf.setOrientation(orient); 487 } 488 489 pf.setPaper(paper); 490 pf = validatePage(pf); 491 return pf; 492 } 493 494 /** 495 * Returns the clone of {@code page} with its settings 496 * adjusted to be compatible with the current printer of this 497 * {@code PrinterJob}. For example, the returned 498 * {@code PageFormat} could have its imageable area 499 * adjusted to fit within the physical area of the paper that 500 * is used by the current printer. 501 * @param page the {@code PageFormat} that is cloned and 502 * whose settings are changed to be compatible with 503 * the current printer 504 * @return a {@code PageFormat} that is cloned from 505 * {@code page} and whose settings are changed 506 * to conform with this {@code PrinterJob}. 507 */ 508 public abstract PageFormat validatePage(PageFormat page); 509 510 /** 511 * Prints a set of pages. 512 * @exception PrinterException an error in the print system 513 * caused the job to be aborted. 514 * @see Book 515 * @see Pageable 516 * @see Printable 517 */ 518 public abstract void print() throws PrinterException; 519 520 /** 521 * Prints a set of pages using the settings in the attribute 522 * set. The default implementation ignores the attribute set. 523 * <p> 524 * Note that some attributes may be set directly on the PrinterJob 525 * by equivalent method calls, (for example), copies: 526 * {@code setCopies(int)}, job name: {@code setJobName(String)} 527 * and specifying media size and orientation though the 528 * {@code PageFormat} object. 529 * <p> 530 * If a supported attribute-value is specified in this attribute set, 531 * it will take precedence over the API settings for this print() 532 * operation only. 533 * The following behaviour is specified for PageFormat: 534 * If a client uses the Printable interface, then the 535 * {@code attributes} parameter to this method is examined 536 * for attributes which specify media (by size), orientation, and 537 * imageable area, and those are used to construct a new PageFormat 538 * which is passed to the Printable object's print() method. 539 * See {@link Printable} for an explanation of the required 540 * behaviour of a Printable to ensure optimal printing via PrinterJob. 541 * For clients of the Pageable interface, the PageFormat will always 542 * be as supplied by that interface, on a per page basis. 543 * <p> 544 * These behaviours allow an application to directly pass the 545 * user settings returned from 546 * {@code printDialog(PrintRequestAttributeSet attributes} to 547 * this print() method. 548 * 549 * @param attributes a set of attributes for the job 550 * @exception PrinterException an error in the print system 551 * caused the job to be aborted. 552 * @see Book 553 * @see Pageable 554 * @see Printable 555 * @since 1.4 556 */ 557 public void print(PrintRequestAttributeSet attributes) 558 throws PrinterException { 559 print(); 560 } 561 562 /** 563 * Sets the number of copies to be printed. 564 * @param copies the number of copies to be printed 565 * @see #getCopies 566 */ 567 public abstract void setCopies(int copies); 568 569 /** 570 * Gets the number of copies to be printed. 571 * @return the number of copies to be printed. 572 * @see #setCopies 573 */ 574 public abstract int getCopies(); 575 576 /** 577 * Gets the name of the printing user. 578 * @return the name of the printing user 579 * @throws SecurityException if a security manager exists and 580 * PropertyPermission - user.name is not given in the policy file 581 */ 582 public abstract String getUserName(); 583 584 /** 585 * Sets the name of the document to be printed. 586 * The document name can not be {@code null}. 587 * @param jobName the name of the document to be printed 588 * @see #getJobName 589 */ 590 public abstract void setJobName(String jobName); 591 592 /** 593 * Gets the name of the document to be printed. 594 * @return the name of the document to be printed. 595 * @see #setJobName 596 */ 597 public abstract String getJobName(); 598 599 /** 600 * Cancels a print job that is in progress. If 601 * {@link #print() print} has been called but has not 602 * returned then this method signals 603 * that the job should be cancelled at the next 604 * chance. If there is no print job in progress then 605 * this call does nothing. 606 */ 607 public abstract void cancel(); 608 609 /** 610 * Returns {@code true} if a print job is 611 * in progress, but is going to be cancelled 612 * at the next opportunity; otherwise returns 613 * {@code false}. 614 * @return {@code true} if the job in progress 615 * is going to be cancelled; {@code false} otherwise. 616 */ 617 public abstract boolean isCancelled(); 618 619 }