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.OrientationRequested; 83 import javax.print.attribute.standard.Media; 84 import javax.print.attribute.standard.MediaSizeName; 85 import javax.print.attribute.standard.MediaSize; 86 import javax.print.attribute.standard.MediaTray; 87 import javax.print.attribute.standard.PageRanges; 88 89 import sun.awt.Win32FontManager; 90 91 import sun.print.RasterPrinterJob; 92 import sun.print.SunAlternateMedia; 93 import sun.print.SunPageSelection; 94 import sun.print.Win32MediaTray; 95 import sun.print.Win32PrintService; 96 import sun.print.PrintServiceLookupProvider; 97 import sun.print.ServiceDialog; 98 import sun.print.DialogOwner; 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 ownerFrame = (dlgOwner != null) ? dlgOwner.getOwner() : null; 482 483 WPrintDialog dialog; 484 if (ownerFrame instanceof Frame) { 485 dialog = new WPrintDialog((Frame)ownerFrame, this); 486 } else { 487 dialog = new WPrintDialog((Dialog)ownerFrame, this); 488 } 489 dialog.setRetVal(false); 490 dialog.setVisible(true); 491 boolean prv = dialog.getRetVal(); 492 dialog.dispose(); 493 494 Destination dest = 495 (Destination)attributes.get(Destination.class); 496 if ((dest == null) || !prv){ 497 return prv; 498 } else { 499 String title = null; 500 String strBundle = "sun.print.resources.serviceui"; 501 ResourceBundle rb = ResourceBundle.getBundle(strBundle); 502 try { 503 title = rb.getString("dialog.printtofile"); 504 } catch (MissingResourceException e) { 505 } 506 FileDialog fileDialog; 507 if (ownerFrame instanceof Frame) { 508 fileDialog = new FileDialog((Frame)ownerFrame, title, 509 FileDialog.SAVE); 510 } else { 511 fileDialog = new FileDialog((Dialog)ownerFrame, title, 512 FileDialog.SAVE); 513 } 514 515 URI destURI = dest.getURI(); 516 // Old code destURI.getPath() would return null for "file:out.prn" 517 // so we use getSchemeSpecificPart instead. 518 String pathName = (destURI != null) ? 519 destURI.getSchemeSpecificPart() : null; 520 if (pathName != null) { 521 File file = new File(pathName); 522 fileDialog.setFile(file.getName()); 523 File parent = file.getParentFile(); 524 if (parent != null) { 525 fileDialog.setDirectory(parent.getPath()); 526 } 527 } else { 528 fileDialog.setFile("out.prn"); 529 } 530 531 fileDialog.setVisible(true); 532 String fileName = fileDialog.getFile(); 533 if (fileName == null) { 534 fileDialog.dispose(); 535 return false; 536 } 537 String fullName = fileDialog.getDirectory() + fileName; 538 File f = new File(fullName); 539 File pFile = f.getParentFile(); 540 while ((f.exists() && 541 (!f.isFile() || !f.canWrite())) || 542 ((pFile != null) && 543 (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) { 544 545 if (ownerFrame instanceof Frame) { 546 (new PrintToFileErrorDialog((Frame)ownerFrame, 547 ServiceDialog.getMsg("dialog.owtitle"), 548 ServiceDialog.getMsg("dialog.writeerror")+" "+fullName, 549 ServiceDialog.getMsg("button.ok"))).setVisible(true); 550 } else { 551 (new PrintToFileErrorDialog((Dialog)ownerFrame, 552 ServiceDialog.getMsg("dialog.owtitle"), 553 ServiceDialog.getMsg("dialog.writeerror")+" "+fullName, 554 ServiceDialog.getMsg("button.ok"))).setVisible(true); 555 } 556 557 fileDialog.setVisible(true); 558 fileName = fileDialog.getFile(); 559 if (fileName == null) { 560 fileDialog.dispose(); 561 return false; 562 } 563 fullName = fileDialog.getDirectory() + fileName; 564 f = new File(fullName); 565 pFile = f.getParentFile(); 566 } 567 fileDialog.dispose(); 568 attributes.add(new Destination(f.toURI())); 569 return true; 570 } 571 572 } 573 574 /** 575 * Presents the user a dialog for changing properties of the 576 * print job interactively. 577 * @return false if the user cancels the dialog and 578 * true otherwise. 579 * @exception HeadlessException if GraphicsEnvironment.isHeadless() 580 * returns true. 581 * @see java.awt.GraphicsEnvironment#isHeadless 582 */ 583 @Override 584 public boolean printDialog() throws HeadlessException { 585 586 if (GraphicsEnvironment.isHeadless()) { 587 throw new HeadlessException(); 588 } 589 // current request attribute set should be reflected to the print dialog. 590 // If null, create new instance of HashPrintRequestAttributeSet. 591 if (attributes == null) { 592 attributes = new HashPrintRequestAttributeSet(); 593 } 594 595 if (!(getPrintService() instanceof Win32PrintService)) { 596 return super.printDialog(attributes); 597 } 598 599 if (noDefaultPrinter == true) { 600 return false; 601 } else { 602 return displayNativeDialog(); 603 } 604 } 605 606 /** 607 * Associate this PrinterJob with a new PrintService. 608 * 609 * Throws {@code PrinterException} if the specified service 610 * cannot support the {@code Pageable} and 611 * </code>Printable</code> interfaces necessary to support 2D printing. 612 * @param service print service which supports 2D printing. 613 * 614 * @throws PrinterException if the specified service does not support 615 * 2D printing. 616 */ 617 @Override 618 public void setPrintService(PrintService service) 619 throws PrinterException { 620 super.setPrintService(service); 621 if (!(service instanceof Win32PrintService)) { 622 return; 623 } 624 driverDoesMultipleCopies = false; 625 driverDoesCollation = false; 626 setNativePrintServiceIfNeeded(service.getName()); 627 } 628 629 /* associates this job with the specified native service */ 630 private native void setNativePrintService(String name) 631 throws PrinterException; 632 633 private String lastNativeService = null; 634 private void setNativePrintServiceIfNeeded(String name) 635 throws PrinterException { 636 637 if (name != null && !(name.equals(lastNativeService))) { 638 setNativePrintService(name); 639 lastNativeService = name; 640 } 641 } 642 643 @Override 644 public PrintService getPrintService() { 645 if (myService == null) { 646 String printerName = getNativePrintService(); 647 648 if (printerName != null) { 649 myService = PrintServiceLookupProvider.getWin32PrintLUS(). 650 getPrintServiceByName(printerName); 651 // no need to call setNativePrintService as this name is 652 // currently set in native 653 if (myService != null) { 654 return myService; 655 } 656 } 657 658 myService = PrintServiceLookup.lookupDefaultPrintService(); 659 if (myService instanceof Win32PrintService) { 660 try { 661 setNativePrintServiceIfNeeded(myService.getName()); 662 } catch (Exception e) { 663 myService = null; 664 } 665 } 666 667 } 668 return myService; 669 } 670 671 private native String getNativePrintService(); 672 673 private void initAttributeMembers() { 674 mAttSides = 0; 675 mAttChromaticity = 0; 676 mAttXRes = 0; 677 mAttYRes = 0; 678 mAttQuality = 0; 679 mAttCollate = -1; 680 mAttCopies = 0; 681 mAttMediaTray = 0; 682 mAttMediaSizeName = 0; 683 mDestination = null; 684 685 } 686 687 /** 688 * copy the attributes to the native print job 689 * Note that this method, and hence the re-initialisation 690 * of the GDI values is done on each entry to the print dialog since 691 * an app could redisplay the print dialog for the same job and 692 * 1) the application may have changed attribute settings 693 * 2) the application may have changed the printer. 694 * In the event that the user changes the printer using the 695 dialog, then it is up to GDI to report back all changed values. 696 */ 697 @Override 698 protected void setAttributes(PrintRequestAttributeSet attributes) 699 throws PrinterException { 700 701 // initialize attribute values 702 initAttributeMembers(); 703 super.setAttributes(attributes); 704 705 mAttCopies = getCopiesInt(); 706 mDestination = destinationAttr; 707 708 if (attributes == null) { 709 return; // now always use attributes, so this shouldn't happen. 710 } 711 Attribute[] attrs = attributes.toArray(); 712 for (int i=0; i< attrs.length; i++) { 713 Attribute attr = attrs[i]; 714 try { 715 if (attr.getCategory() == Sides.class) { 716 setSidesAttrib(attr); 717 } 718 else if (attr.getCategory() == Chromaticity.class) { 719 setColorAttrib(attr); 720 } 721 else if (attr.getCategory() == PrinterResolution.class) { 722 if (myService.isAttributeValueSupported(attr, null, null)) { 723 setResolutionAttrib(attr); 724 } 725 } 726 else if (attr.getCategory() == PrintQuality.class) { 727 setQualityAttrib(attr); 728 } 729 else if (attr.getCategory() == SheetCollate.class) { 730 setCollateAttrib(attr); 731 } else if (attr.getCategory() == Media.class || 732 attr.getCategory() == SunAlternateMedia.class) { 733 /* SunAlternateMedia is used if its a tray, and 734 * any Media that is specified is not a tray. 735 */ 736 if (attr.getCategory() == SunAlternateMedia.class) { 737 Media media = (Media)attributes.get(Media.class); 738 if (media == null || 739 !(media instanceof MediaTray)) { 740 attr = ((SunAlternateMedia)attr).getMedia(); 741 } 742 } 743 if (attr instanceof MediaSizeName) { 744 setWin32MediaAttrib(attr); 745 } 746 if (attr instanceof MediaTray) { 747 setMediaTrayAttrib(attr); 748 } 749 } 750 751 } catch (ClassCastException e) { 752 } 753 } 754 } 755 756 /** 757 * Alters the orientation and Paper to match defaults obtained 758 * from a printer. 759 */ 760 private native void getDefaultPage(PageFormat page); 761 762 /** 763 * The passed in PageFormat will be copied and altered to describe 764 * the default page size and orientation of the PrinterJob's 765 * current printer. 766 * Note: PageFormat.getPaper() returns a clone and getDefaultPage() 767 * gets that clone so it won't overwrite the original paper. 768 */ 769 @Override 770 public PageFormat defaultPage(PageFormat page) { 771 PageFormat newPage = (PageFormat)page.clone(); 772 getDefaultPage(newPage); 773 return newPage; 774 } 775 776 /** 777 * validate the paper size against the current printer. 778 */ 779 @Override 780 protected native void validatePaper(Paper origPaper, Paper newPaper ); 781 782 /** 783 * Examine the metrics captured by the 784 * {@code PeekGraphics} instance and 785 * if capable of directly converting this 786 * print job to the printer's control language 787 * or the native OS's graphics primitives, then 788 * return a {@code PathGraphics} to perform 789 * that conversion. If there is not an object 790 * capable of the conversion then return 791 * {@code null}. Returning {@code null} 792 * causes the print job to be rasterized. 793 */ 794 795 @Override 796 protected Graphics2D createPathGraphics(PeekGraphics peekGraphics, 797 PrinterJob printerJob, 798 Printable painter, 799 PageFormat pageFormat, 800 int pageIndex) { 801 802 WPathGraphics pathGraphics; 803 PeekMetrics metrics = peekGraphics.getMetrics(); 804 805 /* If the application has drawn anything that 806 * out PathGraphics class can not handle then 807 * return a null PathGraphics. If the property 808 * to force the raster pipeline has been set then 809 * we also want to avoid the path (pdl) pipeline 810 * and return null. 811 */ 812 if (forcePDL == false && (forceRaster == true 813 || metrics.hasNonSolidColors() 814 || metrics.hasCompositing() 815 )) { 816 pathGraphics = null; 817 } else { 818 BufferedImage bufferedImage = new BufferedImage(8, 8, 819 BufferedImage.TYPE_INT_RGB); 820 Graphics2D bufferedGraphics = bufferedImage.createGraphics(); 821 822 boolean canRedraw = peekGraphics.getAWTDrawingOnly() == false; 823 pathGraphics = new WPathGraphics(bufferedGraphics, printerJob, 824 painter, pageFormat, pageIndex, 825 canRedraw); 826 } 827 828 return pathGraphics; 829 } 830 831 832 @Override 833 protected double getXRes() { 834 if (mAttXRes != 0) { 835 return mAttXRes; 836 } else { 837 return mPrintXRes; 838 } 839 } 840 841 @Override 842 protected double getYRes() { 843 if (mAttYRes != 0) { 844 return mAttYRes; 845 } else { 846 return mPrintYRes; 847 } 848 } 849 850 @Override 851 protected double getPhysicalPrintableX(Paper p) { 852 return mPrintPhysX; 853 } 854 855 @Override 856 protected double getPhysicalPrintableY(Paper p) { 857 return mPrintPhysY; 858 } 859 860 @Override 861 protected double getPhysicalPrintableWidth(Paper p) { 862 return mPrintWidth; 863 } 864 865 @Override 866 protected double getPhysicalPrintableHeight(Paper p) { 867 return mPrintHeight; 868 } 869 870 @Override 871 protected double getPhysicalPageWidth(Paper p) { 872 return mPageWidth; 873 } 874 875 @Override 876 protected double getPhysicalPageHeight(Paper p) { 877 return mPageHeight; 878 } 879 880 /** 881 * We don't (yet) provide API to support collation, and 882 * when we do the logic here will require adjustment, but 883 * this method is currently necessary to honour user-originated 884 * collation requests - which can only originate from the print dialog. 885 * REMIND: check if this can be deleted already. 886 */ 887 @Override 888 protected boolean isCollated() { 889 return userRequestedCollation; 890 } 891 892 /** 893 * Returns how many times the entire book should 894 * be printed by the PrintJob. If the printer 895 * itself supports collation then this method 896 * should return 1 indicating that the entire 897 * book need only be printed once and the copies 898 * will be collated and made in the printer. 899 */ 900 @Override 901 protected int getCollatedCopies() { 902 debug_println("driverDoesMultipleCopies="+driverDoesMultipleCopies 903 +" driverDoesCollation="+driverDoesCollation); 904 if (super.isCollated() && !driverDoesCollation) { 905 // we will do our own collation so we need to 906 // tell the printer to not collate 907 mAttCollate = 0; 908 mAttCopies = 1; 909 return getCopies(); 910 } 911 912 return 1; 913 } 914 915 /** 916 * Returns how many times each page in the book 917 * should be consecutively printed by PrinterJob. 918 * If the underlying Window's driver will 919 * generate the copies, rather than having RasterPrinterJob 920 * iterate over the number of copies, this method always returns 921 * 1. 922 */ 923 @Override 924 protected int getNoncollatedCopies() { 925 if (driverDoesMultipleCopies || super.isCollated()) { 926 return 1; 927 } else { 928 return getCopies(); 929 } 930 } 931 932 /* These getter/setters are called from native code */ 933 934 /** 935 * Return the Window's device context that we are printing 936 * into. 937 */ 938 private long getPrintDC() { 939 return handleRecord.mPrintDC; 940 } 941 942 private void setPrintDC(long mPrintDC) { 943 handleRecord.mPrintDC = mPrintDC; 944 } 945 946 private long getDevMode() { 947 return handleRecord.mPrintHDevMode; 948 } 949 950 private void setDevMode(long mPrintHDevMode) { 951 handleRecord.mPrintHDevMode = mPrintHDevMode; 952 } 953 954 private long getDevNames() { 955 return handleRecord.mPrintHDevNames; 956 } 957 958 private void setDevNames(long mPrintHDevNames) { 959 handleRecord.mPrintHDevNames = mPrintHDevNames; 960 } 961 962 protected void beginPath() { 963 beginPath(getPrintDC()); 964 } 965 966 protected void endPath() { 967 endPath(getPrintDC()); 968 } 969 970 protected void closeFigure() { 971 closeFigure(getPrintDC()); 972 } 973 974 protected void fillPath() { 975 fillPath(getPrintDC()); 976 } 977 978 protected void moveTo(float x, float y) { 979 moveTo(getPrintDC(), x, y); 980 } 981 982 protected void lineTo(float x, float y) { 983 lineTo(getPrintDC(), x, y); 984 } 985 986 protected void polyBezierTo(float control1x, float control1y, 987 float control2x, float control2y, 988 float endX, float endY) { 989 990 polyBezierTo(getPrintDC(), control1x, control1y, 991 control2x, control2y, 992 endX, endY); 993 } 994 995 /** 996 * Set the current polgon fill rule into the printer device context. 997 * The {@code fillRule} should 998 * be one of the following Windows constants: 999 * {@code ALTERNATE} or {@code WINDING}. 1000 */ 1001 protected void setPolyFillMode(int fillRule) { 1002 setPolyFillMode(getPrintDC(), fillRule); 1003 } 1004 1005 /* 1006 * Create a Window's solid brush for the color specified 1007 * by {@code (red, green, blue)}. Once the brush 1008 * is created, select it in the current printing device 1009 * context and free the old brush. 1010 */ 1011 protected void selectSolidBrush(Color color) { 1012 1013 /* We only need to select a brush if the color has changed. 1014 */ 1015 if (color.equals(mLastColor) == false) { 1016 mLastColor = color; 1017 float[] rgb = color.getRGBColorComponents(null); 1018 1019 selectSolidBrush(getPrintDC(), 1020 (int) (rgb[0] * MAX_WCOLOR), 1021 (int) (rgb[1] * MAX_WCOLOR), 1022 (int) (rgb[2] * MAX_WCOLOR)); 1023 } 1024 } 1025 1026 /** 1027 * Return the x coordinate of the current pen 1028 * position in the print device context. 1029 */ 1030 protected int getPenX() { 1031 1032 return getPenX(getPrintDC()); 1033 } 1034 1035 1036 /** 1037 * Return the y coordinate of the current pen 1038 * position in the print device context. 1039 */ 1040 protected int getPenY() { 1041 1042 return getPenY(getPrintDC()); 1043 } 1044 1045 /** 1046 * Set the current path in the printer device's 1047 * context to be clipping path. 1048 */ 1049 protected void selectClipPath() { 1050 selectClipPath(getPrintDC()); 1051 } 1052 1053 1054 protected void frameRect(float x, float y, float width, float height) { 1055 frameRect(getPrintDC(), x, y, width, height); 1056 } 1057 1058 protected void fillRect(float x, float y, float width, float height, 1059 Color color) { 1060 float[] rgb = color.getRGBColorComponents(null); 1061 1062 fillRect(getPrintDC(), x, y, width, height, 1063 (int) (rgb[0] * MAX_WCOLOR), 1064 (int) (rgb[1] * MAX_WCOLOR), 1065 (int) (rgb[2] * MAX_WCOLOR)); 1066 } 1067 1068 1069 protected void selectPen(float width, Color color) { 1070 1071 float[] rgb = color.getRGBColorComponents(null); 1072 1073 selectPen(getPrintDC(), width, 1074 (int) (rgb[0] * MAX_WCOLOR), 1075 (int) (rgb[1] * MAX_WCOLOR), 1076 (int) (rgb[2] * MAX_WCOLOR)); 1077 } 1078 1079 1080 protected boolean selectStylePen(int cap, int join, float width, 1081 Color color) { 1082 1083 long endCap; 1084 long lineJoin; 1085 1086 float[] rgb = color.getRGBColorComponents(null); 1087 1088 switch(cap) { 1089 case BasicStroke.CAP_BUTT: endCap = PS_ENDCAP_FLAT; break; 1090 case BasicStroke.CAP_ROUND: endCap = PS_ENDCAP_ROUND; break; 1091 default: 1092 case BasicStroke.CAP_SQUARE: endCap = PS_ENDCAP_SQUARE; break; 1093 } 1094 1095 switch(join) { 1096 case BasicStroke.JOIN_BEVEL:lineJoin = PS_JOIN_BEVEL; break; 1097 default: 1098 case BasicStroke.JOIN_MITER:lineJoin = PS_JOIN_MITER; break; 1099 case BasicStroke.JOIN_ROUND:lineJoin = PS_JOIN_ROUND; break; 1100 } 1101 1102 return (selectStylePen(getPrintDC(), endCap, lineJoin, width, 1103 (int) (rgb[0] * MAX_WCOLOR), 1104 (int) (rgb[1] * MAX_WCOLOR), 1105 (int) (rgb[2] * MAX_WCOLOR))); 1106 } 1107 1108 /** 1109 * Set a GDI font capable of drawing the java Font 1110 * passed in. 1111 */ 1112 protected boolean setFont(String family, float size, int style, 1113 int rotation, float awScale) { 1114 1115 boolean didSetFont = true; 1116 1117 if (!family.equals(mLastFontFamily) || 1118 size != mLastFontSize || 1119 style != mLastFontStyle || 1120 rotation != mLastRotation || 1121 awScale != mLastAwScale) { 1122 1123 didSetFont = setFont(getPrintDC(), 1124 family, 1125 size, 1126 (style & Font.BOLD) != 0, 1127 (style & Font.ITALIC) != 0, 1128 rotation, awScale); 1129 if (didSetFont) { 1130 mLastFontFamily = family; 1131 mLastFontSize = size; 1132 mLastFontStyle = style; 1133 mLastRotation = rotation; 1134 mLastAwScale = awScale; 1135 } 1136 } 1137 return didSetFont; 1138 } 1139 1140 /** 1141 * Set the GDI color for text drawing. 1142 */ 1143 protected void setTextColor(Color color) { 1144 1145 /* We only need to select a brush if the color has changed. 1146 */ 1147 if (color.equals(mLastTextColor) == false) { 1148 mLastTextColor = color; 1149 float[] rgb = color.getRGBColorComponents(null); 1150 1151 setTextColor(getPrintDC(), 1152 (int) (rgb[0] * MAX_WCOLOR), 1153 (int) (rgb[1] * MAX_WCOLOR), 1154 (int) (rgb[2] * MAX_WCOLOR)); 1155 } 1156 } 1157 1158 /** 1159 * Remove control characters. 1160 */ 1161 @Override 1162 protected String removeControlChars(String str) { 1163 return super.removeControlChars(str); 1164 } 1165 1166 /** 1167 * Draw the string {@code text} to the printer's 1168 * device context at the specified position. 1169 */ 1170 protected void textOut(String str, float x, float y, 1171 float[] positions) { 1172 /* Don't leave handling of control chars to GDI. 1173 * If control chars are removed, 'positions' isn't valid. 1174 * This means the caller needs to be aware of this and remove 1175 * control chars up front if supplying positions. Since the 1176 * caller is tightly integrated here, that's acceptable. 1177 */ 1178 String text = removeControlChars(str); 1179 assert (positions == null) || (text.length() == str.length()); 1180 if (text.length() == 0) { 1181 return; 1182 } 1183 textOut(getPrintDC(), text, text.length(), false, x, y, positions); 1184 } 1185 1186 /** 1187 * Draw the glyphs {@code glyphs} to the printer's 1188 * device context at the specified position. 1189 */ 1190 protected void glyphsOut(int []glyphs, float x, float y, 1191 float[] positions) { 1192 1193 /* TrueType glyph codes are 16 bit values, so can be packed 1194 * in a unicode string, and that's how GDI expects them. 1195 * A flag bit is set to indicate to GDI that these are glyphs, 1196 * not characters. The positions array must always be non-null 1197 * here for our purposes, although if not supplied, GDI should 1198 * just use the default advances for the glyphs. 1199 * Mask out upper 16 bits to remove any slot from a composite. 1200 */ 1201 char[] glyphCharArray = new char[glyphs.length]; 1202 for (int i=0;i<glyphs.length;i++) { 1203 glyphCharArray[i] = (char)(glyphs[i] & 0xffff); 1204 } 1205 String glyphStr = new String(glyphCharArray); 1206 textOut(getPrintDC(), glyphStr, glyphs.length, true, x, y, positions); 1207 } 1208 1209 1210 /** 1211 * Get the advance of this text that GDI returns for the 1212 * font currently selected into the GDI device context for 1213 * this job. Note that the removed control characters are 1214 * interpreted as zero-width by JDK and we remove them for 1215 * rendering so also remove them for measurement so that 1216 * this measurement can be properly compared with JDK measurement. 1217 */ 1218 protected int getGDIAdvance(String text) { 1219 /* Don't leave handling of control chars to GDI. */ 1220 text = removeControlChars(text); 1221 if (text.length() == 0) { 1222 return 0; 1223 } 1224 return getGDIAdvance(getPrintDC(), text); 1225 } 1226 1227 /** 1228 * Draw the 24 bit BGR image buffer represented by 1229 * {@code image} to the GDI device context 1230 * {@code printDC}. The image is drawn at 1231 * {@code (destX, destY)} in device coordinates. 1232 * The image is scaled into a square of size 1233 * specified by {@code destWidth} and 1234 * {@code destHeight}. The portion of the 1235 * source image copied into that square is specified 1236 * by {@code srcX}, {@code srcY}, 1237 * {@code srcWidth}, and srcHeight. 1238 */ 1239 protected void drawImage3ByteBGR(byte[] image, 1240 float destX, float destY, 1241 float destWidth, float destHeight, 1242 float srcX, float srcY, 1243 float srcWidth, float srcHeight) { 1244 1245 1246 drawDIBImage(getPrintDC(), image, 1247 destX, destY, 1248 destWidth, destHeight, 1249 srcX, srcY, 1250 srcWidth, srcHeight, 1251 24, null); 1252 1253 } 1254 1255 /* If 'icm' is null we expect its 24 bit (ie 3BYTE_BGR). 1256 * If 'icm' is non-null we expect its no more than 8 bpp and 1257 * specifically must be a valid DIB sizes : 1, 4 or 8 bpp. 1258 * Then we need to extract the colours into a byte array of the 1259 * format required by GDI which is an array of 'RGBQUAD' 1260 * RGBQUAD looks like : 1261 * typedef struct tagRGBQUAD { 1262 * BYTE rgbBlue; 1263 * BYTE rgbGreen; 1264 * BYTE rgbRed; 1265 * BYTE rgbReserved; // must be zero. 1266 * } RGBQUAD; 1267 * There's no alignment problem as GDI expects this to be packed 1268 * and each struct will start on a 4 byte boundary anyway. 1269 */ 1270 protected void drawDIBImage(byte[] image, 1271 float destX, float destY, 1272 float destWidth, float destHeight, 1273 float srcX, float srcY, 1274 float srcWidth, float srcHeight, 1275 int sampleBitsPerPixel, 1276 IndexColorModel icm) { 1277 int bitCount = 24; 1278 byte[] bmiColors = null; 1279 1280 if (icm != null) { 1281 bitCount = sampleBitsPerPixel; 1282 bmiColors = new byte[(1<<icm.getPixelSize())*4]; 1283 for (int i=0;i<icm.getMapSize(); i++) { 1284 bmiColors[i*4+0]=(byte)(icm.getBlue(i)&0xff); 1285 bmiColors[i*4+1]=(byte)(icm.getGreen(i)&0xff); 1286 bmiColors[i*4+2]=(byte)(icm.getRed(i)&0xff); 1287 } 1288 } 1289 1290 drawDIBImage(getPrintDC(), image, 1291 destX, destY, 1292 destWidth, destHeight, 1293 srcX, srcY, 1294 srcWidth, srcHeight, 1295 bitCount, bmiColors); 1296 } 1297 1298 /** 1299 * Begin a new page. 1300 */ 1301 @Override 1302 protected void startPage(PageFormat format, Printable painter, 1303 int index, boolean paperChanged) { 1304 1305 /* Invalidate any device state caches we are 1306 * maintaining. Win95/98 resets the device 1307 * context attributes to default values at 1308 * the start of each page. 1309 */ 1310 invalidateCachedState(); 1311 1312 deviceStartPage(format, painter, index, paperChanged); 1313 } 1314 1315 /** 1316 * End a page. 1317 */ 1318 @Override 1319 protected void endPage(PageFormat format, Printable painter, 1320 int index) { 1321 1322 deviceEndPage(format, painter, index); 1323 } 1324 1325 /** 1326 * Forget any device state we may have cached. 1327 */ 1328 private void invalidateCachedState() { 1329 mLastColor = null; 1330 mLastTextColor = null; 1331 mLastFontFamily = null; 1332 } 1333 1334 private boolean defaultCopies = true; 1335 /** 1336 * Set the number of copies to be printed. 1337 */ 1338 @Override 1339 public void setCopies(int copies) { 1340 super.setCopies(copies); 1341 defaultCopies = false; 1342 mAttCopies = copies; 1343 setNativeCopies(copies); 1344 } 1345 1346 1347 /* Native Methods */ 1348 1349 /** 1350 * Set copies in device. 1351 */ 1352 private native void setNativeCopies(int copies); 1353 1354 /** 1355 * Displays the print dialog and records the user's settings 1356 * into this object. Return false if the user cancels the 1357 * dialog. 1358 * If the dialog is to use a set of attributes, useAttributes is true. 1359 */ 1360 private native boolean jobSetup(Pageable doc, boolean allowPrintToFile); 1361 1362 /* Make sure printer DC is intialised and that info about the printer 1363 * is reflected back up to Java code 1364 */ 1365 @Override 1366 protected native void initPrinter(); 1367 1368 /** 1369 * Call Window's StartDoc routine to begin a 1370 * print job. The DC from the print dialog is 1371 * used. If the print dialog was not displayed 1372 * then a DC for the default printer is created. 1373 * The native StartDoc returns false if the end-user cancelled 1374 * printing. This is possible if the printer is connected to FILE: 1375 * in which case windows queries the user for a destination and the 1376 * user may cancel out of it. Note that the implementation of 1377 * cancel() throws PrinterAbortException to indicate the user cancelled. 1378 */ 1379 private native boolean _startDoc(String dest, String jobName) 1380 throws PrinterException; 1381 @Override 1382 protected void startDoc() throws PrinterException { 1383 if (!_startDoc(mDestination, getJobName())) { 1384 cancel(); 1385 } 1386 } 1387 1388 /** 1389 * Call Window's EndDoc routine to end a 1390 * print job. 1391 */ 1392 @Override 1393 protected native void endDoc(); 1394 1395 /** 1396 * Call Window's AbortDoc routine to abort a 1397 * print job. 1398 */ 1399 @Override 1400 protected native void abortDoc(); 1401 1402 /** 1403 * Call Windows native resource freeing APIs 1404 */ 1405 private static native void deleteDC(long dc, long devmode, long devnames); 1406 1407 /** 1408 * Begin a new page. This call's Window's 1409 * StartPage routine. 1410 */ 1411 protected native void deviceStartPage(PageFormat format, Printable painter, 1412 int index, boolean paperChanged); 1413 /** 1414 * End a page. This call's Window's EndPage 1415 * routine. 1416 */ 1417 protected native void deviceEndPage(PageFormat format, Printable painter, 1418 int index); 1419 1420 /** 1421 * Prints the contents of the array of ints, 'data' 1422 * to the current page. The band is placed at the 1423 * location (x, y) in device coordinates on the 1424 * page. The width and height of the band is 1425 * specified by the caller. 1426 */ 1427 @Override 1428 protected native void printBand(byte[] data, int x, int y, 1429 int width, int height); 1430 1431 /** 1432 * Begin a Window's rendering path in the device 1433 * context {@code printDC}. 1434 */ 1435 protected native void beginPath(long printDC); 1436 1437 /** 1438 * End a Window's rendering path in the device 1439 * context {@code printDC}. 1440 */ 1441 protected native void endPath(long printDC); 1442 1443 /** 1444 * Close a subpath in a Window's rendering path in the device 1445 * context {@code printDC}. 1446 */ 1447 protected native void closeFigure(long printDC); 1448 1449 /** 1450 * Fill a defined Window's rendering path in the device 1451 * context {@code printDC}. 1452 */ 1453 protected native void fillPath(long printDC); 1454 1455 /** 1456 * Move the Window's pen position to {@code (x,y)} 1457 * in the device context {@code printDC}. 1458 */ 1459 protected native void moveTo(long printDC, float x, float y); 1460 1461 /** 1462 * Draw a line from the current pen position to 1463 * {@code (x,y)} in the device context {@code printDC}. 1464 */ 1465 protected native void lineTo(long printDC, float x, float y); 1466 1467 protected native void polyBezierTo(long printDC, 1468 float control1x, float control1y, 1469 float control2x, float control2y, 1470 float endX, float endY); 1471 1472 /** 1473 * Set the current polgon fill rule into the device context 1474 * {@code printDC}. The {@code fillRule} should 1475 * be one of the following Windows constants: 1476 * {@code ALTERNATE} or {@code WINDING}. 1477 */ 1478 protected native void setPolyFillMode(long printDC, int fillRule); 1479 1480 /** 1481 * Create a Window's solid brush for the color specified 1482 * by {@code (red, green, blue)}. Once the brush 1483 * is created, select it in the device 1484 * context {@code printDC} and free the old brush. 1485 */ 1486 protected native void selectSolidBrush(long printDC, 1487 int red, int green, int blue); 1488 1489 /** 1490 * Return the x coordinate of the current pen 1491 * position in the device context 1492 * {@code printDC}. 1493 */ 1494 protected native int getPenX(long printDC); 1495 1496 /** 1497 * Return the y coordinate of the current pen 1498 * position in the device context 1499 * {@code printDC}. 1500 */ 1501 protected native int getPenY(long printDC); 1502 1503 /** 1504 * Select the device context's current path 1505 * to be the clipping path. 1506 */ 1507 protected native void selectClipPath(long printDC); 1508 1509 /** 1510 * Draw a rectangle using specified brush. 1511 */ 1512 protected native void frameRect(long printDC, float x, float y, 1513 float width, float height); 1514 1515 /** 1516 * Fill a rectangle specified by the coordinates using 1517 * specified brush. 1518 */ 1519 protected native void fillRect(long printDC, float x, float y, 1520 float width, float height, 1521 int red, int green, int blue); 1522 1523 /** 1524 * Create a solid brush using the RG & B colors and width. 1525 * Select this brush and delete the old one. 1526 */ 1527 protected native void selectPen(long printDC, float width, 1528 int red, int green, int blue); 1529 1530 /** 1531 * Create a solid brush using the RG & B colors and specified 1532 * pen styles. Select this created brush and delete the old one. 1533 */ 1534 protected native boolean selectStylePen(long printDC, long cap, 1535 long join, float width, 1536 int red, int green, int blue); 1537 1538 /** 1539 * Set a GDI font capable of drawing the java Font 1540 * passed in. 1541 */ 1542 protected native boolean setFont(long printDC, String familyName, 1543 float fontSize, 1544 boolean bold, 1545 boolean italic, 1546 int rotation, 1547 float awScale); 1548 1549 1550 /** 1551 * Set the GDI color for text drawing. 1552 */ 1553 protected native void setTextColor(long printDC, 1554 int red, int green, int blue); 1555 1556 1557 /** 1558 * Draw the string {@code text} into the device 1559 * context {@code printDC} at the specified 1560 * position. 1561 */ 1562 protected native void textOut(long printDC, String text, 1563 int strlen, boolean glyphs, 1564 float x, float y, float[] positions); 1565 1566 1567 private native int getGDIAdvance(long printDC, String text); 1568 1569 /** 1570 * Draw the DIB compatible image buffer represented by 1571 * {@code image} to the GDI device context 1572 * {@code printDC}. The image is drawn at 1573 * {@code (destX, destY)} in device coordinates. 1574 * The image is scaled into a square of size 1575 * specified by {@code destWidth} and 1576 * {@code destHeight}. The portion of the 1577 * source image copied into that square is specified 1578 * by {@code srcX}, {@code srcY}, 1579 * {@code srcWidth}, and srcHeight. 1580 * Note that the image isn't completely compatible with DIB format. 1581 * At the very least it needs to be padded so each scanline is 1582 * DWORD aligned. Also we "flip" the image to make it a bottom-up DIB. 1583 */ 1584 private native void drawDIBImage(long printDC, byte[] image, 1585 float destX, float destY, 1586 float destWidth, float destHeight, 1587 float srcX, float srcY, 1588 float srcWidth, float srcHeight, 1589 int bitCount, byte[] bmiColors); 1590 1591 1592 //** BEGIN Functions called by native code for querying/updating attributes 1593 1594 private String getPrinterAttrib() { 1595 // getPrintService will get current print service or default if none 1596 PrintService service = this.getPrintService(); 1597 String name = (service != null) ? service.getName() : null; 1598 return name; 1599 } 1600 1601 /* SheetCollate */ 1602 private int getCollateAttrib() { 1603 // -1 means unset, 0 uncollated, 1 collated. 1604 return mAttCollate; 1605 } 1606 1607 private void setCollateAttrib(Attribute attr) { 1608 if (attr == SheetCollate.COLLATED) { 1609 mAttCollate = 1; // DMCOLLATE_TRUE 1610 } else { 1611 mAttCollate = 0; // DMCOLLATE_FALSE 1612 } 1613 } 1614 1615 private void setCollateAttrib(Attribute attr, 1616 PrintRequestAttributeSet set) { 1617 setCollateAttrib(attr); 1618 set.add(attr); 1619 } 1620 1621 /* Orientation */ 1622 1623 private int getOrientAttrib() { 1624 int orient = PageFormat.PORTRAIT; 1625 OrientationRequested orientReq = (attributes == null) ? null : 1626 (OrientationRequested)attributes.get(OrientationRequested.class); 1627 if (orientReq == null) { 1628 orientReq = (OrientationRequested) 1629 myService.getDefaultAttributeValue(OrientationRequested.class); 1630 } 1631 if (orientReq != null) { 1632 if (orientReq == OrientationRequested.REVERSE_LANDSCAPE) { 1633 orient = PageFormat.REVERSE_LANDSCAPE; 1634 } else if (orientReq == OrientationRequested.LANDSCAPE) { 1635 orient = PageFormat.LANDSCAPE; 1636 } 1637 } 1638 1639 return orient; 1640 } 1641 1642 private void setOrientAttrib(Attribute attr, 1643 PrintRequestAttributeSet set) { 1644 if (set != null) { 1645 set.add(attr); 1646 } 1647 } 1648 1649 /* Copies and Page Range. */ 1650 private int getCopiesAttrib() { 1651 if (defaultCopies) { 1652 return 0; 1653 } else { 1654 return getCopiesInt(); 1655 } 1656 } 1657 1658 private void setRangeCopiesAttribute(int from, int to, boolean isRangeSet, 1659 int copies) { 1660 if (attributes != null) { 1661 if (isRangeSet) { 1662 attributes.add(new PageRanges(from, to)); 1663 setPageRange(from, to); 1664 } 1665 defaultCopies = false; 1666 attributes.add(new Copies(copies)); 1667 /* Since this is called from native to tell Java to sync 1668 * up with native, we don't call this class's own setCopies() 1669 * method which is mainly to send the value down to native 1670 */ 1671 super.setCopies(copies); 1672 mAttCopies = copies; 1673 } 1674 } 1675 1676 1677 1678 private boolean getDestAttrib() { 1679 return (mDestination != null); 1680 } 1681 1682 /* Quality */ 1683 private int getQualityAttrib() { 1684 return mAttQuality; 1685 } 1686 1687 private void setQualityAttrib(Attribute attr) { 1688 if (attr == PrintQuality.HIGH) { 1689 mAttQuality = -4; // DMRES_HIGH 1690 } else if (attr == PrintQuality.NORMAL) { 1691 mAttQuality = -3; // DMRES_MEDIUM 1692 } else { 1693 mAttQuality = -2; // DMRES_LOW 1694 } 1695 } 1696 1697 private void setQualityAttrib(Attribute attr, 1698 PrintRequestAttributeSet set) { 1699 setQualityAttrib(attr); 1700 set.add(attr); 1701 } 1702 1703 /* Color/Chromaticity */ 1704 private int getColorAttrib() { 1705 return mAttChromaticity; 1706 } 1707 1708 private void setColorAttrib(Attribute attr) { 1709 if (attr == Chromaticity.COLOR) { 1710 mAttChromaticity = 2; // DMCOLOR_COLOR 1711 } else { 1712 mAttChromaticity = 1; // DMCOLOR_MONOCHROME 1713 } 1714 } 1715 1716 private void setColorAttrib(Attribute attr, 1717 PrintRequestAttributeSet set) { 1718 setColorAttrib(attr); 1719 set.add(attr); 1720 } 1721 1722 /* Sides */ 1723 private int getSidesAttrib() { 1724 return mAttSides; 1725 } 1726 1727 private void setSidesAttrib(Attribute attr) { 1728 if (attr == Sides.TWO_SIDED_LONG_EDGE) { 1729 mAttSides = 2; // DMDUP_VERTICAL 1730 } else if (attr == Sides.TWO_SIDED_SHORT_EDGE) { 1731 mAttSides = 3; // DMDUP_HORIZONTAL 1732 } else { // Sides.ONE_SIDED 1733 mAttSides = 1; 1734 } 1735 } 1736 1737 private void setSidesAttrib(Attribute attr, 1738 PrintRequestAttributeSet set) { 1739 setSidesAttrib(attr); 1740 set.add(attr); 1741 } 1742 1743 /** MediaSizeName / dmPaper */ 1744 private int[] getWin32MediaAttrib() { 1745 int wid_ht[] = {0, 0}; 1746 if (attributes != null) { 1747 Media media = (Media)attributes.get(Media.class); 1748 if (media instanceof MediaSizeName) { 1749 MediaSizeName msn = (MediaSizeName)media; 1750 MediaSize ms = MediaSize.getMediaSizeForName(msn); 1751 if (ms != null) { 1752 wid_ht[0] = (int)(ms.getX(MediaSize.INCH) * 72.0); 1753 wid_ht[1] = (int)(ms.getY(MediaSize.INCH) * 72.0); 1754 } 1755 } 1756 } 1757 return wid_ht; 1758 } 1759 1760 private void setWin32MediaAttrib(Attribute attr) { 1761 if (!(attr instanceof MediaSizeName)) { 1762 return; 1763 } 1764 MediaSizeName msn = (MediaSizeName)attr; 1765 mAttMediaSizeName = ((Win32PrintService)myService).findPaperID(msn); 1766 } 1767 1768 private void addPaperSize(PrintRequestAttributeSet aset, 1769 int dmIndex, int width, int length) { 1770 1771 if (aset == null) { 1772 return; 1773 } 1774 MediaSizeName msn = 1775 ((Win32PrintService)myService).findWin32Media(dmIndex); 1776 if (msn == null) { 1777 msn = ((Win32PrintService)myService). 1778 findMatchingMediaSizeNameMM((float)width, (float)length); 1779 } 1780 1781 if (msn != null) { 1782 aset.add(msn); 1783 } 1784 } 1785 1786 private void setWin32MediaAttrib(int dmIndex, int width, int length) { 1787 addPaperSize(attributes, dmIndex, width, length); 1788 mAttMediaSizeName = dmIndex; 1789 } 1790 1791 /* MediaTray / dmTray */ 1792 private void setMediaTrayAttrib(Attribute attr) { 1793 if (attr == MediaTray.BOTTOM) { 1794 mAttMediaTray = 2; // DMBIN_LOWER 1795 } else if (attr == MediaTray.ENVELOPE) { 1796 mAttMediaTray = 5; // DMBIN_ENVELOPE 1797 } else if (attr == MediaTray.LARGE_CAPACITY) { 1798 mAttMediaTray = 11; // DMBIN_LARGECAPACITY 1799 } else if (attr == MediaTray.MAIN) { 1800 mAttMediaTray =1; // DMBIN_UPPER 1801 } else if (attr == MediaTray.MANUAL) { 1802 mAttMediaTray = 4; // DMBIN_MANUAL 1803 } else if (attr == MediaTray.MIDDLE) { 1804 mAttMediaTray = 3; // DMBIN_MIDDLE 1805 } else if (attr == MediaTray.SIDE) { 1806 // no equivalent predefined value 1807 mAttMediaTray = 7; // DMBIN_AUTO 1808 } else if (attr == MediaTray.TOP) { 1809 mAttMediaTray = 1; // DMBIN_UPPER 1810 } else { 1811 if (attr instanceof Win32MediaTray) { 1812 mAttMediaTray = ((Win32MediaTray)attr).winID; 1813 } else { 1814 mAttMediaTray = 1; // default 1815 } 1816 } 1817 } 1818 1819 private void setMediaTrayAttrib(int dmBinID) { 1820 mAttMediaTray = dmBinID; 1821 MediaTray tray = ((Win32PrintService)myService).findMediaTray(dmBinID); 1822 } 1823 1824 private int getMediaTrayAttrib() { 1825 return mAttMediaTray; 1826 } 1827 1828 1829 1830 private boolean getPrintToFileEnabled() { 1831 SecurityManager security = System.getSecurityManager(); 1832 if (security != null) { 1833 FilePermission printToFilePermission = 1834 new FilePermission("<<ALL FILES>>", "read,write"); 1835 try { 1836 security.checkPermission(printToFilePermission); 1837 } catch (SecurityException e) { 1838 return false; 1839 } 1840 } 1841 return true; 1842 } 1843 1844 private void setNativeAttributes(int flags, int fields, int values) { 1845 if (attributes == null) { 1846 return; 1847 } 1848 if ((flags & PD_PRINTTOFILE) != 0) { 1849 Destination destPrn = (Destination)attributes.get( 1850 Destination.class); 1851 if (destPrn == null) { 1852 try { 1853 attributes.add(new Destination( 1854 new File("./out.prn").toURI())); 1855 } catch (SecurityException se) { 1856 try { 1857 attributes.add(new Destination( 1858 new URI("file:out.prn"))); 1859 } catch (URISyntaxException e) { 1860 } 1861 } 1862 } 1863 } else { 1864 attributes.remove(Destination.class); 1865 } 1866 1867 if ((flags & PD_COLLATE) != 0) { 1868 setCollateAttrib(SheetCollate.COLLATED, attributes); 1869 } else { 1870 setCollateAttrib(SheetCollate.UNCOLLATED, attributes); 1871 } 1872 1873 if ((flags & PD_NOSELECTION) != PD_NOSELECTION) { 1874 if ((flags & PD_PAGENUMS) != 0) { 1875 attributes.add(SunPageSelection.RANGE); 1876 } else if ((flags & PD_SELECTION) != 0) { 1877 attributes.add(SunPageSelection.SELECTION); 1878 } else { 1879 attributes.add(SunPageSelection.ALL); 1880 } 1881 } 1882 1883 if ((fields & DM_ORIENTATION) != 0) { 1884 if ((values & SET_ORIENTATION) != 0) { 1885 setOrientAttrib(OrientationRequested.LANDSCAPE, attributes); 1886 } else { 1887 setOrientAttrib(OrientationRequested.PORTRAIT, attributes); 1888 } 1889 } 1890 1891 if ((fields & DM_COLOR) != 0) { 1892 if ((values & SET_COLOR) != 0) { 1893 setColorAttrib(Chromaticity.COLOR, attributes); 1894 } else { 1895 setColorAttrib(Chromaticity.MONOCHROME, attributes); 1896 } 1897 } 1898 1899 if ((fields & DM_PRINTQUALITY) != 0) { 1900 PrintQuality quality; 1901 if ((values & SET_RES_LOW) != 0) { 1902 quality = PrintQuality.DRAFT; 1903 } else if ((fields & SET_RES_HIGH) != 0) { 1904 quality = PrintQuality.HIGH; 1905 } else { 1906 quality = PrintQuality.NORMAL; 1907 } 1908 setQualityAttrib(quality, attributes); 1909 } 1910 1911 if ((fields & DM_DUPLEX) != 0) { 1912 Sides sides; 1913 if ((values & SET_DUP_VERTICAL) != 0) { 1914 sides = Sides.TWO_SIDED_LONG_EDGE; 1915 } else if ((values & SET_DUP_HORIZONTAL) != 0) { 1916 sides = Sides.TWO_SIDED_SHORT_EDGE; 1917 } else { 1918 sides = Sides.ONE_SIDED; 1919 } 1920 setSidesAttrib(sides, attributes); 1921 } 1922 } 1923 1924 private static final class DevModeValues { 1925 int dmFields; 1926 short copies; 1927 short collate; 1928 short color; 1929 short duplex; 1930 short orient; 1931 short paper; 1932 short bin; 1933 short xres_quality; 1934 short yres; 1935 } 1936 1937 private void getDevModeValues(PrintRequestAttributeSet aset, 1938 DevModeValues info) { 1939 1940 Copies c = (Copies)aset.get(Copies.class); 1941 if (c != null) { 1942 info.dmFields |= DM_COPIES; 1943 info.copies = (short)c.getValue(); 1944 } 1945 1946 SheetCollate sc = (SheetCollate)aset.get(SheetCollate.class); 1947 if (sc != null) { 1948 info.dmFields |= DM_COLLATE; 1949 info.collate = (sc == SheetCollate.COLLATED) ? 1950 DMCOLLATE_TRUE : DMCOLLATE_FALSE; 1951 } 1952 1953 Chromaticity ch = (Chromaticity)aset.get(Chromaticity.class); 1954 if (ch != null) { 1955 info.dmFields |= DM_COLOR; 1956 if (ch == Chromaticity.COLOR) { 1957 info.color = DMCOLOR_COLOR; 1958 } else { 1959 info.color = DMCOLOR_MONOCHROME; 1960 } 1961 } 1962 1963 Sides s = (Sides)aset.get(Sides.class); 1964 if (s != null) { 1965 info.dmFields |= DM_DUPLEX; 1966 if (s == Sides.TWO_SIDED_LONG_EDGE) { 1967 info.duplex = DMDUP_VERTICAL; 1968 } else if (s == Sides.TWO_SIDED_SHORT_EDGE) { 1969 info.duplex = DMDUP_HORIZONTAL; 1970 } else { // Sides.ONE_SIDED 1971 info.duplex = DMDUP_SIMPLEX; 1972 } 1973 } 1974 1975 OrientationRequested or = 1976 (OrientationRequested)aset.get(OrientationRequested.class); 1977 if (or != null) { 1978 info.dmFields |= DM_ORIENTATION; 1979 info.orient = (or == OrientationRequested.LANDSCAPE) 1980 ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT; 1981 } 1982 1983 Media m = (Media)aset.get(Media.class); 1984 if (m instanceof MediaSizeName) { 1985 info.dmFields |= DM_PAPERSIZE; 1986 MediaSizeName msn = (MediaSizeName)m; 1987 info.paper = 1988 (short)((Win32PrintService)myService).findPaperID(msn); 1989 } 1990 1991 MediaTray mt = null; 1992 if (m instanceof MediaTray) { 1993 mt = (MediaTray)m; 1994 } 1995 if (mt == null) { 1996 SunAlternateMedia sam = 1997 (SunAlternateMedia)aset.get(SunAlternateMedia.class); 1998 if (sam != null && (sam.getMedia() instanceof MediaTray)) { 1999 mt = (MediaTray)sam.getMedia(); 2000 } 2001 } 2002 2003 if (mt != null) { 2004 info.dmFields |= DM_DEFAULTSOURCE; 2005 info.bin = (short)(((Win32PrintService)myService).findTrayID(mt)); 2006 } 2007 2008 PrintQuality q = (PrintQuality)aset.get(PrintQuality.class); 2009 if (q != null) { 2010 info.dmFields |= DM_PRINTQUALITY; 2011 if (q == PrintQuality.DRAFT) { 2012 info.xres_quality = DMRES_DRAFT; 2013 } else if (q == PrintQuality.HIGH) { 2014 info.xres_quality = DMRES_HIGH; 2015 } else { 2016 info.xres_quality = DMRES_MEDIUM; 2017 } 2018 } 2019 2020 PrinterResolution r = 2021 (PrinterResolution)aset.get(PrinterResolution.class); 2022 if (r != null) { 2023 info.dmFields |= DM_PRINTQUALITY | DM_YRESOLUTION; 2024 info.xres_quality = 2025 (short)r.getCrossFeedResolution(PrinterResolution.DPI); 2026 info.yres = (short)r.getFeedResolution(PrinterResolution.DPI); 2027 } 2028 } 2029 2030 /* This method is called from native to update the values in the 2031 * attribute set which originates from the cross-platform dialog, 2032 * but updated by the native DocumentPropertiesUI which updates the 2033 * devmode. This syncs the devmode back in to the attributes so that 2034 * we can update the cross-platform dialog. 2035 * The attribute set here is a temporary one installed whilst this 2036 * happens, 2037 */ 2038 private void setJobAttributes(PrintRequestAttributeSet attributes, 2039 int fields, int values, 2040 short copies, 2041 short dmPaperSize, 2042 short dmPaperWidth, 2043 short dmPaperLength, 2044 short dmDefaultSource, 2045 short xRes, 2046 short yRes) { 2047 2048 if (attributes == null) { 2049 return; 2050 } 2051 2052 if ((fields & DM_COPIES) != 0) { 2053 attributes.add(new Copies(copies)); 2054 } 2055 2056 if ((fields & DM_COLLATE) != 0) { 2057 if ((values & SET_COLLATED) != 0) { 2058 attributes.add(SheetCollate.COLLATED); 2059 } else { 2060 attributes.add(SheetCollate.UNCOLLATED); 2061 } 2062 } 2063 2064 if ((fields & DM_ORIENTATION) != 0) { 2065 if ((values & SET_ORIENTATION) != 0) { 2066 attributes.add(OrientationRequested.LANDSCAPE); 2067 } else { 2068 attributes.add(OrientationRequested.PORTRAIT); 2069 } 2070 } 2071 2072 if ((fields & DM_COLOR) != 0) { 2073 if ((values & SET_COLOR) != 0) { 2074 attributes.add(Chromaticity.COLOR); 2075 } else { 2076 attributes.add(Chromaticity.MONOCHROME); 2077 } 2078 } 2079 2080 if ((fields & DM_PRINTQUALITY) != 0) { 2081 /* value < 0 indicates quality setting. 2082 * value > 0 indicates X resolution. In that case 2083 * hopefully we will also find y-resolution specified. 2084 * If its not, assume its the same as x-res. 2085 * Maybe Java code should try to reconcile this against 2086 * the printers claimed set of supported resolutions. 2087 */ 2088 if (xRes < 0) { 2089 PrintQuality quality; 2090 if ((values & SET_RES_LOW) != 0) { 2091 quality = PrintQuality.DRAFT; 2092 } else if ((fields & SET_RES_HIGH) != 0) { 2093 quality = PrintQuality.HIGH; 2094 } else { 2095 quality = PrintQuality.NORMAL; 2096 } 2097 attributes.add(quality); 2098 } else if (xRes > 0 && yRes > 0) { 2099 attributes.add( 2100 new PrinterResolution(xRes, yRes, PrinterResolution.DPI)); 2101 } 2102 } 2103 2104 if ((fields & DM_DUPLEX) != 0) { 2105 Sides sides; 2106 if ((values & SET_DUP_VERTICAL) != 0) { 2107 sides = Sides.TWO_SIDED_LONG_EDGE; 2108 } else if ((values & SET_DUP_HORIZONTAL) != 0) { 2109 sides = Sides.TWO_SIDED_SHORT_EDGE; 2110 } else { 2111 sides = Sides.ONE_SIDED; 2112 } 2113 attributes.add(sides); 2114 } 2115 2116 if ((fields & DM_PAPERSIZE) != 0) { 2117 addPaperSize(attributes, dmPaperSize, dmPaperWidth, dmPaperLength); 2118 } 2119 2120 if ((fields & DM_DEFAULTSOURCE) != 0) { 2121 MediaTray tray = 2122 ((Win32PrintService)myService).findMediaTray(dmDefaultSource); 2123 attributes.add(new SunAlternateMedia(tray)); 2124 } 2125 } 2126 2127 private native boolean showDocProperties(long hWnd, 2128 PrintRequestAttributeSet aset, 2129 int dmFields, 2130 short copies, 2131 short collate, 2132 short color, 2133 short duplex, 2134 short orient, 2135 short paper, 2136 short bin, 2137 short xres_quality, 2138 short yres); 2139 2140 public PrintRequestAttributeSet 2141 showDocumentProperties(Window owner, 2142 PrintService service, 2143 PrintRequestAttributeSet aset) 2144 { 2145 try { 2146 setNativePrintServiceIfNeeded(service.getName()); 2147 } catch (PrinterException e) { 2148 } 2149 final ComponentAccessor acc = AWTAccessor.getComponentAccessor(); 2150 long hWnd = acc.<WComponentPeer>getPeer(owner).getHWnd(); 2151 DevModeValues info = new DevModeValues(); 2152 getDevModeValues(aset, info); 2153 boolean ok = 2154 showDocProperties(hWnd, aset, 2155 info.dmFields, 2156 info.copies, 2157 info.collate, 2158 info.color, 2159 info.duplex, 2160 info.orient, 2161 info.paper, 2162 info.bin, 2163 info.xres_quality, 2164 info.yres); 2165 2166 if (ok) { 2167 return aset; 2168 } else { 2169 return null; 2170 } 2171 } 2172 2173 /* Printer Resolution. See also getXRes() and getYRes() */ 2174 private void setResolutionDPI(int xres, int yres) { 2175 if (attributes != null) { 2176 PrinterResolution res = 2177 new PrinterResolution(xres, yres, PrinterResolution.DPI); 2178 attributes.add(res); 2179 } 2180 mAttXRes = xres; 2181 mAttYRes = yres; 2182 } 2183 2184 private void setResolutionAttrib(Attribute attr) { 2185 PrinterResolution pr = (PrinterResolution)attr; 2186 mAttXRes = pr.getCrossFeedResolution(PrinterResolution.DPI); 2187 mAttYRes = pr.getFeedResolution(PrinterResolution.DPI); 2188 } 2189 2190 private void setPrinterNameAttrib(String printerName) { 2191 PrintService service = this.getPrintService(); 2192 2193 if (printerName == null) { 2194 return; 2195 } 2196 2197 if (service != null && printerName.equals(service.getName())) { 2198 return; 2199 } else { 2200 PrintService []services = PrinterJob.lookupPrintServices(); 2201 for (int i=0; i<services.length; i++) { 2202 if (printerName.equals(services[i].getName())) { 2203 2204 try { 2205 this.setPrintService(services[i]); 2206 } catch (PrinterException e) { 2207 } 2208 return; 2209 } 2210 } 2211 } 2212 //** END Functions called by native code for querying/updating attributes 2213 2214 } 2215 2216 @SuppressWarnings("serial") // JDK-implementation class 2217 class PrintToFileErrorDialog extends Dialog implements ActionListener{ 2218 public PrintToFileErrorDialog(Frame parent, String title, String message, 2219 String buttonText) { 2220 super(parent, title, true); 2221 init (parent, title, message, buttonText); 2222 } 2223 2224 public PrintToFileErrorDialog(Dialog parent, String title, String message, 2225 String buttonText) { 2226 super(parent, title, true); 2227 init (parent, title, message, buttonText); 2228 } 2229 2230 private void init(Component parent, String title, String message, 2231 String buttonText) { 2232 Panel p = new Panel(); 2233 add("Center", new Label(message)); 2234 Button btn = new Button(buttonText); 2235 btn.addActionListener(this); 2236 p.add(btn); 2237 add("South", p); 2238 pack(); 2239 2240 Dimension dDim = getSize(); 2241 if (parent != null) { 2242 Rectangle fRect = parent.getBounds(); 2243 setLocation(fRect.x + ((fRect.width - dDim.width) / 2), 2244 fRect.y + ((fRect.height - dDim.height) / 2)); 2245 } 2246 } 2247 2248 @Override 2249 public void actionPerformed(ActionEvent event) { 2250 setVisible(false); 2251 dispose(); 2252 return; 2253 } 2254 } 2255 2256 2257 2258 2259 /** 2260 * Initialize JNI field and method ids 2261 */ 2262 private static native void initIDs(); 2263 2264 }