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