001 /*
002 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.awt.print;
027
028 import java.awt.AWTError;
029 import java.awt.HeadlessException;
030 import java.util.Enumeration;
031
032 import javax.print.DocFlavor;
033 import javax.print.PrintService;
034 import javax.print.PrintServiceLookup;
035 import javax.print.StreamPrintServiceFactory;
036 import javax.print.attribute.PrintRequestAttributeSet;
037 import javax.print.attribute.standard.Media;
038 import javax.print.attribute.standard.MediaPrintableArea;
039 import javax.print.attribute.standard.MediaSize;
040 import javax.print.attribute.standard.MediaSizeName;
041 import javax.print.attribute.standard.OrientationRequested;
042
043 import sun.security.action.GetPropertyAction;
044
045 /**
046 * The <code>PrinterJob</code> class is the principal class that controls
047 * printing. An application calls methods in this class to set up a job,
048 * optionally to invoke a print dialog with the user, and then to print
049 * the pages of the job.
050 */
051 public abstract class PrinterJob {
052
053 /* Public Class Methods */
054
055 /**
056 * Creates and returns a <code>PrinterJob</code> which is initially
057 * associated with the default printer.
058 * If no printers are available on the system, a PrinterJob will still
059 * be returned from this method, but <code>getPrintService()</code>
060 * will return <code>null</code>, and calling
061 * {@link #print() print} with this <code>PrinterJob</code> might
062 * generate an exception. Applications that need to determine if
063 * there are suitable printers before creating a <code>PrinterJob</code>
064 * should ensure that the array returned from
065 * {@link #lookupPrintServices() lookupPrintServices} is not empty.
066 * @return a new <code>PrinterJob</code>.
067 *
068 * @throws SecurityException if a security manager exists and its
069 * {@link java.lang.SecurityManager#checkPrintJobAccess}
070 * method disallows this thread from creating a print job request
071 */
072 public static PrinterJob getPrinterJob() {
073 SecurityManager security = System.getSecurityManager();
074 if (security != null) {
075 security.checkPrintJobAccess();
076 }
077 return (PrinterJob) java.security.AccessController
078 .doPrivileged(new java.security.PrivilegedAction() {
079 public Object run() {
080 String nm = System.getProperty(
081 "java.awt.printerjob", null);
082 try {
083 return (PrinterJob) Class.forName(nm)
084 .newInstance();
085 } catch (ClassNotFoundException e) {
086 throw new AWTError("PrinterJob not found: "
087 + nm);
088 } catch (InstantiationException e) {
089 throw new AWTError(
090 "Could not instantiate PrinterJob: "
091 + nm);
092 } catch (IllegalAccessException e) {
093 throw new AWTError(
094 "Could not access PrinterJob: "
095 + nm);
096 }
097 }
098 });
099 }
100
101 /**
102 * A convenience method which looks up 2D print services.
103 * Services returned from this method may be installed on
104 * <code>PrinterJob</code>s which support print services.
105 * Calling this method is equivalent to calling
106 * {@link javax.print.PrintServiceLookup#lookupPrintServices(
107 * DocFlavor, AttributeSet)
108 * <code>PrintServiceLookup.lookupPrintServices()</code>}
109 * and specifying a Pageable DocFlavor.
110 * @return a possibly empty array of 2D print services.
111 * @since 1.4
112 */
113 public static PrintService[] lookupPrintServices() {
114 return PrintServiceLookup.lookupPrintServices(
115 DocFlavor.SERVICE_FORMATTED.PAGEABLE, null);
116 }
117
118 /**
119 * A convenience method which locates factories for stream print
120 * services which can image 2D graphics.
121 * Sample usage :
122 * <pre>
123 * FileOutputStream outstream;
124 * StreamPrintService psPrinter;
125 * String psMimeType = "application/postscript";
126 *
127 * StreamPrintServiceFactory[] factories =
128 * PrinterJob.lookupStreamPrintServices(psMimeType);
129 * if (factories.length > 0) {
130 * try {
131 * outstream = new File("out.ps");
132 * psPrinter = factories[0].getPrintService(fos);
133 * // psPrinter can now be set as the service on a PrinterJob
134 * } catch (FileNotFoundException e) {
135 * }
136 * }
137 * </pre>
138 * Services returned from this method may be installed on
139 * <code>PrinterJob</code> instances which support print services.
140 * Calling this method is equivalent to calling
141 * {@link javax.print.StreamPrintServiceFactory#lookupStreamPrintServiceFactories(DocFlavor, String)
142 * <code>StreamPrintServiceFactory.lookupStreamPrintServiceFactories()
143 * </code>} and specifying a Pageable DocFlavor.
144 *
145 * @param mimeType the required output format, or null to mean any format.
146 * @return a possibly empty array of 2D stream print service factories.
147 * @since 1.4
148 */
149 public static StreamPrintServiceFactory[] lookupStreamPrintServices(
150 String mimeType) {
151 return StreamPrintServiceFactory
152 .lookupStreamPrintServiceFactories(
153 DocFlavor.SERVICE_FORMATTED.PAGEABLE, mimeType);
154 }
155
156 /* Public Methods */
157
158 /**
159 * A <code>PrinterJob</code> object should be created using the
160 * static {@link #getPrinterJob() <code>getPrinterJob</code>} method.
161 */
162 public PrinterJob() {
163 }
164
165 /**
166 * Returns the service (printer) for this printer job.
167 * Implementations of this class which do not support print services
168 * may return null. null will also be returned if no printers are
169 * available.
170 * @return the service for this printer job.
171 * @see #setPrintService(PrintService)
172 * @see #getPrinterJob()
173 * @since 1.4
174 */
175 public PrintService getPrintService() {
176 return null;
177 }
178
179 /**
180 * Associate this PrinterJob with a new PrintService.
181 * This method is overridden by subclasses which support
182 * specifying a Print Service.
183 *
184 * Throws <code>PrinterException</code> if the specified service
185 * cannot support the <code>Pageable</code> and
186 * <code>Printable</code> interfaces necessary to support 2D printing.
187 * @param service a print service that supports 2D printing
188 * @exception PrinterException if the specified service does not support
189 * 2D printing, or this PrinterJob class does not support
190 * setting a 2D print service, or the specified service is
191 * otherwise not a valid print service.
192 * @see #getPrintService
193 * @since 1.4
194 */
195 public void setPrintService(PrintService service)
196 throws PrinterException {
197 throw new PrinterException(
198 "Setting a service is not supported on this class");
199 }
200
201 /**
202 * Calls <code>painter</code> to render the pages. The pages in the
203 * document to be printed by this
204 * <code>PrinterJob</code> are rendered by the {@link Printable}
205 * object, <code>painter</code>. The {@link PageFormat} for each page
206 * is the default page format.
207 * @param painter the <code>Printable</code> that renders each page of
208 * the document.
209 */
210 public abstract void setPrintable(Printable painter);
211
212 /**
213 * Calls <code>painter</code> to render the pages in the specified
214 * <code>format</code>. The pages in the document to be printed by
215 * this <code>PrinterJob</code> are rendered by the
216 * <code>Printable</code> object, <code>painter</code>. The
217 * <code>PageFormat</code> of each page is <code>format</code>.
218 * @param painter the <code>Printable</code> called to render
219 * each page of the document
220 * @param format the size and orientation of each page to
221 * be printed
222 */
223 public abstract void setPrintable(Printable painter,
224 PageFormat format);
225
226 /**
227 * Queries <code>document</code> for the number of pages and
228 * the <code>PageFormat</code> and <code>Printable</code> for each
229 * page held in the <code>Pageable</code> instance,
230 * <code>document</code>.
231 * @param document the pages to be printed. It can not be
232 * <code>null</code>.
233 * @exception NullPointerException the <code>Pageable</code> passed in
234 * was <code>null</code>.
235 * @see PageFormat
236 * @see Printable
237 */
238 public abstract void setPageable(Pageable document)
239 throws NullPointerException;
240
241 /**
242 * Presents a dialog to the user for changing the properties of
243 * the print job.
244 * This method will display a native dialog if a native print
245 * service is selected, and user choice of printers will be restricted
246 * to these native print services.
247 * To present the cross platform print dialog for all services,
248 * including native ones instead use
249 * <code>printDialog(PrintRequestAttributeSet)</code>.
250 * <p>
251 * PrinterJob implementations which can use PrintService's will update
252 * the PrintService for this PrinterJob to reflect the new service
253 * selected by the user.
254 * @return <code>true</code> if the user does not cancel the dialog;
255 * <code>false</code> otherwise.
256 * @exception HeadlessException if GraphicsEnvironment.isHeadless()
257 * returns true.
258 * @see java.awt.GraphicsEnvironment#isHeadless
259 */
260 public abstract boolean printDialog() throws HeadlessException;
261
262 /**
263 * A convenience method which displays a cross-platform print dialog
264 * for all services which are capable of printing 2D graphics using the
265 * <code>Pageable</code> interface. The selected printer when the
266 * dialog is initially displayed will reflect the print service currently
267 * attached to this print job.
268 * If the user changes the print service, the PrinterJob will be
269 * updated to reflect this, unless the user cancels the dialog.
270 * As well as allowing the user to select the destination printer,
271 * the user can also select values of various print request attributes.
272 * <p>
273 * The attributes parameter on input will reflect the applications
274 * required initial selections in the user dialog. Attributes not
275 * specified display using the default for the service. On return it
276 * will reflect the user's choices. Selections may be updated by
277 * the implementation to be consistent with the supported values
278 * for the currently selected print service.
279 * <p>
280 * As the user scrolls to a new print service selection, the values
281 * copied are based on the settings for the previous service, together
282 * with any user changes. The values are not based on the original
283 * settings supplied by the client.
284 * <p>
285 * With the exception of selected printer, the PrinterJob state is
286 * not updated to reflect the user's changes.
287 * For the selections to affect a printer job, the attributes must
288 * be specified in the call to the
289 * <code>print(PrintRequestAttributeSet)</code> method. If using
290 * the Pageable interface, clients which intend to use media selected
291 * by the user must create a PageFormat derived from the user's
292 * selections.
293 * If the user cancels the dialog, the attributes will not reflect
294 * any changes made by the user.
295 * @param attributes on input is application supplied attributes,
296 * on output the contents are updated to reflect user choices.
297 * This parameter may not be null.
298 * @return <code>true</code> if the user does not cancel the dialog;
299 * <code>false</code> otherwise.
300 * @exception HeadlessException if GraphicsEnvironment.isHeadless()
301 * returns true.
302 * @exception NullPointerException if <code>attributes</code> parameter
303 * is null.
304 * @see java.awt.GraphicsEnvironment#isHeadless
305 * @since 1.4
306 *
307 */
308 public boolean printDialog(PrintRequestAttributeSet attributes)
309 throws HeadlessException {
310
311 if (attributes == null) {
312 throw new NullPointerException("attributes");
313 }
314 return printDialog();
315 }
316
317 /**
318 * Displays a dialog that allows modification of a
319 * <code>PageFormat</code> instance.
320 * The <code>page</code> argument is used to initialize controls
321 * in the page setup dialog.
322 * If the user cancels the dialog then this method returns the
323 * original <code>page</code> object unmodified.
324 * If the user okays the dialog then this method returns a new
325 * <code>PageFormat</code> object with the indicated changes.
326 * In either case, the original <code>page</code> object is
327 * not modified.
328 * @param page the default <code>PageFormat</code> presented to the
329 * user for modification
330 * @return the original <code>page</code> object if the dialog
331 * is cancelled; a new <code>PageFormat</code> object
332 * containing the format indicated by the user if the
333 * dialog is acknowledged.
334 * @exception HeadlessException if GraphicsEnvironment.isHeadless()
335 * returns true.
336 * @see java.awt.GraphicsEnvironment#isHeadless
337 * @since 1.2
338 */
339 public abstract PageFormat pageDialog(PageFormat page)
340 throws HeadlessException;
341
342 /**
343 * A convenience method which displays a cross-platform page setup dialog.
344 * The choices available will reflect the print service currently
345 * set on this PrinterJob.
346 * <p>
347 * The attributes parameter on input will reflect the client's
348 * required initial selections in the user dialog. Attributes which are
349 * not specified display using the default for the service. On return it
350 * will reflect the user's choices. Selections may be updated by
351 * the implementation to be consistent with the supported values
352 * for the currently selected print service.
353 * <p>
354 * The return value will be a PageFormat equivalent to the
355 * selections in the PrintRequestAttributeSet.
356 * If the user cancels the dialog, the attributes will not reflect
357 * any changes made by the user, and the return value will be null.
358 * @param attributes on input is application supplied attributes,
359 * on output the contents are updated to reflect user choices.
360 * This parameter may not be null.
361 * @return a page format if the user does not cancel the dialog;
362 * <code>null</code> otherwise.
363 * @exception HeadlessException if GraphicsEnvironment.isHeadless()
364 * returns true.
365 * @exception NullPointerException if <code>attributes</code> parameter
366 * is null.
367 * @see java.awt.GraphicsEnvironment#isHeadless
368 * @since 1.4
369 *
370 */
371 public PageFormat pageDialog(PrintRequestAttributeSet attributes)
372 throws HeadlessException {
373
374 if (attributes == null) {
375 throw new NullPointerException("attributes");
376 }
377 return pageDialog(defaultPage());
378 }
379
380 /**
381 * Clones the <code>PageFormat</code> argument and alters the
382 * clone to describe a default page size and orientation.
383 * @param page the <code>PageFormat</code> to be cloned and altered
384 * @return clone of <code>page</code>, altered to describe a default
385 * <code>PageFormat</code>.
386 */
387 public abstract PageFormat defaultPage(PageFormat page);
388
389 /**
390 * Creates a new <code>PageFormat</code> instance and
391 * sets it to a default size and orientation.
392 * @return a <code>PageFormat</code> set to a default size and
393 * orientation.
394 */
395 public PageFormat defaultPage() {
396 return defaultPage(new PageFormat());
397 }
398
399 /**
400 * Calculates a <code>PageFormat</code> with values consistent with those
401 * supported by the current <code>PrintService</code> for this job
402 * (ie the value returned by <code>getPrintService()</code>) and media,
403 * printable area and orientation contained in <code>attributes</code>.
404 * <p>
405 * Calling this method does not update the job.
406 * It is useful for clients that have a set of attributes obtained from
407 * <code>printDialog(PrintRequestAttributeSet attributes)</code>
408 * and need a PageFormat to print a Pageable object.
409 * @param attributes a set of printing attributes, for example obtained
410 * from calling printDialog. If <code>attributes</code> is null a default
411 * PageFormat is returned.
412 * @return a <code>PageFormat</code> whose settings conform with
413 * those of the current service and the specified attributes.
414 * @since 1.6
415 */
416 public PageFormat getPageFormat(PrintRequestAttributeSet attributes) {
417
418 PrintService service = getPrintService();
419 PageFormat pf = defaultPage();
420
421 if (service == null || attributes == null) {
422 return pf;
423 }
424
425 Media media = (Media) attributes.get(Media.class);
426 MediaPrintableArea mpa = (MediaPrintableArea) attributes
427 .get(MediaPrintableArea.class);
428 OrientationRequested orientReq = (OrientationRequested) attributes
429 .get(OrientationRequested.class);
430
431 if (media == null && mpa == null && orientReq == null) {
432 return pf;
433 }
434 Paper paper = pf.getPaper();
435
436 /* If there's a media but no media printable area, we can try
437 * to retrieve the default value for mpa and use that.
438 */
439 if (mpa == null
440 && media != null
441 && service
442 .isAttributeCategorySupported(MediaPrintableArea.class)) {
443 Object mpaVals = service.getSupportedAttributeValues(
444 MediaPrintableArea.class, null, attributes);
445 if (mpaVals instanceof MediaPrintableArea[]
446 && ((MediaPrintableArea[]) mpaVals).length > 0) {
447 mpa = ((MediaPrintableArea[]) mpaVals)[0];
448 }
449 }
450
451 if (media != null
452 && service.isAttributeValueSupported(media, null,
453 attributes)) {
454 if (media instanceof MediaSizeName) {
455 MediaSizeName msn = (MediaSizeName) media;
456 MediaSize msz = MediaSize.getMediaSizeForName(msn);
457 if (msz != null) {
458 double inch = 72.0;
459 double paperWid = msz.getX(MediaSize.INCH) * inch;
460 double paperHgt = msz.getY(MediaSize.INCH) * inch;
461 paper.setSize(paperWid, paperHgt);
462 if (mpa == null) {
463 paper.setImageableArea(inch, inch, paperWid - 2
464 * inch, paperHgt - 2 * inch);
465 }
466 }
467 }
468 }
469
470 if (mpa != null
471 && service.isAttributeValueSupported(mpa, null,
472 attributes)) {
473 float[] printableArea = mpa
474 .getPrintableArea(MediaPrintableArea.INCH);
475 for (int i = 0; i < printableArea.length; i++) {
476 printableArea[i] = printableArea[i] * 72.0f;
477 }
478 paper.setImageableArea(printableArea[0], printableArea[1],
479 printableArea[2], printableArea[3]);
480 }
481
482 if (orientReq != null
483 && service.isAttributeValueSupported(orientReq, null,
484 attributes)) {
485 int orient;
486 if (orientReq
487 .equals(OrientationRequested.REVERSE_LANDSCAPE)) {
488 orient = PageFormat.REVERSE_LANDSCAPE;
489 } else if (orientReq.equals(OrientationRequested.LANDSCAPE)) {
490 orient = PageFormat.LANDSCAPE;
491 } else {
492 orient = PageFormat.PORTRAIT;
493 }
494 pf.setOrientation(orient);
495 }
496
497 pf.setPaper(paper);
498 pf = validatePage(pf);
499 return pf;
500 }
501
502 /**
503 * Returns the clone of <code>page</code> with its settings
504 * adjusted to be compatible with the current printer of this
505 * <code>PrinterJob</code>. For example, the returned
506 * <code>PageFormat</code> could have its imageable area
507 * adjusted to fit within the physical area of the paper that
508 * is used by the current printer.
509 * @param page the <code>PageFormat</code> that is cloned and
510 * whose settings are changed to be compatible with
511 * the current printer
512 * @return a <code>PageFormat</code> that is cloned from
513 * <code>page</code> and whose settings are changed
514 * to conform with this <code>PrinterJob</code>.
515 */
516 public abstract PageFormat validatePage(PageFormat page);
517
518 /**
519 * Prints a set of pages.
520 * @exception PrinterException an error in the print system
521 * caused the job to be aborted.
522 * @see Book
523 * @see Pageable
524 * @see Printable
525 */
526 public abstract void print() throws PrinterException;
527
528 /**
529 * Prints a set of pages using the settings in the attribute
530 * set. The default implementation ignores the attribute set.
531 * <p>
532 * Note that some attributes may be set directly on the PrinterJob
533 * by equivalent method calls, (for example), copies:
534 * <code>setcopies(int)</code>, job name: <code>setJobName(String)</code>
535 * and specifying media size and orientation though the
536 * <code>PageFormat</code> object.
537 * <p>
538 * If a supported attribute-value is specified in this attribute set,
539 * it will take precedence over the API settings for this print()
540 * operation only.
541 * The following behaviour is specified for PageFormat:
542 * If a client uses the Printable interface, then the
543 * <code>attributes</code> parameter to this method is examined
544 * for attributes which specify media (by size), orientation, and
545 * imageable area, and those are used to construct a new PageFormat
546 * which is passed to the Printable object's print() method.
547 * See {@link Printable} for an explanation of the required
548 * behaviour of a Printable to ensure optimal printing via PrinterJob.
549 * For clients of the Pageable interface, the PageFormat will always
550 * be as supplied by that interface, on a per page basis.
551 * <p>
552 * These behaviours allow an application to directly pass the
553 * user settings returned from
554 * <code>printDialog(PrintRequestAttributeSet attributes</code> to
555 * this print() method.
556 * <p>
557 *
558 * @param attributes a set of attributes for the job
559 * @exception PrinterException an error in the print system
560 * caused the job to be aborted.
561 * @see Book
562 * @see Pageable
563 * @see Printable
564 * @since 1.4
565 */
566 public void print(PrintRequestAttributeSet attributes)
567 throws PrinterException {
568 print();
569 }
570
571 /**
572 * Sets the number of copies to be printed.
573 * @param copies the number of copies to be printed
574 * @see #getCopies
575 */
576 public abstract void setCopies(int copies);
577
578 /**
579 * Gets the number of copies to be printed.
580 * @return the number of copies to be printed.
581 * @see #setCopies
582 */
583 public abstract int getCopies();
584
585 /**
586 * Gets the name of the printing user.
587 * @return the name of the printing user
588 */
589 public abstract String getUserName();
590
591 /**
592 * Sets the name of the document to be printed.
593 * The document name can not be <code>null</code>.
594 * @param jobName the name of the document to be printed
595 * @see #getJobName
596 */
597 public abstract void setJobName(String jobName);
598
599 /**
600 * Gets the name of the document to be printed.
601 * @return the name of the document to be printed.
602 * @see #setJobName
603 */
604 public abstract String getJobName();
605
606 /**
607 * Cancels a print job that is in progress. If
608 * {@link #print() print} has been called but has not
609 * returned then this method signals
610 * that the job should be cancelled at the next
611 * chance. If there is no print job in progress then
612 * this call does nothing.
613 */
614 public abstract void cancel();
615
616 /**
617 * Returns <code>true</code> if a print job is
618 * in progress, but is going to be cancelled
619 * at the next opportunity; otherwise returns
620 * <code>false</code>.
621 * @return <code>true</code> if the job in progress
622 * is going to be cancelled; <code>false</code> otherwise.
623 */
624 public abstract boolean isCancelled();
625
626 }
|