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