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