1 /* 2 * Copyright (c) 1997, 2014, 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.KeyboardFocusManager; 34 import java.awt.Toolkit; 35 import java.awt.BasicStroke; 36 import java.awt.Button; 37 import java.awt.Component; 38 import java.awt.Dimension; 39 import java.awt.Event; 40 import java.awt.event.ActionEvent; 41 import java.awt.event.ActionListener; 42 import java.awt.FileDialog; 43 import java.awt.Dialog; 44 import java.awt.Label; 45 import java.awt.Panel; 46 import java.awt.Rectangle; 47 import java.awt.Window; 48 49 import java.awt.image.BufferedImage; 50 import java.awt.image.IndexColorModel; 51 52 import java.awt.print.Pageable; 53 import java.awt.print.PageFormat; 54 import java.awt.print.Paper; 55 import java.awt.print.Printable; 56 import java.awt.print.PrinterJob; 57 import java.awt.print.PrinterException; 58 import javax.print.PrintService; 59 60 import java.io.File; 61 62 import java.util.MissingResourceException; 63 import java.util.ResourceBundle; 64 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.Win32PrintServiceLookup; 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 JDK1.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(Win32PrintServiceLookup. 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 = Win32PrintServiceLookup.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 final 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 final 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 final 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 final int getCopiesAttrib() { 1633 if (defaultCopies) { 1634 return 0; 1635 } else { 1636 return getCopiesInt(); 1637 } 1638 } 1639 1640 private final void setRangeCopiesAttribute(int from, int to, 1641 boolean isRangeSet, 1642 int copies) { 1643 if (attributes != null) { 1644 if (isRangeSet) { 1645 attributes.add(new PageRanges(from, to)); 1646 setPageRange(from, to); 1647 } 1648 defaultCopies = false; 1649 attributes.add(new Copies(copies)); 1650 /* Since this is called from native to tell Java to sync 1651 * up with native, we don't call this class's own setCopies() 1652 * method which is mainly to send the value down to native 1653 */ 1654 super.setCopies(copies); 1655 mAttCopies = copies; 1656 } 1657 } 1658 1659 1660 1661 private final boolean getDestAttrib() { 1662 return (mDestination != null); 1663 } 1664 1665 /* Quality */ 1666 private final int getQualityAttrib() { 1667 return mAttQuality; 1668 } 1669 1670 private void setQualityAttrib(Attribute attr) { 1671 if (attr == PrintQuality.HIGH) { 1672 mAttQuality = -4; // DMRES_HIGH 1673 } else if (attr == PrintQuality.NORMAL) { 1674 mAttQuality = -3; // DMRES_MEDIUM 1675 } else { 1676 mAttQuality = -2; // DMRES_LOW 1677 } 1678 } 1679 1680 private void setQualityAttrib(Attribute attr, 1681 PrintRequestAttributeSet set) { 1682 setQualityAttrib(attr); 1683 set.add(attr); 1684 } 1685 1686 /* Color/Chromaticity */ 1687 private final int getColorAttrib() { 1688 return mAttChromaticity; 1689 } 1690 1691 private void setColorAttrib(Attribute attr) { 1692 if (attr == Chromaticity.COLOR) { 1693 mAttChromaticity = 2; // DMCOLOR_COLOR 1694 } else { 1695 mAttChromaticity = 1; // DMCOLOR_MONOCHROME 1696 } 1697 } 1698 1699 private void setColorAttrib(Attribute attr, 1700 PrintRequestAttributeSet set) { 1701 setColorAttrib(attr); 1702 set.add(attr); 1703 } 1704 1705 /* Sides */ 1706 private final int getSidesAttrib() { 1707 return mAttSides; 1708 } 1709 1710 private void setSidesAttrib(Attribute attr) { 1711 if (attr == Sides.TWO_SIDED_LONG_EDGE) { 1712 mAttSides = 2; // DMDUP_VERTICAL 1713 } else if (attr == Sides.TWO_SIDED_SHORT_EDGE) { 1714 mAttSides = 3; // DMDUP_HORIZONTAL 1715 } else { // Sides.ONE_SIDED 1716 mAttSides = 1; 1717 } 1718 } 1719 1720 private void setSidesAttrib(Attribute attr, 1721 PrintRequestAttributeSet set) { 1722 setSidesAttrib(attr); 1723 set.add(attr); 1724 } 1725 1726 /** MediaSizeName / dmPaper */ 1727 private final int[] getWin32MediaAttrib() { 1728 int wid_ht[] = {0, 0}; 1729 if (attributes != null) { 1730 Media media = (Media)attributes.get(Media.class); 1731 if (media instanceof MediaSizeName) { 1732 MediaSizeName msn = (MediaSizeName)media; 1733 MediaSize ms = MediaSize.getMediaSizeForName(msn); 1734 if (ms != null) { 1735 wid_ht[0] = (int)(ms.getX(MediaSize.INCH) * 72.0); 1736 wid_ht[1] = (int)(ms.getY(MediaSize.INCH) * 72.0); 1737 } 1738 } 1739 } 1740 return wid_ht; 1741 } 1742 1743 private void setWin32MediaAttrib(Attribute attr) { 1744 if (!(attr instanceof MediaSizeName)) { 1745 return; 1746 } 1747 MediaSizeName msn = (MediaSizeName)attr; 1748 mAttMediaSizeName = ((Win32PrintService)myService).findPaperID(msn); 1749 } 1750 1751 private void addPaperSize(PrintRequestAttributeSet aset, 1752 int dmIndex, int width, int length) { 1753 1754 if (aset == null) { 1755 return; 1756 } 1757 MediaSizeName msn = 1758 ((Win32PrintService)myService).findWin32Media(dmIndex); 1759 if (msn == null) { 1760 msn = ((Win32PrintService)myService). 1761 findMatchingMediaSizeNameMM((float)width, (float)length); 1762 } 1763 1764 if (msn != null) { 1765 aset.add(msn); 1766 } 1767 } 1768 1769 private void setWin32MediaAttrib(int dmIndex, int width, int length) { 1770 addPaperSize(attributes, dmIndex, width, length); 1771 mAttMediaSizeName = dmIndex; 1772 } 1773 1774 /* MediaTray / dmTray */ 1775 private void setMediaTrayAttrib(Attribute attr) { 1776 if (attr == MediaTray.BOTTOM) { 1777 mAttMediaTray = 2; // DMBIN_LOWER 1778 } else if (attr == MediaTray.ENVELOPE) { 1779 mAttMediaTray = 5; // DMBIN_ENVELOPE 1780 } else if (attr == MediaTray.LARGE_CAPACITY) { 1781 mAttMediaTray = 11; // DMBIN_LARGECAPACITY 1782 } else if (attr == MediaTray.MAIN) { 1783 mAttMediaTray =1; // DMBIN_UPPER 1784 } else if (attr == MediaTray.MANUAL) { 1785 mAttMediaTray = 4; // DMBIN_MANUAL 1786 } else if (attr == MediaTray.MIDDLE) { 1787 mAttMediaTray = 3; // DMBIN_MIDDLE 1788 } else if (attr == MediaTray.SIDE) { 1789 // no equivalent predefined value 1790 mAttMediaTray = 7; // DMBIN_AUTO 1791 } else if (attr == MediaTray.TOP) { 1792 mAttMediaTray = 1; // DMBIN_UPPER 1793 } else { 1794 if (attr instanceof Win32MediaTray) { 1795 mAttMediaTray = ((Win32MediaTray)attr).winID; 1796 } else { 1797 mAttMediaTray = 1; // default 1798 } 1799 } 1800 } 1801 1802 private void setMediaTrayAttrib(int dmBinID) { 1803 mAttMediaTray = dmBinID; 1804 MediaTray tray = ((Win32PrintService)myService).findMediaTray(dmBinID); 1805 } 1806 1807 private int getMediaTrayAttrib() { 1808 return mAttMediaTray; 1809 } 1810 1811 1812 1813 private final boolean getPrintToFileEnabled() { 1814 SecurityManager security = System.getSecurityManager(); 1815 if (security != null) { 1816 FilePermission printToFilePermission = 1817 new FilePermission("<<ALL FILES>>", "read,write"); 1818 try { 1819 security.checkPermission(printToFilePermission); 1820 } catch (SecurityException e) { 1821 return false; 1822 } 1823 } 1824 return true; 1825 } 1826 1827 private final void setNativeAttributes(int flags, int fields, int values) { 1828 if (attributes == null) { 1829 return; 1830 } 1831 if ((flags & PD_PRINTTOFILE) != 0) { 1832 Destination destPrn = (Destination)attributes.get( 1833 Destination.class); 1834 if (destPrn == null) { 1835 try { 1836 attributes.add(new Destination( 1837 new File("./out.prn").toURI())); 1838 } catch (SecurityException se) { 1839 try { 1840 attributes.add(new Destination( 1841 new URI("file:out.prn"))); 1842 } catch (URISyntaxException e) { 1843 } 1844 } 1845 } 1846 } else { 1847 attributes.remove(Destination.class); 1848 } 1849 1850 if ((flags & PD_COLLATE) != 0) { 1851 setCollateAttrib(SheetCollate.COLLATED, attributes); 1852 } else { 1853 setCollateAttrib(SheetCollate.UNCOLLATED, attributes); 1854 } 1855 1856 if ((flags & PD_PAGENUMS) != 0) { 1857 attributes.add(SunPageSelection.RANGE); 1858 } else if ((flags & PD_SELECTION) != 0) { 1859 attributes.add(SunPageSelection.SELECTION); 1860 } else { 1861 attributes.add(SunPageSelection.ALL); 1862 } 1863 1864 if ((fields & DM_ORIENTATION) != 0) { 1865 if ((values & SET_ORIENTATION) != 0) { 1866 setOrientAttrib(OrientationRequested.LANDSCAPE, attributes); 1867 } else { 1868 setOrientAttrib(OrientationRequested.PORTRAIT, attributes); 1869 } 1870 } 1871 1872 if ((fields & DM_COLOR) != 0) { 1873 if ((values & SET_COLOR) != 0) { 1874 setColorAttrib(Chromaticity.COLOR, attributes); 1875 } else { 1876 setColorAttrib(Chromaticity.MONOCHROME, attributes); 1877 } 1878 } 1879 1880 if ((fields & DM_PRINTQUALITY) != 0) { 1881 PrintQuality quality; 1882 if ((values & SET_RES_LOW) != 0) { 1883 quality = PrintQuality.DRAFT; 1884 } else if ((fields & SET_RES_HIGH) != 0) { 1885 quality = PrintQuality.HIGH; 1886 } else { 1887 quality = PrintQuality.NORMAL; 1888 } 1889 setQualityAttrib(quality, attributes); 1890 } 1891 1892 if ((fields & DM_DUPLEX) != 0) { 1893 Sides sides; 1894 if ((values & SET_DUP_VERTICAL) != 0) { 1895 sides = Sides.TWO_SIDED_LONG_EDGE; 1896 } else if ((values & SET_DUP_HORIZONTAL) != 0) { 1897 sides = Sides.TWO_SIDED_SHORT_EDGE; 1898 } else { 1899 sides = Sides.ONE_SIDED; 1900 } 1901 setSidesAttrib(sides, attributes); 1902 } 1903 } 1904 1905 private static final class DevModeValues { 1906 int dmFields; 1907 short copies; 1908 short collate; 1909 short color; 1910 short duplex; 1911 short orient; 1912 short paper; 1913 short bin; 1914 short xres_quality; 1915 short yres; 1916 } 1917 1918 private void getDevModeValues(PrintRequestAttributeSet aset, 1919 DevModeValues info) { 1920 1921 Copies c = (Copies)aset.get(Copies.class); 1922 if (c != null) { 1923 info.dmFields |= DM_COPIES; 1924 info.copies = (short)c.getValue(); 1925 } 1926 1927 SheetCollate sc = (SheetCollate)aset.get(SheetCollate.class); 1928 if (sc != null) { 1929 info.dmFields |= DM_COLLATE; 1930 info.collate = (sc == SheetCollate.COLLATED) ? 1931 DMCOLLATE_TRUE : DMCOLLATE_FALSE; 1932 } 1933 1934 Chromaticity ch = (Chromaticity)aset.get(Chromaticity.class); 1935 if (ch != null) { 1936 info.dmFields |= DM_COLOR; 1937 if (ch == Chromaticity.COLOR) { 1938 info.color = DMCOLOR_COLOR; 1939 } else { 1940 info.color = DMCOLOR_MONOCHROME; 1941 } 1942 } 1943 1944 Sides s = (Sides)aset.get(Sides.class); 1945 if (s != null) { 1946 info.dmFields |= DM_DUPLEX; 1947 if (s == Sides.TWO_SIDED_LONG_EDGE) { 1948 info.duplex = DMDUP_VERTICAL; 1949 } else if (s == Sides.TWO_SIDED_SHORT_EDGE) { 1950 info.duplex = DMDUP_HORIZONTAL; 1951 } else { // Sides.ONE_SIDED 1952 info.duplex = DMDUP_SIMPLEX; 1953 } 1954 } 1955 1956 OrientationRequested or = 1957 (OrientationRequested)aset.get(OrientationRequested.class); 1958 if (or != null) { 1959 info.dmFields |= DM_ORIENTATION; 1960 info.orient = (or == OrientationRequested.LANDSCAPE) 1961 ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT; 1962 } 1963 1964 Media m = (Media)aset.get(Media.class); 1965 if (m instanceof MediaSizeName) { 1966 info.dmFields |= DM_PAPERSIZE; 1967 MediaSizeName msn = (MediaSizeName)m; 1968 info.paper = 1969 (short)((Win32PrintService)myService).findPaperID(msn); 1970 } 1971 1972 MediaTray mt = null; 1973 if (m instanceof MediaTray) { 1974 mt = (MediaTray)m; 1975 } 1976 if (mt == null) { 1977 SunAlternateMedia sam = 1978 (SunAlternateMedia)aset.get(SunAlternateMedia.class); 1979 if (sam != null && (sam.getMedia() instanceof MediaTray)) { 1980 mt = (MediaTray)sam.getMedia(); 1981 } 1982 } 1983 1984 if (mt != null) { 1985 info.dmFields |= DM_DEFAULTSOURCE; 1986 info.bin = (short)(((Win32PrintService)myService).findTrayID(mt)); 1987 } 1988 1989 PrintQuality q = (PrintQuality)aset.get(PrintQuality.class); 1990 if (q != null) { 1991 info.dmFields |= DM_PRINTQUALITY; 1992 if (q == PrintQuality.DRAFT) { 1993 info.xres_quality = DMRES_DRAFT; 1994 } else if (q == PrintQuality.HIGH) { 1995 info.xres_quality = DMRES_HIGH; 1996 } else { 1997 info.xres_quality = DMRES_MEDIUM; 1998 } 1999 } 2000 2001 PrinterResolution r = 2002 (PrinterResolution)aset.get(PrinterResolution.class); 2003 if (r != null) { 2004 info.dmFields |= DM_PRINTQUALITY | DM_YRESOLUTION; 2005 info.xres_quality = 2006 (short)r.getCrossFeedResolution(PrinterResolution.DPI); 2007 info.yres = (short)r.getFeedResolution(PrinterResolution.DPI); 2008 } 2009 } 2010 2011 /* This method is called from native to update the values in the 2012 * attribute set which originates from the cross-platform dialog, 2013 * but updated by the native DocumentPropertiesUI which updates the 2014 * devmode. This syncs the devmode back in to the attributes so that 2015 * we can update the cross-platform dialog. 2016 * The attribute set here is a temporary one installed whilst this 2017 * happens, 2018 */ 2019 private final void setJobAttributes(PrintRequestAttributeSet attributes, 2020 int fields, int values, 2021 short copies, 2022 short dmPaperSize, 2023 short dmPaperWidth, 2024 short dmPaperLength, 2025 short dmDefaultSource, 2026 short xRes, 2027 short yRes) { 2028 2029 if (attributes == null) { 2030 return; 2031 } 2032 2033 if ((fields & DM_COPIES) != 0) { 2034 attributes.add(new Copies(copies)); 2035 } 2036 2037 if ((fields & DM_COLLATE) != 0) { 2038 if ((values & SET_COLLATED) != 0) { 2039 attributes.add(SheetCollate.COLLATED); 2040 } else { 2041 attributes.add(SheetCollate.UNCOLLATED); 2042 } 2043 } 2044 2045 if ((fields & DM_ORIENTATION) != 0) { 2046 if ((values & SET_ORIENTATION) != 0) { 2047 attributes.add(OrientationRequested.LANDSCAPE); 2048 } else { 2049 attributes.add(OrientationRequested.PORTRAIT); 2050 } 2051 } 2052 2053 if ((fields & DM_COLOR) != 0) { 2054 if ((values & SET_COLOR) != 0) { 2055 attributes.add(Chromaticity.COLOR); 2056 } else { 2057 attributes.add(Chromaticity.MONOCHROME); 2058 } 2059 } 2060 2061 if ((fields & DM_PRINTQUALITY) != 0) { 2062 /* value < 0 indicates quality setting. 2063 * value > 0 indicates X resolution. In that case 2064 * hopefully we will also find y-resolution specified. 2065 * If its not, assume its the same as x-res. 2066 * Maybe Java code should try to reconcile this against 2067 * the printers claimed set of supported resolutions. 2068 */ 2069 if (xRes < 0) { 2070 PrintQuality quality; 2071 if ((values & SET_RES_LOW) != 0) { 2072 quality = PrintQuality.DRAFT; 2073 } else if ((fields & SET_RES_HIGH) != 0) { 2074 quality = PrintQuality.HIGH; 2075 } else { 2076 quality = PrintQuality.NORMAL; 2077 } 2078 attributes.add(quality); 2079 } else if (xRes > 0 && yRes > 0) { 2080 attributes.add( 2081 new PrinterResolution(xRes, yRes, PrinterResolution.DPI)); 2082 } 2083 } 2084 2085 if ((fields & DM_DUPLEX) != 0) { 2086 Sides sides; 2087 if ((values & SET_DUP_VERTICAL) != 0) { 2088 sides = Sides.TWO_SIDED_LONG_EDGE; 2089 } else if ((values & SET_DUP_HORIZONTAL) != 0) { 2090 sides = Sides.TWO_SIDED_SHORT_EDGE; 2091 } else { 2092 sides = Sides.ONE_SIDED; 2093 } 2094 attributes.add(sides); 2095 } 2096 2097 if ((fields & DM_PAPERSIZE) != 0) { 2098 addPaperSize(attributes, dmPaperSize, dmPaperWidth, dmPaperLength); 2099 } 2100 2101 if ((fields & DM_DEFAULTSOURCE) != 0) { 2102 MediaTray tray = 2103 ((Win32PrintService)myService).findMediaTray(dmDefaultSource); 2104 attributes.add(new SunAlternateMedia(tray)); 2105 } 2106 } 2107 2108 private native boolean showDocProperties(long hWnd, 2109 PrintRequestAttributeSet aset, 2110 int dmFields, 2111 short copies, 2112 short collate, 2113 short color, 2114 short duplex, 2115 short orient, 2116 short paper, 2117 short bin, 2118 short xres_quality, 2119 short yres); 2120 2121 @SuppressWarnings("deprecation") 2122 public PrintRequestAttributeSet 2123 showDocumentProperties(Window owner, 2124 PrintService service, 2125 PrintRequestAttributeSet aset) 2126 { 2127 try { 2128 setNativePrintServiceIfNeeded(service.getName()); 2129 } catch (PrinterException e) { 2130 } 2131 long hWnd = ((WWindowPeer)(owner.getPeer())).getHWnd(); 2132 DevModeValues info = new DevModeValues(); 2133 getDevModeValues(aset, info); 2134 boolean ok = 2135 showDocProperties(hWnd, aset, 2136 info.dmFields, 2137 info.copies, 2138 info.collate, 2139 info.color, 2140 info.duplex, 2141 info.orient, 2142 info.paper, 2143 info.bin, 2144 info.xres_quality, 2145 info.yres); 2146 2147 if (ok) { 2148 return aset; 2149 } else { 2150 return null; 2151 } 2152 } 2153 2154 /* Printer Resolution. See also getXRes() and getYRes() */ 2155 private final void setResolutionDPI(int xres, int yres) { 2156 if (attributes != null) { 2157 PrinterResolution res = 2158 new PrinterResolution(xres, yres, PrinterResolution.DPI); 2159 attributes.add(res); 2160 } 2161 mAttXRes = xres; 2162 mAttYRes = yres; 2163 } 2164 2165 private void setResolutionAttrib(Attribute attr) { 2166 PrinterResolution pr = (PrinterResolution)attr; 2167 mAttXRes = pr.getCrossFeedResolution(PrinterResolution.DPI); 2168 mAttYRes = pr.getFeedResolution(PrinterResolution.DPI); 2169 } 2170 2171 private void setPrinterNameAttrib(String printerName) { 2172 PrintService service = this.getPrintService(); 2173 2174 if (printerName == null) { 2175 return; 2176 } 2177 2178 if (service != null && printerName.equals(service.getName())) { 2179 return; 2180 } else { 2181 PrintService []services = PrinterJob.lookupPrintServices(); 2182 for (int i=0; i<services.length; i++) { 2183 if (printerName.equals(services[i].getName())) { 2184 2185 try { 2186 this.setPrintService(services[i]); 2187 } catch (PrinterException e) { 2188 } 2189 return; 2190 } 2191 } 2192 } 2193 //** END Functions called by native code for querying/updating attributes 2194 2195 } 2196 2197 @SuppressWarnings("serial") // JDK-implementation class 2198 class PrintToFileErrorDialog extends Dialog implements ActionListener{ 2199 public PrintToFileErrorDialog(Frame parent, String title, String message, 2200 String buttonText) { 2201 super(parent, title, true); 2202 init (parent, title, message, buttonText); 2203 } 2204 2205 public PrintToFileErrorDialog(Dialog parent, String title, String message, 2206 String buttonText) { 2207 super(parent, title, true); 2208 init (parent, title, message, buttonText); 2209 } 2210 2211 private void init(Component parent, String title, String message, 2212 String buttonText) { 2213 Panel p = new Panel(); 2214 add("Center", new Label(message)); 2215 Button btn = new Button(buttonText); 2216 btn.addActionListener(this); 2217 p.add(btn); 2218 add("South", p); 2219 pack(); 2220 2221 Dimension dDim = getSize(); 2222 if (parent != null) { 2223 Rectangle fRect = parent.getBounds(); 2224 setLocation(fRect.x + ((fRect.width - dDim.width) / 2), 2225 fRect.y + ((fRect.height - dDim.height) / 2)); 2226 } 2227 } 2228 2229 @Override 2230 public void actionPerformed(ActionEvent event) { 2231 setVisible(false); 2232 dispose(); 2233 return; 2234 } 2235 } 2236 2237 2238 2239 2240 /** 2241 * Initialize JNI field and method ids 2242 */ 2243 private static native void initIDs(); 2244 2245 }