1 /* 2 * Copyright (c) 1997, 2015, 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 sun.awt.windows; 27 28 import java.awt.Color; 29 import java.awt.Font; 30 import java.awt.Graphics2D; 31 import java.awt.GraphicsEnvironment; 32 import java.awt.HeadlessException; 33 import java.awt.Toolkit; 34 import java.awt.BasicStroke; 35 import java.awt.Button; 36 import java.awt.Component; 37 import java.awt.Dimension; 38 import java.awt.event.ActionEvent; 39 import java.awt.event.ActionListener; 40 import java.awt.FileDialog; 41 import java.awt.Dialog; 42 import java.awt.Label; 43 import java.awt.Panel; 44 import java.awt.Rectangle; 45 import java.awt.Window; 46 47 import java.awt.image.BufferedImage; 48 import java.awt.image.IndexColorModel; 49 50 import java.awt.print.Pageable; 51 import java.awt.print.PageFormat; 52 import java.awt.print.Paper; 53 import java.awt.print.Printable; 54 import java.awt.print.PrinterJob; 55 import java.awt.print.PrinterException; 56 import javax.print.PrintService; 57 58 import java.io.File; 59 60 import java.util.MissingResourceException; 61 import java.util.ResourceBundle; 62 63 import sun.awt.AWTAccessor; 64 import sun.awt.AWTAccessor.ComponentAccessor; 65 import sun.print.PeekGraphics; 66 import sun.print.PeekMetrics; 67 68 import java.net.URI; 69 import java.net.URISyntaxException; 70 71 import javax.print.PrintServiceLookup; 72 import javax.print.attribute.PrintRequestAttributeSet; 73 import javax.print.attribute.HashPrintRequestAttributeSet; 74 import javax.print.attribute.Attribute; 75 import javax.print.attribute.standard.Sides; 76 import javax.print.attribute.standard.Chromaticity; 77 import javax.print.attribute.standard.PrintQuality; 78 import javax.print.attribute.standard.PrinterResolution; 79 import javax.print.attribute.standard.SheetCollate; 80 import javax.print.attribute.standard.Copies; 81 import javax.print.attribute.standard.Destination; 82 import javax.print.attribute.standard.DialogOwner; 83 import javax.print.attribute.standard.OrientationRequested; 84 import javax.print.attribute.standard.Media; 85 import javax.print.attribute.standard.MediaSizeName; 86 import javax.print.attribute.standard.MediaSize; 87 import javax.print.attribute.standard.MediaTray; 88 import javax.print.attribute.standard.PageRanges; 89 90 import sun.awt.Win32FontManager; 91 92 import sun.print.RasterPrinterJob; 93 import sun.print.SunAlternateMedia; 94 import sun.print.SunPageSelection; 95 import sun.print.Win32MediaTray; 96 import sun.print.Win32PrintService; 97 import sun.print.PrintServiceLookupProvider; 98 import sun.print.ServiceDialog; 99 100 import java.awt.Frame; 101 import java.io.FilePermission; 102 103 import sun.java2d.Disposer; 104 import sun.java2d.DisposerRecord; 105 import sun.java2d.DisposerTarget; 106 107 /** 108 * A class which initiates and executes a Win32 printer job. 109 * 110 * @author Richard Blanchard 111 */ 112 public final class WPrinterJob extends RasterPrinterJob 113 implements DisposerTarget { 114 115 /* Class Constants */ 116 117 118 /* Instance Variables */ 119 120 /** 121 * These are Windows' ExtCreatePen End Cap Styles 122 * and must match the values in <WINGDI.h> 123 */ 124 protected static final long PS_ENDCAP_ROUND = 0x00000000; 125 protected static final long PS_ENDCAP_SQUARE = 0x00000100; 126 protected static final long PS_ENDCAP_FLAT = 0x00000200; 127 128 /** 129 * These are Windows' ExtCreatePen Line Join Styles 130 * and must match the values in <WINGDI.h> 131 */ 132 protected static final long PS_JOIN_ROUND = 0x00000000; 133 protected static final long PS_JOIN_BEVEL = 0x00001000; 134 protected static final long PS_JOIN_MITER = 0x00002000; 135 136 /** 137 * This is the Window's Polygon fill rule which 138 * Selects alternate mode (fills the area between odd-numbered 139 * and even-numbered polygon sides on each scan line). 140 * It must match the value in <WINGDI.h> It can be passed 141 * to setPolyFillMode(). 142 */ 143 protected static final int POLYFILL_ALTERNATE = 1; 144 145 /** 146 * This is the Window's Polygon fill rule which 147 * Selects winding mode which fills any region 148 * with a nonzero winding value). It must match 149 * the value in <WINGDI.h> It can be passed 150 * to setPolyFillMode(). 151 */ 152 protected static final int POLYFILL_WINDING = 2; 153 154 /** 155 * The maximum value for a Window's color component 156 * as passed to selectSolidBrush. 157 */ 158 private static final int MAX_WCOLOR = 255; 159 160 /** 161 * Flags for setting values from devmode in native code. 162 * Values must match those defined in awt_PrintControl.cpp 163 */ 164 private static final int SET_DUP_VERTICAL = 0x00000010; 165 private static final int SET_DUP_HORIZONTAL = 0x00000020; 166 private static final int SET_RES_HIGH = 0x00000040; 167 private static final int SET_RES_LOW = 0x00000080; 168 private static final int SET_COLOR = 0x00000200; 169 private static final int SET_ORIENTATION = 0x00004000; 170 private static final int SET_COLLATED = 0x00008000; 171 172 /** 173 * Values must match those defined in wingdi.h & commdlg.h 174 */ 175 private static final int PD_COLLATE = 0x00000010; 176 private static final int PD_PRINTTOFILE = 0x00000020; 177 private static final int DM_ORIENTATION = 0x00000001; 178 private static final int DM_PAPERSIZE = 0x00000002; 179 private static final int DM_COPIES = 0x00000100; 180 private static final int DM_DEFAULTSOURCE = 0x00000200; 181 private static final int DM_PRINTQUALITY = 0x00000400; 182 private static final int DM_COLOR = 0x00000800; 183 private static final int DM_DUPLEX = 0x00001000; 184 private static final int DM_YRESOLUTION = 0x00002000; 185 private static final int DM_COLLATE = 0x00008000; 186 187 private static final short DMCOLLATE_FALSE = 0; 188 private static final short DMCOLLATE_TRUE = 1; 189 190 private static final short DMORIENT_PORTRAIT = 1; 191 private static final short DMORIENT_LANDSCAPE = 2; 192 193 private static final short DMCOLOR_MONOCHROME = 1; 194 private static final short DMCOLOR_COLOR = 2; 195 196 private static final short DMRES_DRAFT = -1; 197 private static final short DMRES_LOW = -2; 198 private static final short DMRES_MEDIUM = -3; 199 private static final short DMRES_HIGH = -4; 200 201 private static final short DMDUP_SIMPLEX = 1; 202 private static final short DMDUP_VERTICAL = 2; 203 private static final short DMDUP_HORIZONTAL = 3; 204 205 /** 206 * Pageable MAX pages 207 */ 208 private static final int MAX_UNKNOWN_PAGES = 9999; 209 210 211 /* Collation and copy flags. 212 * The Windows PRINTDLG struct has a nCopies field which on return 213 * indicates how many copies of a print job an application must render. 214 * There is also a PD_COLLATE member of the flags field which if 215 * set on return indicates the application generated copies should be 216 * collated. 217 * Windows printer drivers typically - but not always - support 218 * generating multiple copies themselves, but uncollated is more 219 * universal than collated copies. 220 * When they do, they read the initial values from the PRINTDLG structure 221 * and set them into the driver's DEVMODE structure and intialise 222 * the printer DC based on that, so that when printed those settings 223 * will be used. 224 * For drivers supporting both these capabilities via DEVMODE, then on 225 * return from the Print Dialog, nCopies is set to 1 and the PD_COLLATE is 226 * cleared, so that the application will only render 1 copy and the 227 * driver takes care of the rest. 228 * 229 * Applications which want to know what's going on have to be DEVMODE 230 * savvy and peek at that. 231 * DM_COPIES flag indicates support for multiple driver copies 232 * and dmCopies is the number of copies the driver will print 233 * DM_COLLATE flag indicates support for collated driver copies and 234 * dmCollate == DMCOLLATE_TRUE indicates the option is in effect. 235 * 236 * Multiple copies from Java applications: 237 * We provide API to get & set the number of copies as well as allowing the 238 * user to choose it, so we need to be savvy about DEVMODE, so that 239 * we can accurately report back the number of copies selected by 240 * the user, as well as make use of the driver to render multiple copies. 241 * 242 * Collation and Java applications: 243 * We presently provide no API for specifying collation, but its 244 * present on the Windows Print Dialog, and when a user checks it 245 * they expect it to be obeyed. 246 * The best thing to do is to detect exactly the cases where the 247 * driver doesn't support this and render multiple copies ourselves. 248 * To support all this we need several flags which signal the 249 * printer's capabilities and the user's requests. 250 * Its questionable if we (yet) need to make a distinction between 251 * the user requesting collation and the driver supporting it. 252 * Since for now we only need to know whether we need to render the 253 * copies. However it allows the logic to be clearer. 254 * These fields are changed by native code which detects the driver's 255 * capabilities and the user's choices. 256 */ 257 258 //initialize to false because the Flags that we initialized in PRINTDLG 259 // tells GDI that we can handle our own collation and multiple copies 260 private boolean driverDoesMultipleCopies = false; 261 private boolean driverDoesCollation = false; 262 private boolean userRequestedCollation = false; 263 private boolean noDefaultPrinter = false; 264 265 /* The HandleRecord holds the native resources that need to be freed 266 * when this WPrinterJob is GC'd. 267 */ 268 static class HandleRecord implements DisposerRecord { 269 /** 270 * The Windows device context we will print into. 271 * This variable is set after the Print dialog 272 * is okayed by the user. If the user cancels 273 * the print dialog, then this variable is 0. 274 * Much of the configuration information for a printer is 275 * obtained through printer device specific handles. 276 * We need to associate these with, and free with, the mPrintDC. 277 */ 278 private long mPrintDC; 279 private long mPrintHDevMode; 280 private long mPrintHDevNames; 281 282 @Override 283 public void dispose() { 284 WPrinterJob.deleteDC(mPrintDC, mPrintHDevMode, mPrintHDevNames); 285 } 286 } 287 288 private HandleRecord handleRecord = new HandleRecord(); 289 290 private int mPrintPaperSize; 291 292 /* These fields are directly set in upcalls from the values 293 * obtained from calling DeviceCapabilities() 294 */ 295 private int mPrintXRes; // pixels per inch in x direction 296 297 private int mPrintYRes; // pixels per inch in y direction 298 299 private int mPrintPhysX; // x offset in pixels of printable area 300 301 private int mPrintPhysY; // y offset in pixels of printable area 302 303 private int mPrintWidth; // width in pixels of printable area 304 305 private int mPrintHeight; // height in pixels of printable area 306 307 private int mPageWidth; // width in pixels of entire page 308 309 private int mPageHeight; // height in pixels of entire page 310 311 /* The values of the following variables are pulled directly 312 * into native code (even bypassing getter methods) when starting a doc. 313 * So these need to be synced up from any resulting native changes 314 * by a user dialog. 315 * But the native changes call up to into the attributeset, and that 316 * should be sufficient, since before heading down to native either 317 * to (re-)display a dialog, or to print the doc, these are all 318 * re-populated from the AttributeSet, 319 * Nonetheless having them in sync with the attributeset and native 320 * state is probably safer. 321 * Also whereas the startDoc native code pulls the variables directly, 322 * the dialog code does use getter to pull some of these values. 323 * That's an inconsistency we should fix if it causes problems. 324 */ 325 private int mAttSides; 326 private int mAttChromaticity; 327 private int mAttXRes; 328 private int mAttYRes; 329 private int mAttQuality; 330 private int mAttCollate; 331 private int mAttCopies; 332 private int mAttMediaSizeName; 333 private int mAttMediaTray; 334 335 private String mDestination = null; 336 337 /** 338 * The last color set into the print device context or 339 * {@code null} if no color has been set. 340 */ 341 private Color mLastColor; 342 343 /** 344 * The last text color set into the print device context or 345 * {@code null} if no color has been set. 346 */ 347 private Color mLastTextColor; 348 349 /** 350 * Define the most recent java font set as a GDI font in the printer 351 * device context. mLastFontFamily will be NULL if no 352 * GDI font has been set. 353 */ 354 private String mLastFontFamily; 355 private float mLastFontSize; 356 private int mLastFontStyle; 357 private int mLastRotation; 358 private float mLastAwScale; 359 360 // for AwtPrintControl::InitPrintDialog 361 private PrinterJob pjob; 362 363 private java.awt.peer.ComponentPeer dialogOwnerPeer = null; 364 365 /* Static Initializations */ 366 367 static { 368 // AWT has to be initialized for the native code to function correctly. 369 Toolkit.getDefaultToolkit(); 370 371 initIDs(); 372 373 Win32FontManager.registerJREFontsForPrinting(); 374 } 375 376 /* Constructors */ 377 378 public WPrinterJob() 379 { 380 Disposer.addRecord(disposerReferent, 381 handleRecord = new HandleRecord()); 382 initAttributeMembers(); 383 } 384 385 /* Implement DisposerTarget. Weak references to an Object can delay 386 * its storage reclaimation marginally. 387 * It won't make the native resources be release any more quickly, but 388 * by pointing the reference held by Disposer at an object which becomes 389 * no longer strongly reachable when this WPrinterJob is no longer 390 * strongly reachable, we allow the WPrinterJob to be freed more promptly 391 * than if it were the referenced object. 392 */ 393 private Object disposerReferent = new Object(); 394 395 @Override 396 public Object getDisposerReferent() { 397 return disposerReferent; 398 } 399 400 /* Instance Methods */ 401 402 /** 403 * Display a dialog to the user allowing the modification of a 404 * PageFormat instance. 405 * The {@code page} argument is used to initialize controls 406 * in the page setup dialog. 407 * If the user cancels the dialog, then the method returns the 408 * original {@code page} object unmodified. 409 * If the user okays the dialog then the method returns a new 410 * PageFormat object with the indicated changes. 411 * In either case the original {@code page} object will 412 * not be modified. 413 * @param page the default PageFormat presented to the user 414 * for modification 415 * @return the original {@code page} object if the dialog 416 * is cancelled, or a new PageFormat object containing 417 * the format indicated by the user if the dialog is 418 * acknowledged 419 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 420 * returns true. 421 * @see java.awt.GraphicsEnvironment#isHeadless 422 * @since 1.2 423 */ 424 @Override 425 public PageFormat pageDialog(PageFormat page) throws HeadlessException { 426 if (GraphicsEnvironment.isHeadless()) { 427 throw new HeadlessException(); 428 } 429 430 if (!(getPrintService() instanceof Win32PrintService)) { 431 return super.pageDialog(page); 432 } 433 434 PageFormat pageClone = (PageFormat) page.clone(); 435 boolean result = false; 436 437 /* 438 * Fix for 4507585: show the native modal dialog the same way printDialog() does so 439 * that it won't block event dispatching when called on EventDispatchThread. 440 */ 441 WPageDialog dialog = new WPageDialog((Frame)null, this, 442 pageClone, null); 443 dialog.setRetVal(false); 444 dialog.setVisible(true); 445 result = dialog.getRetVal(); 446 dialog.dispose(); 447 448 // myService => current PrintService 449 if (result && (myService != null)) { 450 // It's possible that current printer is changed through 451 // the "Printer..." button so we query again from native. 452 String printerName = getNativePrintService(); 453 if (!myService.getName().equals(printerName)) { 454 // native printer is different ! 455 // we update the current PrintService 456 try { 457 setPrintService(PrintServiceLookupProvider. 458 getWin32PrintLUS(). 459 getPrintServiceByName(printerName)); 460 } catch (PrinterException e) { 461 } 462 } 463 // Update attributes, this will preserve the page settings. 464 // - same code as in RasterPrinterJob.java 465 updatePageAttributes(myService, pageClone); 466 467 return pageClone; 468 } else { 469 return page; 470 } 471 } 472 473 474 private boolean displayNativeDialog() { 475 // "attributes" is required for getting the updated attributes 476 if (attributes == null) { 477 return false; 478 } 479 480 DialogOwner dlgOwner = (DialogOwner)attributes.get(DialogOwner.class); 481 Window owner = (dlgOwner != null) ? dlgOwner.getOwner() : null; 482 483 WPrintDialog dialog = (owner instanceof Frame) ? 484 new WPrintDialog((Frame)owner, this) : 485 new WPrintDialog((Dialog)owner, this); 486 487 dialog.setRetVal(false); 488 dialog.setVisible(true); 489 boolean prv = dialog.getRetVal(); 490 dialog.dispose(); 491 492 Destination dest = 493 (Destination)attributes.get(Destination.class); 494 if ((dest == null) || !prv){ 495 return prv; 496 } else { 497 String title = null; 498 String strBundle = "sun.print.resources.serviceui"; 499 ResourceBundle rb = ResourceBundle.getBundle(strBundle); 500 try { 501 title = rb.getString("dialog.printtofile"); 502 } catch (MissingResourceException e) { 503 } 504 FileDialog fileDialog = (owner instanceof Frame) ? 505 new FileDialog((Frame)owner, title, FileDialog.SAVE) : 506 new FileDialog((Dialog)owner, title, FileDialog.SAVE); 507 508 URI destURI = dest.getURI(); 509 // Old code destURI.getPath() would return null for "file:out.prn" 510 // so we use getSchemeSpecificPart instead. 511 String pathName = (destURI != null) ? 512 destURI.getSchemeSpecificPart() : null; 513 if (pathName != null) { 514 File file = new File(pathName); 515 fileDialog.setFile(file.getName()); 516 File parent = file.getParentFile(); 517 if (parent != null) { 518 fileDialog.setDirectory(parent.getPath()); 519 } 520 } else { 521 fileDialog.setFile("out.prn"); 522 } 523 524 fileDialog.setVisible(true); 525 String fileName = fileDialog.getFile(); 526 if (fileName == null) { 527 fileDialog.dispose(); 528 return false; 529 } 530 String fullName = fileDialog.getDirectory() + fileName; 531 File f = new File(fullName); 532 File pFile = f.getParentFile(); 533 while ((f.exists() && 534 (!f.isFile() || !f.canWrite())) || 535 ((pFile != null) && 536 (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) { 537 538 if (owner instanceof Frame) { 539 (new PrintToFileErrorDialog((Frame)owner, 540 ServiceDialog.getMsg("dialog.owtitle"), 541 ServiceDialog.getMsg("dialog.writeerror")+" "+fullName, 542 ServiceDialog.getMsg("button.ok"))).setVisible(true); 543 } else { 544 (new PrintToFileErrorDialog((Dialog)owner, 545 ServiceDialog.getMsg("dialog.owtitle"), 546 ServiceDialog.getMsg("dialog.writeerror")+" "+fullName, 547 ServiceDialog.getMsg("button.ok"))).setVisible(true); 548 } 549 550 fileDialog.setVisible(true); 551 fileName = fileDialog.getFile(); 552 if (fileName == null) { 553 fileDialog.dispose(); 554 return false; 555 } 556 fullName = fileDialog.getDirectory() + fileName; 557 f = new File(fullName); 558 pFile = f.getParentFile(); 559 } 560 fileDialog.dispose(); 561 attributes.add(new Destination(f.toURI())); 562 return true; 563 } 564 565 } 566 567 /** 568 * Presents the user a dialog for changing properties of the 569 * print job interactively. 570 * @return false if the user cancels the dialog and 571 * true otherwise. 572 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 573 * returns true. 574 * @see java.awt.GraphicsEnvironment#isHeadless 575 */ 576 @Override 577 public boolean printDialog() throws HeadlessException { 578 579 if (GraphicsEnvironment.isHeadless()) { 580 throw new HeadlessException(); 581 } 582 // current request attribute set should be reflected to the print dialog. 583 // If null, create new instance of HashPrintRequestAttributeSet. 584 if (attributes == null) { 585 attributes = new HashPrintRequestAttributeSet(); 586 } 587 588 if (!(getPrintService() instanceof Win32PrintService)) { 589 return super.printDialog(attributes); 590 } 591 592 if (noDefaultPrinter == true) { 593 return false; 594 } else { 595 return displayNativeDialog(); 596 } 597 } 598 599 /** 600 * Associate this PrinterJob with a new PrintService. 601 * 602 * Throws {@code PrinterException} if the specified service 603 * cannot support the {@code Pageable} and 604 * </code>Printable</code> interfaces necessary to support 2D printing. 605 * @param service print service which supports 2D printing. 606 * 607 * @throws PrinterException if the specified service does not support 608 * 2D printing. 609 */ 610 @Override 611 public void setPrintService(PrintService service) 612 throws PrinterException { 613 super.setPrintService(service); 614 if (!(service instanceof Win32PrintService)) { 615 return; 616 } 617 driverDoesMultipleCopies = false; 618 driverDoesCollation = false; 619 setNativePrintServiceIfNeeded(service.getName()); 620 } 621 622 /* associates this job with the specified native service */ 623 private native void setNativePrintService(String name) 624 throws PrinterException; 625 626 private String lastNativeService = null; 627 private void setNativePrintServiceIfNeeded(String name) 628 throws PrinterException { 629 630 if (name != null && !(name.equals(lastNativeService))) { 631 setNativePrintService(name); 632 lastNativeService = name; 633 } 634 } 635 636 @Override 637 public PrintService getPrintService() { 638 if (myService == null) { 639 String printerName = getNativePrintService(); 640 641 if (printerName != null) { 642 myService = PrintServiceLookupProvider.getWin32PrintLUS(). 643 getPrintServiceByName(printerName); 644 // no need to call setNativePrintService as this name is 645 // currently set in native 646 if (myService != null) { 647 return myService; 648 } 649 } 650 651 myService = PrintServiceLookup.lookupDefaultPrintService(); 652 if (myService instanceof Win32PrintService) { 653 try { 654 setNativePrintServiceIfNeeded(myService.getName()); 655 } catch (Exception e) { 656 myService = null; 657 } 658 } 659 660 } 661 return myService; 662 } 663 664 private native String getNativePrintService(); 665 666 private void initAttributeMembers() { 667 mAttSides = 0; 668 mAttChromaticity = 0; 669 mAttXRes = 0; 670 mAttYRes = 0; 671 mAttQuality = 0; 672 mAttCollate = -1; 673 mAttCopies = 0; 674 mAttMediaTray = 0; 675 mAttMediaSizeName = 0; 676 mDestination = null; 677 678 } 679 680 /** 681 * copy the attributes to the native print job 682 * Note that this method, and hence the re-initialisation 683 * of the GDI values is done on each entry to the print dialog since 684 * an app could redisplay the print dialog for the same job and 685 * 1) the application may have changed attribute settings 686 * 2) the application may have changed the printer. 687 * In the event that the user changes the printer using the 688 dialog, then it is up to GDI to report back all changed values. 689 */ 690 @Override 691 protected void setAttributes(PrintRequestAttributeSet attributes) 692 throws PrinterException { 693 694 // initialize attribute values 695 initAttributeMembers(); 696 super.setAttributes(attributes); 697 698 mAttCopies = getCopiesInt(); 699 mDestination = destinationAttr; 700 701 if (attributes == null) { 702 return; // now always use attributes, so this shouldn't happen. 703 } 704 Attribute[] attrs = attributes.toArray(); 705 for (int i=0; i< attrs.length; i++) { 706 Attribute attr = attrs[i]; 707 try { 708 if (attr.getCategory() == Sides.class) { 709 setSidesAttrib(attr); 710 } 711 else if (attr.getCategory() == Chromaticity.class) { 712 setColorAttrib(attr); 713 } 714 else if (attr.getCategory() == PrinterResolution.class) { 715 if (myService.isAttributeValueSupported(attr, null, null)) { 716 setResolutionAttrib(attr); 717 } 718 } 719 else if (attr.getCategory() == PrintQuality.class) { 720 setQualityAttrib(attr); 721 } 722 else if (attr.getCategory() == SheetCollate.class) { 723 setCollateAttrib(attr); 724 } else if (attr.getCategory() == Media.class || 725 attr.getCategory() == SunAlternateMedia.class) { 726 /* SunAlternateMedia is used if its a tray, and 727 * any Media that is specified is not a tray. 728 */ 729 if (attr.getCategory() == SunAlternateMedia.class) { 730 Media media = (Media)attributes.get(Media.class); 731 if (media == null || 732 !(media instanceof MediaTray)) { 733 attr = ((SunAlternateMedia)attr).getMedia(); 734 } 735 } 736 if (attr instanceof MediaSizeName) { 737 setWin32MediaAttrib(attr); 738 } 739 if (attr instanceof MediaTray) { 740 setMediaTrayAttrib(attr); 741 } 742 } 743 744 } catch (ClassCastException e) { 745 } 746 } 747 } 748 749 /** 750 * Alters the orientation and Paper to match defaults obtained 751 * from a printer. 752 */ 753 private native void getDefaultPage(PageFormat page); 754 755 /** 756 * The passed in PageFormat will be copied and altered to describe 757 * the default page size and orientation of the PrinterJob's 758 * current printer. 759 * Note: PageFormat.getPaper() returns a clone and getDefaultPage() 760 * gets that clone so it won't overwrite the original paper. 761 */ 762 @Override 763 public PageFormat defaultPage(PageFormat page) { 764 PageFormat newPage = (PageFormat)page.clone(); 765 getDefaultPage(newPage); 766 return newPage; 767 } 768 769 /** 770 * validate the paper size against the current printer. 771 */ 772 @Override 773 protected native void validatePaper(Paper origPaper, Paper newPaper ); 774 775 /** 776 * Examine the metrics captured by the 777 * {@code PeekGraphics} instance and 778 * if capable of directly converting this 779 * print job to the printer's control language 780 * or the native OS's graphics primitives, then 781 * return a {@code PathGraphics} to perform 782 * that conversion. If there is not an object 783 * capable of the conversion then return 784 * {@code null}. Returning {@code null} 785 * causes the print job to be rasterized. 786 */ 787 788 @Override 789 protected Graphics2D createPathGraphics(PeekGraphics peekGraphics, 790 PrinterJob printerJob, 791 Printable painter, 792 PageFormat pageFormat, 793 int pageIndex) { 794 795 WPathGraphics pathGraphics; 796 PeekMetrics metrics = peekGraphics.getMetrics(); 797 798 /* If the application has drawn anything that 799 * out PathGraphics class can not handle then 800 * return a null PathGraphics. If the property 801 * to force the raster pipeline has been set then 802 * we also want to avoid the path (pdl) pipeline 803 * and return null. 804 */ 805 if (forcePDL == false && (forceRaster == true 806 || metrics.hasNonSolidColors() 807 || metrics.hasCompositing() 808 )) { 809 pathGraphics = null; 810 } else { 811 BufferedImage bufferedImage = new BufferedImage(8, 8, 812 BufferedImage.TYPE_INT_RGB); 813 Graphics2D bufferedGraphics = bufferedImage.createGraphics(); 814 815 boolean canRedraw = peekGraphics.getAWTDrawingOnly() == false; 816 pathGraphics = new WPathGraphics(bufferedGraphics, printerJob, 817 painter, pageFormat, pageIndex, 818 canRedraw); 819 } 820 821 return pathGraphics; 822 } 823 824 825 @Override 826 protected double getXRes() { 827 if (mAttXRes != 0) { 828 return mAttXRes; 829 } else { 830 return mPrintXRes; 831 } 832 } 833 834 @Override 835 protected double getYRes() { 836 if (mAttYRes != 0) { 837 return mAttYRes; 838 } else { 839 return mPrintYRes; 840 } 841 } 842 843 @Override 844 protected double getPhysicalPrintableX(Paper p) { 845 return mPrintPhysX; 846 } 847 848 @Override 849 protected double getPhysicalPrintableY(Paper p) { 850 return mPrintPhysY; 851 } 852 853 @Override 854 protected double getPhysicalPrintableWidth(Paper p) { 855 return mPrintWidth; 856 } 857 858 @Override 859 protected double getPhysicalPrintableHeight(Paper p) { 860 return mPrintHeight; 861 } 862 863 @Override 864 protected double getPhysicalPageWidth(Paper p) { 865 return mPageWidth; 866 } 867 868 @Override 869 protected double getPhysicalPageHeight(Paper p) { 870 return mPageHeight; 871 } 872 873 /** 874 * We don't (yet) provide API to support collation, and 875 * when we do the logic here will require adjustment, but 876 * this method is currently necessary to honour user-originated 877 * collation requests - which can only originate from the print dialog. 878 * REMIND: check if this can be deleted already. 879 */ 880 @Override 881 protected boolean isCollated() { 882 return userRequestedCollation; 883 } 884 885 /** 886 * Returns how many times the entire book should 887 * be printed by the PrintJob. If the printer 888 * itself supports collation then this method 889 * should return 1 indicating that the entire 890 * book need only be printed once and the copies 891 * will be collated and made in the printer. 892 */ 893 @Override 894 protected int getCollatedCopies() { 895 debug_println("driverDoesMultipleCopies="+driverDoesMultipleCopies 896 +" driverDoesCollation="+driverDoesCollation); 897 if (super.isCollated() && !driverDoesCollation) { 898 // we will do our own collation so we need to 899 // tell the printer to not collate 900 mAttCollate = 0; 901 mAttCopies = 1; 902 return getCopies(); 903 } 904 905 return 1; 906 } 907 908 /** 909 * Returns how many times each page in the book 910 * should be consecutively printed by PrinterJob. 911 * If the underlying Window's driver will 912 * generate the copies, rather than having RasterPrinterJob 913 * iterate over the number of copies, this method always returns 914 * 1. 915 */ 916 @Override 917 protected int getNoncollatedCopies() { 918 if (driverDoesMultipleCopies || super.isCollated()) { 919 return 1; 920 } else { 921 return getCopies(); 922 } 923 } 924 925 /* These getter/setters are called from native code */ 926 927 /** 928 * Return the Window's device context that we are printing 929 * into. 930 */ 931 private long getPrintDC() { 932 return handleRecord.mPrintDC; 933 } 934 935 private void setPrintDC(long mPrintDC) { 936 handleRecord.mPrintDC = mPrintDC; 937 } 938 939 private long getDevMode() { 940 return handleRecord.mPrintHDevMode; 941 } 942 943 private void setDevMode(long mPrintHDevMode) { 944 handleRecord.mPrintHDevMode = mPrintHDevMode; 945 } 946 947 private long getDevNames() { 948 return handleRecord.mPrintHDevNames; 949 } 950 951 private void setDevNames(long mPrintHDevNames) { 952 handleRecord.mPrintHDevNames = mPrintHDevNames; 953 } 954 955 protected void beginPath() { 956 beginPath(getPrintDC()); 957 } 958 959 protected void endPath() { 960 endPath(getPrintDC()); 961 } 962 963 protected void closeFigure() { 964 closeFigure(getPrintDC()); 965 } 966 967 protected void fillPath() { 968 fillPath(getPrintDC()); 969 } 970 971 protected void moveTo(float x, float y) { 972 moveTo(getPrintDC(), x, y); 973 } 974 975 protected void lineTo(float x, float y) { 976 lineTo(getPrintDC(), x, y); 977 } 978 979 protected void polyBezierTo(float control1x, float control1y, 980 float control2x, float control2y, 981 float endX, float endY) { 982 983 polyBezierTo(getPrintDC(), control1x, control1y, 984 control2x, control2y, 985 endX, endY); 986 } 987 988 /** 989 * Set the current polgon fill rule into the printer device context. 990 * The {@code fillRule} should 991 * be one of the following Windows constants: 992 * {@code ALTERNATE} or {@code WINDING}. 993 */ 994 protected void setPolyFillMode(int fillRule) { 995 setPolyFillMode(getPrintDC(), fillRule); 996 } 997 998 /* 999 * Create a Window's solid brush for the color specified 1000 * by {@code (red, green, blue)}. Once the brush 1001 * is created, select it in the current printing device 1002 * context and free the old brush. 1003 */ 1004 protected void selectSolidBrush(Color color) { 1005 1006 /* We only need to select a brush if the color has changed. 1007 */ 1008 if (color.equals(mLastColor) == false) { 1009 mLastColor = color; 1010 float[] rgb = color.getRGBColorComponents(null); 1011 1012 selectSolidBrush(getPrintDC(), 1013 (int) (rgb[0] * MAX_WCOLOR), 1014 (int) (rgb[1] * MAX_WCOLOR), 1015 (int) (rgb[2] * MAX_WCOLOR)); 1016 } 1017 } 1018 1019 /** 1020 * Return the x coordinate of the current pen 1021 * position in the print device context. 1022 */ 1023 protected int getPenX() { 1024 1025 return getPenX(getPrintDC()); 1026 } 1027 1028 1029 /** 1030 * Return the y coordinate of the current pen 1031 * position in the print device context. 1032 */ 1033 protected int getPenY() { 1034 1035 return getPenY(getPrintDC()); 1036 } 1037 1038 /** 1039 * Set the current path in the printer device's 1040 * context to be clipping path. 1041 */ 1042 protected void selectClipPath() { 1043 selectClipPath(getPrintDC()); 1044 } 1045 1046 1047 protected void frameRect(float x, float y, float width, float height) { 1048 frameRect(getPrintDC(), x, y, width, height); 1049 } 1050 1051 protected void fillRect(float x, float y, float width, float height, 1052 Color color) { 1053 float[] rgb = color.getRGBColorComponents(null); 1054 1055 fillRect(getPrintDC(), x, y, width, height, 1056 (int) (rgb[0] * MAX_WCOLOR), 1057 (int) (rgb[1] * MAX_WCOLOR), 1058 (int) (rgb[2] * MAX_WCOLOR)); 1059 } 1060 1061 1062 protected void selectPen(float width, Color color) { 1063 1064 float[] rgb = color.getRGBColorComponents(null); 1065 1066 selectPen(getPrintDC(), width, 1067 (int) (rgb[0] * MAX_WCOLOR), 1068 (int) (rgb[1] * MAX_WCOLOR), 1069 (int) (rgb[2] * MAX_WCOLOR)); 1070 } 1071 1072 1073 protected boolean selectStylePen(int cap, int join, float width, 1074 Color color) { 1075 1076 long endCap; 1077 long lineJoin; 1078 1079 float[] rgb = color.getRGBColorComponents(null); 1080 1081 switch(cap) { 1082 case BasicStroke.CAP_BUTT: endCap = PS_ENDCAP_FLAT; break; 1083 case BasicStroke.CAP_ROUND: endCap = PS_ENDCAP_ROUND; break; 1084 default: 1085 case BasicStroke.CAP_SQUARE: endCap = PS_ENDCAP_SQUARE; break; 1086 } 1087 1088 switch(join) { 1089 case BasicStroke.JOIN_BEVEL:lineJoin = PS_JOIN_BEVEL; break; 1090 default: 1091 case BasicStroke.JOIN_MITER:lineJoin = PS_JOIN_MITER; break; 1092 case BasicStroke.JOIN_ROUND:lineJoin = PS_JOIN_ROUND; break; 1093 } 1094 1095 return (selectStylePen(getPrintDC(), endCap, lineJoin, width, 1096 (int) (rgb[0] * MAX_WCOLOR), 1097 (int) (rgb[1] * MAX_WCOLOR), 1098 (int) (rgb[2] * MAX_WCOLOR))); 1099 } 1100 1101 /** 1102 * Set a GDI font capable of drawing the java Font 1103 * passed in. 1104 */ 1105 protected boolean setFont(String family, float size, int style, 1106 int rotation, float awScale) { 1107 1108 boolean didSetFont = true; 1109 1110 if (!family.equals(mLastFontFamily) || 1111 size != mLastFontSize || 1112 style != mLastFontStyle || 1113 rotation != mLastRotation || 1114 awScale != mLastAwScale) { 1115 1116 didSetFont = setFont(getPrintDC(), 1117 family, 1118 size, 1119 (style & Font.BOLD) != 0, 1120 (style & Font.ITALIC) != 0, 1121 rotation, awScale); 1122 if (didSetFont) { 1123 mLastFontFamily = family; 1124 mLastFontSize = size; 1125 mLastFontStyle = style; 1126 mLastRotation = rotation; 1127 mLastAwScale = awScale; 1128 } 1129 } 1130 return didSetFont; 1131 } 1132 1133 /** 1134 * Set the GDI color for text drawing. 1135 */ 1136 protected void setTextColor(Color color) { 1137 1138 /* We only need to select a brush if the color has changed. 1139 */ 1140 if (color.equals(mLastTextColor) == false) { 1141 mLastTextColor = color; 1142 float[] rgb = color.getRGBColorComponents(null); 1143 1144 setTextColor(getPrintDC(), 1145 (int) (rgb[0] * MAX_WCOLOR), 1146 (int) (rgb[1] * MAX_WCOLOR), 1147 (int) (rgb[2] * MAX_WCOLOR)); 1148 } 1149 } 1150 1151 /** 1152 * Remove control characters. 1153 */ 1154 @Override 1155 protected String removeControlChars(String str) { 1156 return super.removeControlChars(str); 1157 } 1158 1159 /** 1160 * Draw the string {@code text} to the printer's 1161 * device context at the specified position. 1162 */ 1163 protected void textOut(String str, float x, float y, 1164 float[] positions) { 1165 /* Don't leave handling of control chars to GDI. 1166 * If control chars are removed, 'positions' isn't valid. 1167 * This means the caller needs to be aware of this and remove 1168 * control chars up front if supplying positions. Since the 1169 * caller is tightly integrated here, that's acceptable. 1170 */ 1171 String text = removeControlChars(str); 1172 assert (positions == null) || (text.length() == str.length()); 1173 if (text.length() == 0) { 1174 return; 1175 } 1176 textOut(getPrintDC(), text, text.length(), false, x, y, positions); 1177 } 1178 1179 /** 1180 * Draw the glyphs {@code glyphs} to the printer's 1181 * device context at the specified position. 1182 */ 1183 protected void glyphsOut(int []glyphs, float x, float y, 1184 float[] positions) { 1185 1186 /* TrueType glyph codes are 16 bit values, so can be packed 1187 * in a unicode string, and that's how GDI expects them. 1188 * A flag bit is set to indicate to GDI that these are glyphs, 1189 * not characters. The positions array must always be non-null 1190 * here for our purposes, although if not supplied, GDI should 1191 * just use the default advances for the glyphs. 1192 * Mask out upper 16 bits to remove any slot from a composite. 1193 */ 1194 char[] glyphCharArray = new char[glyphs.length]; 1195 for (int i=0;i<glyphs.length;i++) { 1196 glyphCharArray[i] = (char)(glyphs[i] & 0xffff); 1197 } 1198 String glyphStr = new String(glyphCharArray); 1199 textOut(getPrintDC(), glyphStr, glyphs.length, true, x, y, positions); 1200 } 1201 1202 1203 /** 1204 * Get the advance of this text that GDI returns for the 1205 * font currently selected into the GDI device context for 1206 * this job. Note that the removed control characters are 1207 * interpreted as zero-width by JDK and we remove them for 1208 * rendering so also remove them for measurement so that 1209 * this measurement can be properly compared with JDK measurement. 1210 */ 1211 protected int getGDIAdvance(String text) { 1212 /* Don't leave handling of control chars to GDI. */ 1213 text = removeControlChars(text); 1214 if (text.length() == 0) { 1215 return 0; 1216 } 1217 return getGDIAdvance(getPrintDC(), text); 1218 } 1219 1220 /** 1221 * Draw the 24 bit BGR image buffer represented by 1222 * {@code image} to the GDI device context 1223 * {@code printDC}. The image is drawn at 1224 * {@code (destX, destY)} in device coordinates. 1225 * The image is scaled into a square of size 1226 * specified by {@code destWidth} and 1227 * {@code destHeight}. The portion of the 1228 * source image copied into that square is specified 1229 * by {@code srcX}, {@code srcY}, 1230 * {@code srcWidth}, and srcHeight. 1231 */ 1232 protected void drawImage3ByteBGR(byte[] image, 1233 float destX, float destY, 1234 float destWidth, float destHeight, 1235 float srcX, float srcY, 1236 float srcWidth, float srcHeight) { 1237 1238 1239 drawDIBImage(getPrintDC(), image, 1240 destX, destY, 1241 destWidth, destHeight, 1242 srcX, srcY, 1243 srcWidth, srcHeight, 1244 24, null); 1245 1246 } 1247 1248 /* If 'icm' is null we expect its 24 bit (ie 3BYTE_BGR). 1249 * If 'icm' is non-null we expect its no more than 8 bpp and 1250 * specifically must be a valid DIB sizes : 1, 4 or 8 bpp. 1251 * Then we need to extract the colours into a byte array of the 1252 * format required by GDI which is an array of 'RGBQUAD' 1253 * RGBQUAD looks like : 1254 * typedef struct tagRGBQUAD { 1255 * BYTE rgbBlue; 1256 * BYTE rgbGreen; 1257 * BYTE rgbRed; 1258 * BYTE rgbReserved; // must be zero. 1259 * } RGBQUAD; 1260 * There's no alignment problem as GDI expects this to be packed 1261 * and each struct will start on a 4 byte boundary anyway. 1262 */ 1263 protected void drawDIBImage(byte[] image, 1264 float destX, float destY, 1265 float destWidth, float destHeight, 1266 float srcX, float srcY, 1267 float srcWidth, float srcHeight, 1268 int sampleBitsPerPixel, 1269 IndexColorModel icm) { 1270 int bitCount = 24; 1271 byte[] bmiColors = null; 1272 1273 if (icm != null) { 1274 bitCount = sampleBitsPerPixel; 1275 bmiColors = new byte[(1<<icm.getPixelSize())*4]; 1276 for (int i=0;i<icm.getMapSize(); i++) { 1277 bmiColors[i*4+0]=(byte)(icm.getBlue(i)&0xff); 1278 bmiColors[i*4+1]=(byte)(icm.getGreen(i)&0xff); 1279 bmiColors[i*4+2]=(byte)(icm.getRed(i)&0xff); 1280 } 1281 } 1282 1283 drawDIBImage(getPrintDC(), image, 1284 destX, destY, 1285 destWidth, destHeight, 1286 srcX, srcY, 1287 srcWidth, srcHeight, 1288 bitCount, bmiColors); 1289 } 1290 1291 /** 1292 * Begin a new page. 1293 */ 1294 @Override 1295 protected void startPage(PageFormat format, Printable painter, 1296 int index, boolean paperChanged) { 1297 1298 /* Invalidate any device state caches we are 1299 * maintaining. Win95/98 resets the device 1300 * context attributes to default values at 1301 * the start of each page. 1302 */ 1303 invalidateCachedState(); 1304 1305 deviceStartPage(format, painter, index, paperChanged); 1306 } 1307 1308 /** 1309 * End a page. 1310 */ 1311 @Override 1312 protected void endPage(PageFormat format, Printable painter, 1313 int index) { 1314 1315 deviceEndPage(format, painter, index); 1316 } 1317 1318 /** 1319 * Forget any device state we may have cached. 1320 */ 1321 private void invalidateCachedState() { 1322 mLastColor = null; 1323 mLastTextColor = null; 1324 mLastFontFamily = null; 1325 } 1326 1327 private boolean defaultCopies = true; 1328 /** 1329 * Set the number of copies to be printed. 1330 */ 1331 @Override 1332 public void setCopies(int copies) { 1333 super.setCopies(copies); 1334 defaultCopies = false; 1335 mAttCopies = copies; 1336 setNativeCopies(copies); 1337 } 1338 1339 1340 /* Native Methods */ 1341 1342 /** 1343 * Set copies in device. 1344 */ 1345 private native void setNativeCopies(int copies); 1346 1347 /** 1348 * Displays the print dialog and records the user's settings 1349 * into this object. Return false if the user cancels the 1350 * dialog. 1351 * If the dialog is to use a set of attributes, useAttributes is true. 1352 */ 1353 private native boolean jobSetup(Pageable doc, boolean allowPrintToFile); 1354 1355 /* Make sure printer DC is intialised and that info about the printer 1356 * is reflected back up to Java code 1357 */ 1358 @Override 1359 protected native void initPrinter(); 1360 1361 /** 1362 * Call Window's StartDoc routine to begin a 1363 * print job. The DC from the print dialog is 1364 * used. If the print dialog was not displayed 1365 * then a DC for the default printer is created. 1366 * The native StartDoc returns false if the end-user cancelled 1367 * printing. This is possible if the printer is connected to FILE: 1368 * in which case windows queries the user for a destination and the 1369 * user may cancel out of it. Note that the implementation of 1370 * cancel() throws PrinterAbortException to indicate the user cancelled. 1371 */ 1372 private native boolean _startDoc(String dest, String jobName) 1373 throws PrinterException; 1374 @Override 1375 protected void startDoc() throws PrinterException { 1376 if (!_startDoc(mDestination, getJobName())) { 1377 cancel(); 1378 } 1379 } 1380 1381 /** 1382 * Call Window's EndDoc routine to end a 1383 * print job. 1384 */ 1385 @Override 1386 protected native void endDoc(); 1387 1388 /** 1389 * Call Window's AbortDoc routine to abort a 1390 * print job. 1391 */ 1392 @Override 1393 protected native void abortDoc(); 1394 1395 /** 1396 * Call Windows native resource freeing APIs 1397 */ 1398 private static native void deleteDC(long dc, long devmode, long devnames); 1399 1400 /** 1401 * Begin a new page. This call's Window's 1402 * StartPage routine. 1403 */ 1404 protected native void deviceStartPage(PageFormat format, Printable painter, 1405 int index, boolean paperChanged); 1406 /** 1407 * End a page. This call's Window's EndPage 1408 * routine. 1409 */ 1410 protected native void deviceEndPage(PageFormat format, Printable painter, 1411 int index); 1412 1413 /** 1414 * Prints the contents of the array of ints, 'data' 1415 * to the current page. The band is placed at the 1416 * location (x, y) in device coordinates on the 1417 * page. The width and height of the band is 1418 * specified by the caller. 1419 */ 1420 @Override 1421 protected native void printBand(byte[] data, int x, int y, 1422 int width, int height); 1423 1424 /** 1425 * Begin a Window's rendering path in the device 1426 * context {@code printDC}. 1427 */ 1428 protected native void beginPath(long printDC); 1429 1430 /** 1431 * End a Window's rendering path in the device 1432 * context {@code printDC}. 1433 */ 1434 protected native void endPath(long printDC); 1435 1436 /** 1437 * Close a subpath in a Window's rendering path in the device 1438 * context {@code printDC}. 1439 */ 1440 protected native void closeFigure(long printDC); 1441 1442 /** 1443 * Fill a defined Window's rendering path in the device 1444 * context {@code printDC}. 1445 */ 1446 protected native void fillPath(long printDC); 1447 1448 /** 1449 * Move the Window's pen position to {@code (x,y)} 1450 * in the device context {@code printDC}. 1451 */ 1452 protected native void moveTo(long printDC, float x, float y); 1453 1454 /** 1455 * Draw a line from the current pen position to 1456 * {@code (x,y)} in the device context {@code printDC}. 1457 */ 1458 protected native void lineTo(long printDC, float x, float y); 1459 1460 protected native void polyBezierTo(long printDC, 1461 float control1x, float control1y, 1462 float control2x, float control2y, 1463 float endX, float endY); 1464 1465 /** 1466 * Set the current polgon fill rule into the device context 1467 * {@code printDC}. The {@code fillRule} should 1468 * be one of the following Windows constants: 1469 * {@code ALTERNATE} or {@code WINDING}. 1470 */ 1471 protected native void setPolyFillMode(long printDC, int fillRule); 1472 1473 /** 1474 * Create a Window's solid brush for the color specified 1475 * by {@code (red, green, blue)}. Once the brush 1476 * is created, select it in the device 1477 * context {@code printDC} and free the old brush. 1478 */ 1479 protected native void selectSolidBrush(long printDC, 1480 int red, int green, int blue); 1481 1482 /** 1483 * Return the x coordinate of the current pen 1484 * position in the device context 1485 * {@code printDC}. 1486 */ 1487 protected native int getPenX(long printDC); 1488 1489 /** 1490 * Return the y coordinate of the current pen 1491 * position in the device context 1492 * {@code printDC}. 1493 */ 1494 protected native int getPenY(long printDC); 1495 1496 /** 1497 * Select the device context's current path 1498 * to be the clipping path. 1499 */ 1500 protected native void selectClipPath(long printDC); 1501 1502 /** 1503 * Draw a rectangle using specified brush. 1504 */ 1505 protected native void frameRect(long printDC, float x, float y, 1506 float width, float height); 1507 1508 /** 1509 * Fill a rectangle specified by the coordinates using 1510 * specified brush. 1511 */ 1512 protected native void fillRect(long printDC, float x, float y, 1513 float width, float height, 1514 int red, int green, int blue); 1515 1516 /** 1517 * Create a solid brush using the RG & B colors and width. 1518 * Select this brush and delete the old one. 1519 */ 1520 protected native void selectPen(long printDC, float width, 1521 int red, int green, int blue); 1522 1523 /** 1524 * Create a solid brush using the RG & B colors and specified 1525 * pen styles. Select this created brush and delete the old one. 1526 */ 1527 protected native boolean selectStylePen(long printDC, long cap, 1528 long join, float width, 1529 int red, int green, int blue); 1530 1531 /** 1532 * Set a GDI font capable of drawing the java Font 1533 * passed in. 1534 */ 1535 protected native boolean setFont(long printDC, String familyName, 1536 float fontSize, 1537 boolean bold, 1538 boolean italic, 1539 int rotation, 1540 float awScale); 1541 1542 1543 /** 1544 * Set the GDI color for text drawing. 1545 */ 1546 protected native void setTextColor(long printDC, 1547 int red, int green, int blue); 1548 1549 1550 /** 1551 * Draw the string {@code text} into the device 1552 * context {@code printDC} at the specified 1553 * position. 1554 */ 1555 protected native void textOut(long printDC, String text, 1556 int strlen, boolean glyphs, 1557 float x, float y, float[] positions); 1558 1559 1560 private native int getGDIAdvance(long printDC, String text); 1561 1562 /** 1563 * Draw the DIB compatible image buffer represented by 1564 * {@code image} to the GDI device context 1565 * {@code printDC}. The image is drawn at 1566 * {@code (destX, destY)} in device coordinates. 1567 * The image is scaled into a square of size 1568 * specified by {@code destWidth} and 1569 * {@code destHeight}. The portion of the 1570 * source image copied into that square is specified 1571 * by {@code srcX}, {@code srcY}, 1572 * {@code srcWidth}, and srcHeight. 1573 * Note that the image isn't completely compatible with DIB format. 1574 * At the very least it needs to be padded so each scanline is 1575 * DWORD aligned. Also we "flip" the image to make it a bottom-up DIB. 1576 */ 1577 private native void drawDIBImage(long printDC, byte[] image, 1578 float destX, float destY, 1579 float destWidth, float destHeight, 1580 float srcX, float srcY, 1581 float srcWidth, float srcHeight, 1582 int bitCount, byte[] bmiColors); 1583 1584 1585 //** BEGIN Functions called by native code for querying/updating attributes 1586 1587 private String getPrinterAttrib() { 1588 // getPrintService will get current print service or default if none 1589 PrintService service = this.getPrintService(); 1590 String name = (service != null) ? service.getName() : null; 1591 return name; 1592 } 1593 1594 /* SheetCollate */ 1595 private int getCollateAttrib() { 1596 // -1 means unset, 0 uncollated, 1 collated. 1597 return mAttCollate; 1598 } 1599 1600 private void setCollateAttrib(Attribute attr) { 1601 if (attr == SheetCollate.COLLATED) { 1602 mAttCollate = 1; // DMCOLLATE_TRUE 1603 } else { 1604 mAttCollate = 0; // DMCOLLATE_FALSE 1605 } 1606 } 1607 1608 private void setCollateAttrib(Attribute attr, 1609 PrintRequestAttributeSet set) { 1610 setCollateAttrib(attr); 1611 set.add(attr); 1612 } 1613 1614 /* Orientation */ 1615 1616 private int getOrientAttrib() { 1617 int orient = PageFormat.PORTRAIT; 1618 OrientationRequested orientReq = (attributes == null) ? null : 1619 (OrientationRequested)attributes.get(OrientationRequested.class); 1620 if (orientReq == null) { 1621 orientReq = (OrientationRequested) 1622 myService.getDefaultAttributeValue(OrientationRequested.class); 1623 } 1624 if (orientReq != null) { 1625 if (orientReq == OrientationRequested.REVERSE_LANDSCAPE) { 1626 orient = PageFormat.REVERSE_LANDSCAPE; 1627 } else if (orientReq == OrientationRequested.LANDSCAPE) { 1628 orient = PageFormat.LANDSCAPE; 1629 } 1630 } 1631 1632 return orient; 1633 } 1634 1635 private void setOrientAttrib(Attribute attr, 1636 PrintRequestAttributeSet set) { 1637 if (set != null) { 1638 set.add(attr); 1639 } 1640 } 1641 1642 /* Copies and Page Range. */ 1643 private int getCopiesAttrib() { 1644 if (defaultCopies) { 1645 return 0; 1646 } else { 1647 return getCopiesInt(); 1648 } 1649 } 1650 1651 private void setRangeCopiesAttribute(int from, int to, boolean isRangeSet, 1652 int copies) { 1653 if (attributes != null) { 1654 if (isRangeSet) { 1655 attributes.add(new PageRanges(from, to)); 1656 setPageRange(from, to); 1657 } 1658 defaultCopies = false; 1659 attributes.add(new Copies(copies)); 1660 /* Since this is called from native to tell Java to sync 1661 * up with native, we don't call this class's own setCopies() 1662 * method which is mainly to send the value down to native 1663 */ 1664 super.setCopies(copies); 1665 mAttCopies = copies; 1666 } 1667 } 1668 1669 1670 1671 private boolean getDestAttrib() { 1672 return (mDestination != null); 1673 } 1674 1675 /* Quality */ 1676 private int getQualityAttrib() { 1677 return mAttQuality; 1678 } 1679 1680 private void setQualityAttrib(Attribute attr) { 1681 if (attr == PrintQuality.HIGH) { 1682 mAttQuality = -4; // DMRES_HIGH 1683 } else if (attr == PrintQuality.NORMAL) { 1684 mAttQuality = -3; // DMRES_MEDIUM 1685 } else { 1686 mAttQuality = -2; // DMRES_LOW 1687 } 1688 } 1689 1690 private void setQualityAttrib(Attribute attr, 1691 PrintRequestAttributeSet set) { 1692 setQualityAttrib(attr); 1693 set.add(attr); 1694 } 1695 1696 /* Color/Chromaticity */ 1697 private int getColorAttrib() { 1698 return mAttChromaticity; 1699 } 1700 1701 private void setColorAttrib(Attribute attr) { 1702 if (attr == Chromaticity.COLOR) { 1703 mAttChromaticity = 2; // DMCOLOR_COLOR 1704 } else { 1705 mAttChromaticity = 1; // DMCOLOR_MONOCHROME 1706 } 1707 } 1708 1709 private void setColorAttrib(Attribute attr, 1710 PrintRequestAttributeSet set) { 1711 setColorAttrib(attr); 1712 set.add(attr); 1713 } 1714 1715 /* Sides */ 1716 private int getSidesAttrib() { 1717 return mAttSides; 1718 } 1719 1720 private void setSidesAttrib(Attribute attr) { 1721 if (attr == Sides.TWO_SIDED_LONG_EDGE) { 1722 mAttSides = 2; // DMDUP_VERTICAL 1723 } else if (attr == Sides.TWO_SIDED_SHORT_EDGE) { 1724 mAttSides = 3; // DMDUP_HORIZONTAL 1725 } else { // Sides.ONE_SIDED 1726 mAttSides = 1; 1727 } 1728 } 1729 1730 private void setSidesAttrib(Attribute attr, 1731 PrintRequestAttributeSet set) { 1732 setSidesAttrib(attr); 1733 set.add(attr); 1734 } 1735 1736 /** MediaSizeName / dmPaper */ 1737 private int[] getWin32MediaAttrib() { 1738 int wid_ht[] = {0, 0}; 1739 if (attributes != null) { 1740 Media media = (Media)attributes.get(Media.class); 1741 if (media instanceof MediaSizeName) { 1742 MediaSizeName msn = (MediaSizeName)media; 1743 MediaSize ms = MediaSize.getMediaSizeForName(msn); 1744 if (ms != null) { 1745 wid_ht[0] = (int)(ms.getX(MediaSize.INCH) * 72.0); 1746 wid_ht[1] = (int)(ms.getY(MediaSize.INCH) * 72.0); 1747 } 1748 } 1749 } 1750 return wid_ht; 1751 } 1752 1753 private void setWin32MediaAttrib(Attribute attr) { 1754 if (!(attr instanceof MediaSizeName)) { 1755 return; 1756 } 1757 MediaSizeName msn = (MediaSizeName)attr; 1758 mAttMediaSizeName = ((Win32PrintService)myService).findPaperID(msn); 1759 } 1760 1761 private void addPaperSize(PrintRequestAttributeSet aset, 1762 int dmIndex, int width, int length) { 1763 1764 if (aset == null) { 1765 return; 1766 } 1767 MediaSizeName msn = 1768 ((Win32PrintService)myService).findWin32Media(dmIndex); 1769 if (msn == null) { 1770 msn = ((Win32PrintService)myService). 1771 findMatchingMediaSizeNameMM((float)width, (float)length); 1772 } 1773 1774 if (msn != null) { 1775 aset.add(msn); 1776 } 1777 } 1778 1779 private void setWin32MediaAttrib(int dmIndex, int width, int length) { 1780 addPaperSize(attributes, dmIndex, width, length); 1781 mAttMediaSizeName = dmIndex; 1782 } 1783 1784 /* MediaTray / dmTray */ 1785 private void setMediaTrayAttrib(Attribute attr) { 1786 if (attr == MediaTray.BOTTOM) { 1787 mAttMediaTray = 2; // DMBIN_LOWER 1788 } else if (attr == MediaTray.ENVELOPE) { 1789 mAttMediaTray = 5; // DMBIN_ENVELOPE 1790 } else if (attr == MediaTray.LARGE_CAPACITY) { 1791 mAttMediaTray = 11; // DMBIN_LARGECAPACITY 1792 } else if (attr == MediaTray.MAIN) { 1793 mAttMediaTray =1; // DMBIN_UPPER 1794 } else if (attr == MediaTray.MANUAL) { 1795 mAttMediaTray = 4; // DMBIN_MANUAL 1796 } else if (attr == MediaTray.MIDDLE) { 1797 mAttMediaTray = 3; // DMBIN_MIDDLE 1798 } else if (attr == MediaTray.SIDE) { 1799 // no equivalent predefined value 1800 mAttMediaTray = 7; // DMBIN_AUTO 1801 } else if (attr == MediaTray.TOP) { 1802 mAttMediaTray = 1; // DMBIN_UPPER 1803 } else { 1804 if (attr instanceof Win32MediaTray) { 1805 mAttMediaTray = ((Win32MediaTray)attr).winID; 1806 } else { 1807 mAttMediaTray = 1; // default 1808 } 1809 } 1810 } 1811 1812 private void setMediaTrayAttrib(int dmBinID) { 1813 mAttMediaTray = dmBinID; 1814 MediaTray tray = ((Win32PrintService)myService).findMediaTray(dmBinID); 1815 } 1816 1817 private int getMediaTrayAttrib() { 1818 return mAttMediaTray; 1819 } 1820 1821 1822 1823 private boolean getPrintToFileEnabled() { 1824 SecurityManager security = System.getSecurityManager(); 1825 if (security != null) { 1826 FilePermission printToFilePermission = 1827 new FilePermission("<<ALL FILES>>", "read,write"); 1828 try { 1829 security.checkPermission(printToFilePermission); 1830 } catch (SecurityException e) { 1831 return false; 1832 } 1833 } 1834 return true; 1835 } 1836 1837 private void setNativeAttributes(int flags, int fields, int values) { 1838 if (attributes == null) { 1839 return; 1840 } 1841 if ((flags & PD_PRINTTOFILE) != 0) { 1842 Destination destPrn = (Destination)attributes.get( 1843 Destination.class); 1844 if (destPrn == null) { 1845 try { 1846 attributes.add(new Destination( 1847 new File("./out.prn").toURI())); 1848 } catch (SecurityException se) { 1849 try { 1850 attributes.add(new Destination( 1851 new URI("file:out.prn"))); 1852 } catch (URISyntaxException e) { 1853 } 1854 } 1855 } 1856 } else { 1857 attributes.remove(Destination.class); 1858 } 1859 1860 if ((flags & PD_COLLATE) != 0) { 1861 setCollateAttrib(SheetCollate.COLLATED, attributes); 1862 } else { 1863 setCollateAttrib(SheetCollate.UNCOLLATED, attributes); 1864 } 1865 1866 if ((flags & PD_NOSELECTION) != PD_NOSELECTION) { 1867 if ((flags & PD_PAGENUMS) != 0) { 1868 attributes.add(SunPageSelection.RANGE); 1869 } else if ((flags & PD_SELECTION) != 0) { 1870 attributes.add(SunPageSelection.SELECTION); 1871 } else { 1872 attributes.add(SunPageSelection.ALL); 1873 } 1874 } 1875 1876 if ((fields & DM_ORIENTATION) != 0) { 1877 if ((values & SET_ORIENTATION) != 0) { 1878 setOrientAttrib(OrientationRequested.LANDSCAPE, attributes); 1879 } else { 1880 setOrientAttrib(OrientationRequested.PORTRAIT, attributes); 1881 } 1882 } 1883 1884 if ((fields & DM_COLOR) != 0) { 1885 if ((values & SET_COLOR) != 0) { 1886 setColorAttrib(Chromaticity.COLOR, attributes); 1887 } else { 1888 setColorAttrib(Chromaticity.MONOCHROME, attributes); 1889 } 1890 } 1891 1892 if ((fields & DM_PRINTQUALITY) != 0) { 1893 PrintQuality quality; 1894 if ((values & SET_RES_LOW) != 0) { 1895 quality = PrintQuality.DRAFT; 1896 } else if ((fields & SET_RES_HIGH) != 0) { 1897 quality = PrintQuality.HIGH; 1898 } else { 1899 quality = PrintQuality.NORMAL; 1900 } 1901 setQualityAttrib(quality, attributes); 1902 } 1903 1904 if ((fields & DM_DUPLEX) != 0) { 1905 Sides sides; 1906 if ((values & SET_DUP_VERTICAL) != 0) { 1907 sides = Sides.TWO_SIDED_LONG_EDGE; 1908 } else if ((values & SET_DUP_HORIZONTAL) != 0) { 1909 sides = Sides.TWO_SIDED_SHORT_EDGE; 1910 } else { 1911 sides = Sides.ONE_SIDED; 1912 } 1913 setSidesAttrib(sides, attributes); 1914 } 1915 } 1916 1917 private static final class DevModeValues { 1918 int dmFields; 1919 short copies; 1920 short collate; 1921 short color; 1922 short duplex; 1923 short orient; 1924 short paper; 1925 short bin; 1926 short xres_quality; 1927 short yres; 1928 } 1929 1930 private void getDevModeValues(PrintRequestAttributeSet aset, 1931 DevModeValues info) { 1932 1933 Copies c = (Copies)aset.get(Copies.class); 1934 if (c != null) { 1935 info.dmFields |= DM_COPIES; 1936 info.copies = (short)c.getValue(); 1937 } 1938 1939 SheetCollate sc = (SheetCollate)aset.get(SheetCollate.class); 1940 if (sc != null) { 1941 info.dmFields |= DM_COLLATE; 1942 info.collate = (sc == SheetCollate.COLLATED) ? 1943 DMCOLLATE_TRUE : DMCOLLATE_FALSE; 1944 } 1945 1946 Chromaticity ch = (Chromaticity)aset.get(Chromaticity.class); 1947 if (ch != null) { 1948 info.dmFields |= DM_COLOR; 1949 if (ch == Chromaticity.COLOR) { 1950 info.color = DMCOLOR_COLOR; 1951 } else { 1952 info.color = DMCOLOR_MONOCHROME; 1953 } 1954 } 1955 1956 Sides s = (Sides)aset.get(Sides.class); 1957 if (s != null) { 1958 info.dmFields |= DM_DUPLEX; 1959 if (s == Sides.TWO_SIDED_LONG_EDGE) { 1960 info.duplex = DMDUP_VERTICAL; 1961 } else if (s == Sides.TWO_SIDED_SHORT_EDGE) { 1962 info.duplex = DMDUP_HORIZONTAL; 1963 } else { // Sides.ONE_SIDED 1964 info.duplex = DMDUP_SIMPLEX; 1965 } 1966 } 1967 1968 OrientationRequested or = 1969 (OrientationRequested)aset.get(OrientationRequested.class); 1970 if (or != null) { 1971 info.dmFields |= DM_ORIENTATION; 1972 info.orient = (or == OrientationRequested.LANDSCAPE) 1973 ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT; 1974 } 1975 1976 Media m = (Media)aset.get(Media.class); 1977 if (m instanceof MediaSizeName) { 1978 info.dmFields |= DM_PAPERSIZE; 1979 MediaSizeName msn = (MediaSizeName)m; 1980 info.paper = 1981 (short)((Win32PrintService)myService).findPaperID(msn); 1982 } 1983 1984 MediaTray mt = null; 1985 if (m instanceof MediaTray) { 1986 mt = (MediaTray)m; 1987 } 1988 if (mt == null) { 1989 SunAlternateMedia sam = 1990 (SunAlternateMedia)aset.get(SunAlternateMedia.class); 1991 if (sam != null && (sam.getMedia() instanceof MediaTray)) { 1992 mt = (MediaTray)sam.getMedia(); 1993 } 1994 } 1995 1996 if (mt != null) { 1997 info.dmFields |= DM_DEFAULTSOURCE; 1998 info.bin = (short)(((Win32PrintService)myService).findTrayID(mt)); 1999 } 2000 2001 PrintQuality q = (PrintQuality)aset.get(PrintQuality.class); 2002 if (q != null) { 2003 info.dmFields |= DM_PRINTQUALITY; 2004 if (q == PrintQuality.DRAFT) { 2005 info.xres_quality = DMRES_DRAFT; 2006 } else if (q == PrintQuality.HIGH) { 2007 info.xres_quality = DMRES_HIGH; 2008 } else { 2009 info.xres_quality = DMRES_MEDIUM; 2010 } 2011 } 2012 2013 PrinterResolution r = 2014 (PrinterResolution)aset.get(PrinterResolution.class); 2015 if (r != null) { 2016 info.dmFields |= DM_PRINTQUALITY | DM_YRESOLUTION; 2017 info.xres_quality = 2018 (short)r.getCrossFeedResolution(PrinterResolution.DPI); 2019 info.yres = (short)r.getFeedResolution(PrinterResolution.DPI); 2020 } 2021 } 2022 2023 /* This method is called from native to update the values in the 2024 * attribute set which originates from the cross-platform dialog, 2025 * but updated by the native DocumentPropertiesUI which updates the 2026 * devmode. This syncs the devmode back in to the attributes so that 2027 * we can update the cross-platform dialog. 2028 * The attribute set here is a temporary one installed whilst this 2029 * happens, 2030 */ 2031 private void setJobAttributes(PrintRequestAttributeSet attributes, 2032 int fields, int values, 2033 short copies, 2034 short dmPaperSize, 2035 short dmPaperWidth, 2036 short dmPaperLength, 2037 short dmDefaultSource, 2038 short xRes, 2039 short yRes) { 2040 2041 if (attributes == null) { 2042 return; 2043 } 2044 2045 if ((fields & DM_COPIES) != 0) { 2046 attributes.add(new Copies(copies)); 2047 } 2048 2049 if ((fields & DM_COLLATE) != 0) { 2050 if ((values & SET_COLLATED) != 0) { 2051 attributes.add(SheetCollate.COLLATED); 2052 } else { 2053 attributes.add(SheetCollate.UNCOLLATED); 2054 } 2055 } 2056 2057 if ((fields & DM_ORIENTATION) != 0) { 2058 if ((values & SET_ORIENTATION) != 0) { 2059 attributes.add(OrientationRequested.LANDSCAPE); 2060 } else { 2061 attributes.add(OrientationRequested.PORTRAIT); 2062 } 2063 } 2064 2065 if ((fields & DM_COLOR) != 0) { 2066 if ((values & SET_COLOR) != 0) { 2067 attributes.add(Chromaticity.COLOR); 2068 } else { 2069 attributes.add(Chromaticity.MONOCHROME); 2070 } 2071 } 2072 2073 if ((fields & DM_PRINTQUALITY) != 0) { 2074 /* value < 0 indicates quality setting. 2075 * value > 0 indicates X resolution. In that case 2076 * hopefully we will also find y-resolution specified. 2077 * If its not, assume its the same as x-res. 2078 * Maybe Java code should try to reconcile this against 2079 * the printers claimed set of supported resolutions. 2080 */ 2081 if (xRes < 0) { 2082 PrintQuality quality; 2083 if ((values & SET_RES_LOW) != 0) { 2084 quality = PrintQuality.DRAFT; 2085 } else if ((fields & SET_RES_HIGH) != 0) { 2086 quality = PrintQuality.HIGH; 2087 } else { 2088 quality = PrintQuality.NORMAL; 2089 } 2090 attributes.add(quality); 2091 } else if (xRes > 0 && yRes > 0) { 2092 attributes.add( 2093 new PrinterResolution(xRes, yRes, PrinterResolution.DPI)); 2094 } 2095 } 2096 2097 if ((fields & DM_DUPLEX) != 0) { 2098 Sides sides; 2099 if ((values & SET_DUP_VERTICAL) != 0) { 2100 sides = Sides.TWO_SIDED_LONG_EDGE; 2101 } else if ((values & SET_DUP_HORIZONTAL) != 0) { 2102 sides = Sides.TWO_SIDED_SHORT_EDGE; 2103 } else { 2104 sides = Sides.ONE_SIDED; 2105 } 2106 attributes.add(sides); 2107 } 2108 2109 if ((fields & DM_PAPERSIZE) != 0) { 2110 addPaperSize(attributes, dmPaperSize, dmPaperWidth, dmPaperLength); 2111 } 2112 2113 if ((fields & DM_DEFAULTSOURCE) != 0) { 2114 MediaTray tray = 2115 ((Win32PrintService)myService).findMediaTray(dmDefaultSource); 2116 attributes.add(new SunAlternateMedia(tray)); 2117 } 2118 } 2119 2120 private native boolean showDocProperties(long hWnd, 2121 PrintRequestAttributeSet aset, 2122 int dmFields, 2123 short copies, 2124 short collate, 2125 short color, 2126 short duplex, 2127 short orient, 2128 short paper, 2129 short bin, 2130 short xres_quality, 2131 short yres); 2132 2133 public PrintRequestAttributeSet 2134 showDocumentProperties(Window owner, 2135 PrintService service, 2136 PrintRequestAttributeSet aset) 2137 { 2138 try { 2139 setNativePrintServiceIfNeeded(service.getName()); 2140 } catch (PrinterException e) { 2141 } 2142 final ComponentAccessor acc = AWTAccessor.getComponentAccessor(); 2143 long hWnd = acc.<WComponentPeer>getPeer(owner).getHWnd(); 2144 DevModeValues info = new DevModeValues(); 2145 getDevModeValues(aset, info); 2146 boolean ok = 2147 showDocProperties(hWnd, aset, 2148 info.dmFields, 2149 info.copies, 2150 info.collate, 2151 info.color, 2152 info.duplex, 2153 info.orient, 2154 info.paper, 2155 info.bin, 2156 info.xres_quality, 2157 info.yres); 2158 2159 if (ok) { 2160 return aset; 2161 } else { 2162 return null; 2163 } 2164 } 2165 2166 /* Printer Resolution. See also getXRes() and getYRes() */ 2167 private void setResolutionDPI(int xres, int yres) { 2168 if (attributes != null) { 2169 PrinterResolution res = 2170 new PrinterResolution(xres, yres, PrinterResolution.DPI); 2171 attributes.add(res); 2172 } 2173 mAttXRes = xres; 2174 mAttYRes = yres; 2175 } 2176 2177 private void setResolutionAttrib(Attribute attr) { 2178 PrinterResolution pr = (PrinterResolution)attr; 2179 mAttXRes = pr.getCrossFeedResolution(PrinterResolution.DPI); 2180 mAttYRes = pr.getFeedResolution(PrinterResolution.DPI); 2181 } 2182 2183 private void setPrinterNameAttrib(String printerName) { 2184 PrintService service = this.getPrintService(); 2185 2186 if (printerName == null) { 2187 return; 2188 } 2189 2190 if (service != null && printerName.equals(service.getName())) { 2191 return; 2192 } else { 2193 PrintService []services = PrinterJob.lookupPrintServices(); 2194 for (int i=0; i<services.length; i++) { 2195 if (printerName.equals(services[i].getName())) { 2196 2197 try { 2198 this.setPrintService(services[i]); 2199 } catch (PrinterException e) { 2200 } 2201 return; 2202 } 2203 } 2204 } 2205 //** END Functions called by native code for querying/updating attributes 2206 2207 } 2208 2209 @SuppressWarnings("serial") // JDK-implementation class 2210 class PrintToFileErrorDialog extends Dialog implements ActionListener{ 2211 public PrintToFileErrorDialog(Frame parent, String title, String message, 2212 String buttonText) { 2213 super(parent, title, true); 2214 init (parent, title, message, buttonText); 2215 } 2216 2217 public PrintToFileErrorDialog(Dialog parent, String title, String message, 2218 String buttonText) { 2219 super(parent, title, true); 2220 init (parent, title, message, buttonText); 2221 } 2222 2223 private void init(Component parent, String title, String message, 2224 String buttonText) { 2225 Panel p = new Panel(); 2226 add("Center", new Label(message)); 2227 Button btn = new Button(buttonText); 2228 btn.addActionListener(this); 2229 p.add(btn); 2230 add("South", p); 2231 pack(); 2232 2233 Dimension dDim = getSize(); 2234 if (parent != null) { 2235 Rectangle fRect = parent.getBounds(); 2236 setLocation(fRect.x + ((fRect.width - dDim.width) / 2), 2237 fRect.y + ((fRect.height - dDim.height) / 2)); 2238 } 2239 } 2240 2241 @Override 2242 public void actionPerformed(ActionEvent event) { 2243 setVisible(false); 2244 dispose(); 2245 return; 2246 } 2247 } 2248 2249 2250 2251 2252 /** 2253 * Initialize JNI field and method ids 2254 */ 2255 private static native void initIDs(); 2256 2257 }