1 /*
2 * Copyright 1997-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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 * <code>PrintServiceLookup.lookupPrintServices()</code>}
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>
117 * FileOutputStream outstream;
118 * StreamPrintService psPrinter;
119 * String psMimeType = "application/postscript";
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(fos);
127 * // psPrinter can now be set as the service on a PrinterJob
128 * } catch (FileNotFoundException e) {
129 * }
130 * }
131 * </pre>
132 * Services returned from this method may be installed on
133 * <code>PrinterJob</code> instances which support print services.
134 * Calling this method is equivalent to calling
135 * {@link javax.print.StreamPrintServiceFactory#lookupStreamPrintServiceFactories(DocFlavor, String)
136 * <code>StreamPrintServiceFactory.lookupStreamPrintServiceFactories()
137 * </code>} 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</code> object should be created using the
155 * static {@link #getPrinterJob() <code>getPrinterJob</code>} 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</code> if the specified service
180 * cannot support the <code>Pageable</code> and
181 * <code>Printable</code> 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</code> to render the pages. The pages in the
198 * document to be printed by this
199 * <code>PrinterJob</code> are rendered by the {@link Printable}
200 * object, <code>painter</code>. The {@link PageFormat} for each page
201 * is the default page format.
202 * @param painter the <code>Printable</code> that renders each page of
203 * the document.
204 */
205 public abstract void setPrintable(Printable painter);
206
207 /**
208 * Calls <code>painter</code> to render the pages in the specified
209 * <code>format</code>. The pages in the document to be printed by
210 * this <code>PrinterJob</code> are rendered by the
211 * <code>Printable</code> object, <code>painter</code>. The
212 * <code>PageFormat</code> of each page is <code>format</code>.
213 * @param painter the <code>Printable</code> 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</code> for the number of pages and
222 * the <code>PageFormat</code> and <code>Printable</code> for each
223 * page held in the <code>Pageable</code> instance,
224 * <code>document</code>.
225 * @param document the pages to be printed. It can not be
226 * <code>null</code>.
227 * @exception NullPointerException the <code>Pageable</code> passed in
228 * was <code>null</code>.
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)</code>.
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</code> if the user does not cancel the dialog;
249 * <code>false</code> 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</code> 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)</code> 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</code> if the user does not cancel the dialog;
293 * <code>false</code> otherwise.
294 * @exception HeadlessException if GraphicsEnvironment.isHeadless()
295 * returns true.
296 * @exception NullPointerException if <code>attributes</code> 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</code> instance.
314 * The <code>page</code> 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</code> object unmodified.
318 * If the user okays the dialog then this method returns a new
319 * <code>PageFormat</code> object with the indicated changes.
320 * In either case, the original <code>page</code> object is
321 * not modified.
322 * @param page the default <code>PageFormat</code> presented to the
323 * user for modification
324 * @return the original <code>page</code> object if the dialog
325 * is cancelled; a new <code>PageFormat</code> 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</code> otherwise.
357 * @exception HeadlessException if GraphicsEnvironment.isHeadless()
358 * returns true.
359 * @exception NullPointerException if <code>attributes</code> 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</code> argument and alters the
376 * clone to describe a default page size and orientation.
377 * @param page the <code>PageFormat</code> to be cloned and altered
378 * @return clone of <code>page</code>, altered to describe a default
379 * <code>PageFormat</code>.
380 */
381 public abstract PageFormat defaultPage(PageFormat page);
382
383 /**
384 * Creates a new <code>PageFormat</code> instance and
385 * sets it to a default size and orientation.
386 * @return a <code>PageFormat</code> 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</code> with values consistent with those
395 * supported by the current <code>PrintService</code> for this job
396 * (ie the value returned by <code>getPrintService()</code>) and media,
397 * printable area and orientation contained in <code>attributes</code>.
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)</code>
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</code> is null a default
405 * PageFormat is returned.
406 * @return a <code>PageFormat</code> 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</code> with its settings
494 * adjusted to be compatible with the current printer of this
495 * <code>PrinterJob</code>. For example, the returned
496 * <code>PageFormat</code> 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</code> that is cloned and
500 * whose settings are changed to be compatible with
501 * the current printer
502 * @return a <code>PageFormat</code> that is cloned from
503 * <code>page</code> and whose settings are changed
504 * to conform with this <code>PrinterJob</code>.
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)</code>, job name: <code>setJobName(String)</code>
525 * and specifying media size and orientation though the
526 * <code>PageFormat</code> 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</code> 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</code> to
545 * this print() method.
546 * <p>
547 *
548 * @param attributes a set of attributes for the job
549 * @exception PrinterException an error in the print system
550 * caused the job to be aborted.
551 * @see Book
552 * @see Pageable
553 * @see Printable
554 * @since 1.4
555 */
556 public void print(PrintRequestAttributeSet attributes)
557 throws PrinterException {
558 print();
559 }
560
561 /**
562 * Sets the number of copies to be printed.
563 * @param copies the number of copies to be printed
564 * @see #getCopies
565 */
566 public abstract void setCopies(int copies);
567
568 /**
569 * Gets the number of copies to be printed.
570 * @return the number of copies to be printed.
571 * @see #setCopies
572 */
573 public abstract int getCopies();
574
575 /**
576 * Gets the name of the printing user.
577 * @return the name of the printing user
578 */
579 public abstract String getUserName();
580
581 /**
582 * Sets the name of the document to be printed.
583 * The document name can not be <code>null</code>.
584 * @param jobName the name of the document to be printed
585 * @see #getJobName
586 */
587 public abstract void setJobName(String jobName);
588
589 /**
590 * Gets the name of the document to be printed.
591 * @return the name of the document to be printed.
592 * @see #setJobName
593 */
594 public abstract String getJobName();
595
596 /**
597 * Cancels a print job that is in progress. If
598 * {@link #print() print} has been called but has not
599 * returned then this method signals
600 * that the job should be cancelled at the next
601 * chance. If there is no print job in progress then
602 * this call does nothing.
603 */
604 public abstract void cancel();
605
606 /**
607 * Returns <code>true</code> if a print job is
608 * in progress, but is going to be cancelled
609 * at the next opportunity; otherwise returns
610 * <code>false</code>.
611 * @return <code>true</code> if the job in progress
612 * is going to be cancelled; <code>false</code> otherwise.
613 */
614 public abstract boolean isCancelled();
615
616 }