diff options
author | smallsql <smallsql> | 2011-01-24 16:38:37 +0300 |
---|---|---|
committer | smallsql <smallsql> | 2011-01-24 16:38:37 +0300 |
commit | e6457788e8098e8cfde737cbc14bbc056222dc58 (patch) | |
tree | 707e2e60058a0c6f265067aa9e0dc6fe6803f286 /openjdk/sun/print | |
parent | 0d4d781ceee5cc97c327d548ed3b067be3f26b95 (diff) |
Implementation of several print attributes (Copies, Collation, Orientation, MediaSize, MediaTray). The PrintGraphics now fully supports the create() function.
Diffstat (limited to 'openjdk/sun/print')
-rw-r--r-- | openjdk/sun/print/Win32PrintJob.java | 486 | ||||
-rw-r--r-- | openjdk/sun/print/Win32PrintService.java | 155 |
2 files changed, 561 insertions, 80 deletions
diff --git a/openjdk/sun/print/Win32PrintJob.java b/openjdk/sun/print/Win32PrintJob.java index ae7ba2a9..0ec8fc14 100644 --- a/openjdk/sun/print/Win32PrintJob.java +++ b/openjdk/sun/print/Win32PrintJob.java @@ -1,6 +1,6 @@ /* Copyright (C) 2009 Volker Berlin (i-net software) - Copyright (C) 2010 Karsten Heinrich (i-net software) + Copyright (C) 2010, 2011 Karsten Heinrich (i-net software) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -24,17 +24,17 @@ */ package sun.print; +import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; -import java.awt.GraphicsConfiguration; -import java.awt.HeadlessException; +import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.print.PageFormat; import java.awt.print.Pageable; +import java.awt.print.Paper; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; -import java.io.BufferedInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -43,6 +43,8 @@ import java.io.InputStream; import java.net.URI; import java.net.URL; import java.util.ArrayList; +import java.util.List; +import java.util.TreeSet; import javax.print.CancelablePrintJob; import javax.print.Doc; @@ -58,6 +60,7 @@ import javax.print.attribute.PrintJobAttribute; import javax.print.attribute.PrintJobAttributeSet; import javax.print.attribute.PrintRequestAttribute; import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.Chromaticity; import javax.print.attribute.standard.Copies; import javax.print.attribute.standard.Destination; import javax.print.attribute.standard.DocumentName; @@ -65,9 +68,12 @@ import javax.print.attribute.standard.Fidelity; import javax.print.attribute.standard.JobName; import javax.print.attribute.standard.JobOriginatingUserName; import javax.print.attribute.standard.Media; +import javax.print.attribute.standard.MediaPrintableArea; import javax.print.attribute.standard.MediaSize; import javax.print.attribute.standard.MediaSizeName; +import javax.print.attribute.standard.MediaTray; import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.PageRanges; import javax.print.attribute.standard.PrinterIsAcceptingJobs; import javax.print.attribute.standard.PrinterState; import javax.print.attribute.standard.PrinterStateReason; @@ -79,6 +85,7 @@ import javax.print.event.PrintJobEvent; import javax.print.event.PrintJobListener; import sun.awt.windows.WPrinterJob; +import sun.print.Win32PrintService.NetMediaTray; import cli.System.Drawing.Printing.*; @@ -95,9 +102,8 @@ public class Win32PrintJob implements CancelablePrintJob{ private final Win32PrintService service; - private boolean fidelity; + private boolean printing; - private boolean printReturned; private PrintRequestAttributeSet reqAttrSet; @@ -115,6 +121,8 @@ public class Win32PrintJob implements CancelablePrintJob{ private InputStream instream; /* default values overridden by those extracted from the attributes */ + private boolean fidelity; + private boolean printColor; private String jobName = "Java Printing"; private int copies; private MediaSizeName mediaName; @@ -123,6 +131,11 @@ public class Win32PrintJob implements CancelablePrintJob{ private final PrintPeer peer; private PrinterException printerException; + + private PageNumberConverter pageRanges; + + private MediaTray mediaTray; + Win32PrintJob(Win32PrintService service, PrintPeer peer){ this.service = service; @@ -440,11 +453,17 @@ public class Win32PrintJob implements CancelablePrintJob{ } public void pageableJob(Pageable pageable) throws PrintException { + // a general hint for this code here: The PrintJob implementation (WPrinterJob) in the Oracle + // JRE implements SunPrinterJobService - which we don't here. Unfortunately this is used as a hint + // to distinguish between the build-in printer service and custom printer services. So for the RasterPrinterJob + // this implementation of the Win32PrintJob is a custom print job! That's why several methods of + // RasterPrintJob(which only apply to the SunPrinterJobService otherwise) had to be moved here. + // This includes the attribute resolving and the media patch for instance. try { - PrintDocument printDocument = createPrintDocument(); + PrintDocument printDocument = createPrintDocument( ); + pageable = patchMedia( pageable ); - //TODO Attribute set in printDocument - printDocument.add_QueryPageSettings(new QueryPageSettingsEventHandler(new QueryPage( pageable ) ) ); + printDocument.add_QueryPageSettings(new QueryPageSettingsEventHandler(new QueryPage( pageable, printColor, mediaTray ) ) ); printDocument.add_PrintPage(new PrintPageEventHandler(new PrintPage(pageable))); printDocument.Print(); if(printerException != null){ @@ -463,25 +482,203 @@ public class Win32PrintJob implements CancelablePrintJob{ } - private PrintDocument createPrintDocument(){ + private PrintDocument createPrintDocument() throws PrintException{ PrintDocument printDocument = new PrintDocument(); PrinterSettings settings = printDocument.get_PrinterSettings(); - + settings.set_PrinterName( service.getName() ); + if( !settings.get_IsValid() ){ + throw new PrintException("Printer name ''" + service.getName() + "' is invalid."); + } + + if( jobName != null ){ + printDocument.set_DocumentName( jobName ); + } + printDocument.get_DefaultPageSettings().set_Color(printColor); + Attribute destination = reqAttrSet.get(Destination.class); if(destination instanceof Destination){ File destFile = new File(((Destination)destination).getURI()); settings.set_PrintFileName(destFile.getAbsolutePath()); } - + settings.set_Copies((short)copies); + boolean collated = false; if(copies > 1){ - Attribute collate = reqAttrSet.get(SheetCollate.class); - settings.set_Collate(collate == SheetCollate.COLLATED); + Object collate = reqAttrSet.get(SheetCollate.class); + if( collate == null ){ + collate = service.getDefaultAttributeValue(SheetCollate.class); + } + collated = collate == SheetCollate.COLLATED; + settings.set_Collate( collated ); } - + Attribute pageRangeObj = reqAttrSet.get(PageRanges.class); + if( pageRangeObj != null ){ + int[][] ranges = ((PageRanges)pageRangeObj).getMembers(); + if( ranges.length > 1 ){ + settings.set_PrintRange( PrintRange.wrap( PrintRange.Selection ) ); + } else { + if( ranges.length > 0 ){ + settings.set_FromPage(ranges[0][0]); + settings.set_ToPage(ranges[0][1]); + settings.set_PrintRange( PrintRange.wrap( PrintRange.SomePages ) ); + } // else allPages??? + } + } else { + settings.set_PrintRange( PrintRange.wrap( PrintRange.AllPages ) ); + } + pageRanges = new PageNumberConverter( (PageRanges)pageRangeObj, copies, collated ); return printDocument; } + // copied from RasterPrintJob + // Since we don't implement SunPrinterJobService the hack in RasterPrintService which applies + // the media format to the auto-generated OpenBook doesn't work here. So we have to modify + // the page format of the OpenBook here - equal to the code in RasterPrintJob + private Pageable patchMedia( Pageable pageable ){ + /* OpenBook is used internally only when app uses Printable. + * This is the case when we use the values from the attribute set. + */ + Media media = (Media)reqAttrSet.get(Media.class); + OrientationRequested orientReq = (OrientationRequested)reqAttrSet.get(OrientationRequested.class); + MediaPrintableArea mpa = (MediaPrintableArea)reqAttrSet.get(MediaPrintableArea.class); + + if ((orientReq != null || media != null || mpa != null) && pageable instanceof OpenBook) { + + /* We could almost(!) use PrinterJob.getPageFormat() except + * here we need to start with the PageFormat from the OpenBook : + */ + Printable printable = pageable.getPrintable(0); + PageFormat pf = (PageFormat)pageable.getPageFormat(0).clone(); + Paper paper = pf.getPaper(); + + /* If there's a media but no media printable area, we can try + * to retrieve the default value for mpa and use that. + */ + if (mpa == null && media != null && service.isAttributeCategorySupported(MediaPrintableArea.class)) { + Object mpaVals = service. getSupportedAttributeValues(MediaPrintableArea.class, null, reqAttrSet); + if (mpaVals instanceof MediaPrintableArea[] && ((MediaPrintableArea[])mpaVals).length > 0) { + mpa = ((MediaPrintableArea[])mpaVals)[0]; + } + } + + if (isSupportedValue(orientReq, reqAttrSet) || (!fidelity && orientReq != null)) { + int orient; + if (orientReq.equals(OrientationRequested.REVERSE_LANDSCAPE)) { + orient = PageFormat.REVERSE_LANDSCAPE; + } else if (orientReq.equals(OrientationRequested.LANDSCAPE)) { + orient = PageFormat.LANDSCAPE; + } else { + orient = PageFormat.PORTRAIT; + } + pf.setOrientation(orient); + } + + if (isSupportedValue(media, reqAttrSet) || (!fidelity && media != null)) { + if (media instanceof MediaSizeName) { + MediaSizeName msn = (MediaSizeName)media; + MediaSize msz = MediaSize.getMediaSizeForName(msn); + if (msz != null) { + float paperWid = msz.getX(MediaSize.INCH) * 72.0f; + float paperHgt = msz.getY(MediaSize.INCH) * 72.0f; + paper.setSize(paperWid, paperHgt); + if (mpa == null) { + paper.setImageableArea(72.0, 72.0, paperWid-144.0, paperHgt-144.0); + } + } + } + } + + if (isSupportedValue(mpa, reqAttrSet) || (!fidelity && mpa != null)) { + float [] printableArea = mpa.getPrintableArea(MediaPrintableArea.INCH); + for (int i=0; i < printableArea.length; i++) { + printableArea[i] = printableArea[i]*72.0f; + } + paper.setImageableArea(printableArea[0], printableArea[1], printableArea[2], printableArea[3]); + } + + pf.setPaper(paper); + pf = validatePage(pf); + return new OpenBook(pf, printable); + } + return pageable; + } + + // copied from RasterPrintJob to since we don't implement SunPrinterJobService + /** + * The passed in PageFormat is cloned and altered to be usable on + * the PrinterJob's current printer. + */ + private PageFormat validatePage(PageFormat page) { + PageFormat newPage = (PageFormat)page.clone(); + Paper newPaper = new Paper(); + validatePaper(newPage.getPaper(), newPaper); + newPage.setPaper(newPaper); + + return newPage; + } + + // copied from RasterPrintJob to since we don't implement SunPrinterJobService + /** + * updates a Paper object to reflect the current printer's selected + * paper size and imageable area for that paper size. + * Default implementation copies settings from the original, applies + * applies some validity checks, changes them only if they are + * clearly unreasonable, then sets them into the new Paper. + * Subclasses are expected to override this method to make more + * informed decisons. + */ + protected void validatePaper(Paper origPaper, Paper newPaper) { + if (origPaper == null || newPaper == null) { + return; + } else { + double wid = origPaper.getWidth(); + double hgt = origPaper.getHeight(); + double ix = origPaper.getImageableX(); + double iy = origPaper.getImageableY(); + double iw = origPaper.getImageableWidth(); + double ih = origPaper.getImageableHeight(); + + /* Assume any +ve values are legal. Overall paper dimensions + * take precedence. Make sure imageable area fits on the paper. + */ + Paper defaultPaper = new Paper(); + wid = ((wid > 0.0) ? wid : defaultPaper.getWidth()); + hgt = ((hgt > 0.0) ? hgt : defaultPaper.getHeight()); + ix = ((ix > 0.0) ? ix : defaultPaper.getImageableX()); + iy = ((iy > 0.0) ? iy : defaultPaper.getImageableY()); + iw = ((iw > 0.0) ? iw : defaultPaper.getImageableWidth()); + ih = ((ih > 0.0) ? ih : defaultPaper.getImageableHeight()); + /* full width/height is not likely to be imageable, but since we + * don't know the limits we have to allow it + */ + if (iw > wid) { + iw = wid; + } + if (ih > hgt) { + ih = hgt; + } + if ((ix + iw) > wid) { + ix = wid - iw; + } + if ((iy + ih) > hgt) { + iy = hgt - ih; + } + newPaper.setSize(wid, hgt); + newPaper.setImageableArea(ix, iy, iw, ih); + } + } + + // copied from RasterPrintJob + /** + * Checks whether a certain attribute value is valid for the current print service + * @param attrval the attribute value + * @param attrset Set of printing attributes for a supposed job (both job-level attributes and document-level attributes), or null. + * @return true if valid + */ + protected boolean isSupportedValue(Attribute attrval, PrintRequestAttributeSet attrset) { + return (attrval != null && service != null && service.isAttributeValueSupported(attrval, DocFlavor.SERVICE_FORMATTED.PAGEABLE, attrset)); + } + /* * There's some inefficiency here as the job set is created even though it may never be requested. @@ -566,7 +763,17 @@ public class Win32PrintJob implements CancelablePrintJob{ } else { fidelity = false; } + + Attribute chroma = reqAttrSet.get( Chromaticity.class ); + // TODO check whether supported by the print service + printColor = chroma == Chromaticity.COLOR; + Attribute newTray = reqAttrSet.get( Media.class ); + if( newTray instanceof MediaTray ){ + mediaTray = (MediaTray)newTray; + } + // TODO check whether supported by the print service + Class category; Attribute [] attrs = reqAttrSet.toArray(); for (int i=0; i<attrs.length; i++) { @@ -616,7 +823,7 @@ public class Win32PrintJob implements CancelablePrintJob{ // If requested MediaSizeName is not supported, // get the corresponding media size - this will // be used to create a new PageFormat. - if (!service.isAttributeValueSupported(attr, null, null)) { + if (!service.isAttributeValueSupported(attr, flavor, null)) { mediaSize = MediaSize.getMediaSizeForName(mediaName); } } @@ -641,6 +848,24 @@ public class Win32PrintJob implements CancelablePrintJob{ } } } + + /** + * Converts the Java 1/72 inch to .NET 1/100 inch + * @param javaLength the java length in 1/72 inch + * @return the .NET length in 1/100 inch + */ + private static int java2netLength( int javaLength ){ + return (int) Math.round( (double)(javaLength * 100) / 72d ); + } + + /** + * Converts the Java 1/72 inch to .NET 1/100 inch + * @param javaLength the java length in 1/72 inch + * @return the .NET length in 1/100 inch + */ + private static int java2netLength( double javaLength ){ + return (int) Math.round( (javaLength * 100) / 72d ); + } private class PrintPage implements PrintPageEventHandler.Method{ @@ -651,11 +876,6 @@ public class Win32PrintJob implements CancelablePrintJob{ PrintPage(Pageable pageable){ this.pageable = pageable; - //TODO firstPage - //TODO lastPage - //TODO PageRange - //TODO Num Copies - //TODO collatedCopies } @@ -663,21 +883,22 @@ public class Win32PrintJob implements CancelablePrintJob{ public void Invoke(Object paramObject, PrintPageEventArgs ev){ try{ - System.err.println("Invoke:"+paramObject); - Printable printable = pageable.getPrintable(pageIndex); - PageFormat pageFormat = pageable.getPageFormat(pageIndex); + int realPage = pageRanges.getPageForIndex(pageIndex); + + Printable printable = pageable.getPrintable(realPage); + PageFormat pageFormat = pageable.getPageFormat(realPage); BufferedImage pBand = new BufferedImage(1, 1, BufferedImage.TYPE_3BYTE_BGR); Graphics2D imageGraphics = pBand.createGraphics(); - ((RasterPrinterJob)job).setGraphicsConfigInfo(imageGraphics.getTransform(), pageFormat.getWidth(), pageFormat.getHeight()); + ((RasterPrinterJob)job).setGraphicsConfigInfo(imageGraphics.getTransform(), pageFormat.getImageableWidth(), pageFormat.getImageableHeight()); PeekGraphics peekGraphics = new PeekGraphics(imageGraphics, job ); /* * Because Sun is calling first with a PeekGraphics that we do it else for compatibility */ - if(pageIndex == 0){ - int pageResult = printable.print(peekGraphics, pageFormat, pageIndex); + if(realPage == 0){ + int pageResult = printable.print(peekGraphics, pageFormat, realPage); if(pageResult != Printable.PAGE_EXISTS){ ev.set_HasMorePages(false); ev.set_Cancel(true); @@ -685,12 +906,40 @@ public class Win32PrintJob implements CancelablePrintJob{ } } Graphics printGraphics = peer.createGraphics(ev.get_Graphics()); - printable.print(printGraphics, pageFormat, pageIndex++); - - printable = pageable.getPrintable(pageIndex); - pageFormat = pageable.getPageFormat(pageIndex); - int pageResult = printable.print(peekGraphics, pageFormat, pageIndex); - ev.set_HasMorePages(pageResult == Printable.PAGE_EXISTS); + if( printGraphics instanceof Graphics2D ){ + Graphics2D g2d = ((Graphics2D)printGraphics); + int tX = (int) pageFormat.getWidth(); + int tY = (int) pageFormat.getHeight(); + // apply Java to .NET scaling (1/72 inch to 1/100 inch) + g2d.scale(100d/72d, 100d/72d); + // NOTE on Landscape printing: + // Setting landscape to true on the printer settings + // of a page already rotates the page! The orig. java code rotates the page itself, + // for .NET this is not required. + if( orient == OrientationRequested.REVERSE_LANDSCAPE){ + g2d.translate( tX, tY ); + g2d.rotate( Math.PI ); + } + } + printable.print(printGraphics, pageFormat, realPage); + + realPage = pageRanges.getPageForIndex(++pageIndex); + if( realPage >= 0 ){ + printable = pageable.getPrintable(realPage); + pageFormat = pageable.getPageFormat(realPage); + int pageResult = printable.print(peekGraphics, pageFormat, realPage); + if( pageResult == Printable.PAGE_EXISTS ){ + ev.set_HasMorePages( true ); + } else { + if( pageRanges.checkJobComplete(pageIndex) ){ + ev.set_HasMorePages( false ); + } else { + ev.set_HasMorePages( true ); + } + } + } else { + ev.set_HasMorePages( false ); + } }catch(PrinterException ex){ printerException = ex; ex.printStackTrace(); @@ -705,37 +954,174 @@ public class Win32PrintJob implements CancelablePrintJob{ private final Pageable pageable; private int pageIndex; + private final boolean printColor; + private final MediaTray tray; - QueryPage(Pageable pageable){ - this.pageable = pageable; - //TODO firstPage - //TODO lastPage - //TODO PageRange - //TODO Num Copies - //TODO collatedCopies + QueryPage(Pageable pageable, boolean printColor, MediaTray tray ){ + this.printColor = printColor; + this.pageable = pageable; + this.tray = tray; } @Override public void Invoke(Object source, QueryPageSettingsEventArgs e) { + int realPage = pageRanges.getPageForIndex(pageIndex); // apply page settings to the current page - PageFormat format = pageable.getPageFormat(pageIndex); + PageFormat format = pageable.getPageFormat(realPage); PageSettings pageSettings = e.get_PageSettings(); - pageSettings.set_Landscape(format.getOrientation() == PageFormat.LANDSCAPE); + pageSettings.set_Color( printColor ); + PaperSource paperSource = service.getPaperSourceForTray( tray ); + if( paperSource != null ){ + pageSettings.set_PaperSource( paperSource ); + } PaperSize ps = new PaperSize(); - ps.set_Height( (int)Math.round( format.getHeight() ) ); - ps.set_Width( (int)Math.round( format.getWidth() ) ); + ps.set_Height( java2netLength( format.getHeight() ) ); + ps.set_Width( java2netLength( format.getWidth() ) ); pageSettings.set_PaperSize( ps ); Margins margins = new Margins(); - margins.set_Left( (int) format.getImageableX() ); - margins.set_Top( (int)format.getImageableY() ); - margins.set_Right( (int) (format.getWidth() - format.getImageableX() - format.getImageableWidth() ) ); - margins.set_Bottom( (int)(format.getHeight() - format.getImageableY() - format.getImageableHeight() ) ); - pageSettings.set_Margins( margins ); + margins.set_Left( java2netLength( format.getImageableX() ) ); + margins.set_Top( java2netLength( format.getImageableY() ) ); + margins.set_Right( java2netLength(format.getWidth() - format.getImageableX() - format.getImageableWidth() ) ); + margins.set_Bottom( java2netLength(format.getHeight() - format.getImageableY() - format.getImageableHeight() ) ); + pageSettings.set_Margins( margins ); pageIndex++; } - + } + + /** + * Determines which logical page to print for a certain physical page + */ + public static class PageNumberConverter{ + + private List<Range> ranges; + private int totalPages = -1; + private final int copies; + + public PageNumberConverter( PageRanges pages, int copies, boolean collated ) { + // NOTE: uncollated is handled by the printer driver! If we would handle that here, + // we would get copies^2 copies! + this.copies = collated ? copies : 1; + if( pages != null && pages.getMembers() != null && pages.getMembers().length > 0 ){ + TreeSet<Range> rangesSort = new TreeSet<Range>(); + OUTER: + for( int[] range : pages.getMembers() ){ + Range r = new Range( range[0], range[1] + 1 ); // +1 to inlucde the uppre end + for( Range recent : rangesSort ){ + if( recent.canMerge(r) ){ + recent.merge(r); + continue OUTER; + } + } + rangesSort.add( r ); + } + // finally merge + Range recent = null; + ranges = new ArrayList<Range>(); + for( Range r : rangesSort ){ + if( recent != null && recent.canMerge( r ) ){ + recent.merge( r ); + } else { + ranges.add( r ); + recent = r; + } + } + // calculate total pages, required for collated copies + totalPages = 0; + for( Range r : rangesSort ){ + int diff = r.end - r.start; + totalPages += diff; + } + } + } + + /** + * Must be called in case the printable returns no-more-pages. Will return whether the print job + * will continue due to pending copies + * @param index the current page index + * @return if false, the print job will continue with copies, if true terminate the job + */ + public boolean checkJobComplete( int index ){ + if( ranges != null ){ + return true; + } + if( totalPages < 0 ){ + // this is the first time, this was called for 'all-pages' so it's the total number + totalPages = index; + } + return index > copies * totalPages; + } + + /** + * Returns which page to be printed for a certain page index + * @param index the inex to be printed + * @return the page number or -1, if there is no page for this index + */ + public int getPageForIndex( int index ){ + if( index < 0 || ( totalPages >=0 && index >= copies * totalPages ) ){ + return -1; + } + if( ranges == null ){ + return totalPages >=0 ? index % totalPages : index; + } + int counter = 0; + if( copies > 1 ){ + counter += (index / totalPages) * totalPages; + } + for( Range r : ranges ){ + int upper = counter + (r.end - r.start); + if( index < upper ){ + // so we're in the correct range + return r.start + ( index - counter ) - 1; + } else { + counter = upper; + } + } + return -1; + } + + /** + * A singular page range + */ + private static class Range implements Comparable<Range> { + + public int start; + public int end; + + public Range(int start, int end) { + this.start = start; + this.end = end; + } + + /** + * Checks whether the ranges intersect of have no gap in between + * @param otherRange the range to be checked + * @return true, if the ranges can be merged + */ + public boolean canMerge( Range otherRange ){ + if( otherRange.end >= start && otherRange.end <= end ){ + return true; + } + if( otherRange.start >= start && otherRange.start <= end ){ + return true; + } + return false; + } + + /** + * Merges the other range into this range. Ignores the gap between the ranges if there is any + * @param otherRange the range to be merged + */ + public void merge( Range otherRange ){ + start = Math.min(start, otherRange.start); + end = Math.max(end, otherRange.end); + } + + public int compareTo(Range o) { + return start - o.start; + } + } } } diff --git a/openjdk/sun/print/Win32PrintService.java b/openjdk/sun/print/Win32PrintService.java index b1667e96..739cacd4 100644 --- a/openjdk/sun/print/Win32PrintService.java +++ b/openjdk/sun/print/Win32PrintService.java @@ -1,6 +1,6 @@ /* Copyright (C) 2009 Volker Berlin (i-net software) - Copyright (C) 2010 Karsten Heinrich (i-net software) + Copyright (C) 2010, 2011 Karsten Heinrich (i-net software) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -55,6 +55,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import javax.print.DocFlavor; import javax.print.DocPrintJob; @@ -77,6 +78,7 @@ import javax.print.attribute.standard.Media; import javax.print.attribute.standard.MediaPrintableArea; import javax.print.attribute.standard.MediaSize; import javax.print.attribute.standard.MediaSizeName; +import javax.print.attribute.standard.MediaTray; import javax.print.attribute.standard.OrientationRequested; import javax.print.attribute.standard.PageRanges; import javax.print.attribute.standard.PrintQuality; @@ -91,21 +93,26 @@ import javax.print.attribute.standard.SheetCollate; import javax.print.attribute.standard.Sides; import javax.print.event.PrintServiceAttributeListener; +import cli.System.NewsStyleUriParser; import cli.System.Type; import cli.System.Collections.IEnumerator; import cli.System.Drawing.RectangleF; import cli.System.Drawing.Printing.Duplex; import cli.System.Drawing.Printing.PaperKind; import cli.System.Drawing.Printing.PaperSize; +import cli.System.Drawing.Printing.PaperSource; import cli.System.Drawing.Printing.PrintDocument; import cli.System.Drawing.Printing.PrinterSettings; import cli.System.Drawing.Printing.PrinterSettings.PaperSizeCollection; +import cli.System.Drawing.Printing.PrinterSettings.PaperSourceCollection; import cli.System.Net.Mime.MediaTypeNames; /** * @author Volker Berlin */ -public class Win32PrintService implements PrintService{ +public class Win32PrintService implements PrintService { + // note: the Win32PrintService is implemented as foreign service (doesn't implement SunPrinterJobService) + // to avoid implementing the WPrinterJob private static final DocFlavor[] supportedFlavors = { DocFlavor.SERVICE_FORMATTED.PAGEABLE, @@ -216,6 +223,8 @@ public class Win32PrintService implements PrintService{ private final PrinterSettings settings; private PrinterName name; + private MediaTray[] mediaTrays; + transient private ServiceNotifier notifier = null; public Win32PrintService(String name, PrintPeer peer){ @@ -483,7 +492,7 @@ public class Win32PrintService implements PrintService{ } if( category == Media.class ){ PaperSizeCollection sizes = settings.get_PaperSizes(); - List<MediaSizeName> medias = new ArrayList<MediaSizeName>(); + List<Media> medias = new ArrayList<Media>(); for( int i = 0; i < sizes.get_Count(); i++ ){ PaperSize media = sizes.get_Item(i); MediaSizeName mediaName = findMatchingMedia( sizes.get_Item(i) ); @@ -492,6 +501,11 @@ public class Win32PrintService implements PrintService{ medias.add( mediaName); } } + // add media trays + MediaTray[] trays = getMediaTrays(); + for( MediaTray tray : trays ){ + medias.add( tray ); + } return medias.size() > 0 ? medias.toArray( new Media[medias.size() ] ) : null; } if (category == PageRanges.class) { @@ -556,6 +570,27 @@ public class Win32PrintService implements PrintService{ } return null; } + + private MediaTray[] getMediaTrays(){ + if( mediaTrays != null ){ + // the print service is a singleton per printer so we only do this once + return mediaTrays; + } + PaperSourceCollection trays = settings.get_PaperSources(); + int count = trays.get_Count(); + List<MediaTray> trayList = new ArrayList<MediaTray>(); + for( int i=0; i < count; i++ ){ + PaperSource tray = trays.get_Item(i); + MediaTray javaTray = getDefaultTray(tray); + if( javaTray != null ){ + trayList.add( javaTray ); + } else { + trayList.add( new NetMediaTray( tray ) ); + } + } + mediaTrays = trayList.toArray( new MediaTray[trayList.size()]); + return mediaTrays; + } @Override @@ -653,31 +688,91 @@ public class Win32PrintService implements PrintService{ return null; } -// /** -// * A simple MediaSizeName implementation. This is required since some programs only query the -// * attributes for MediaSizeName instances - which is not correct, since all {@link Media} implementations -// * are allowed here! Anyways, we have to deal with this an provide the additional formats of .NET as well. -// */ -// private static class CustomMediaSizeName extends MediaSizeName { -// -// private final String name; -// -// /** -// * Creates the instance for a media name -// * @param name the name of the paper format -// */ -// protected CustomMediaSizeName( String name) { -// super(-1); -// this.name = name; -// } -// -// /** -// * Returns the paper format name -// * @return the paper format name -// */ -// @Override -// public String toString() { -// return name; -// } -// } + /** + * Returns the Java-default {@link MediaTray} for a paper source. This is required since these default + * trays are public constants which can be used without checking for the actually present media trays + * @param source the .NET paper source to get the predefined source for + * @return the media tray or null, in case there is no mapping for the paper source + */ + private MediaTray getDefaultTray( PaperSource source ){ + // convert from .NET kind to java's pre defined MediaTrays + switch( source.get_RawKind() ){ + case 1 : return MediaTray.TOP; + case 2 : return MediaTray.BOTTOM; + case 3 : return MediaTray.MIDDLE; + case 4 : return MediaTray.MANUAL; + case 5 : return MediaTray.ENVELOPE; + case 6 : return Win32MediaTray.ENVELOPE_MANUAL; + case 7 : return Win32MediaTray.AUTO; + case 8 : return Win32MediaTray.TRACTOR; + case 9 : return Win32MediaTray.SMALL_FORMAT; + case 10 : return Win32MediaTray.LARGE_FORMAT; + case 11 : return MediaTray.LARGE_CAPACITY; + case 14 : return MediaTray.MAIN; + case 15 : return Win32MediaTray.FORMSOURCE; + // FIXME which PaperSourceKind is MediaTray.SIDE ??? + } + return null; + } + + /** + * Returns the .NET {@link PaperSource} for a media tray. This will be done either by mapping or + * directly in case the tray is a {@link NetMediaTray} + * @param tray the tray to get the paper source for, must not be null + * @return the selected {@link PaperSource} or null, in case there is no matching {@link PaperSource} + */ + public PaperSource getPaperSourceForTray( MediaTray tray ){ + if( tray instanceof NetMediaTray ){ + return ((NetMediaTray)tray).getPaperSource( this ); + } + // try to find the appropriate paper source for the Java-Defined tray + PaperSourceCollection trays = settings.get_PaperSources(); + int count = trays.get_Count(); + for( int i=0; i < count; i++ ){ + PaperSource paperSource = trays.get_Item(i); + if( getDefaultTray( paperSource ) == tray ){ + return paperSource; + } + } + return null; + } + + public static class NetMediaTray extends MediaTray{ + + private static final long serialVersionUID = 1L; + + /** Not really used but required by the EnumSyntax super class */ + private static AtomicInteger idCounter = new AtomicInteger(8); + + private int rawKind; + private String name; + private transient PaperSource netSource; + + public NetMediaTray( PaperSource netSource ) { + super( idCounter.getAndIncrement() ); + this.rawKind = netSource.get_RawKind(); + this.name = netSource.get_SourceName(); + this.netSource = netSource; + } + + public PaperSource getPaperSource( Win32PrintService service ){ + if( netSource == null ){ + PaperSourceCollection sources = service.settings.get_PaperSources(); + int count = sources.get_Count(); + for( int i=0; i < count; i++ ){ + PaperSource source = sources.get_Item(i); + if( source.get_RawKind() == rawKind ){ + netSource = source; + break; + } + } + } + return netSource; + } + + @Override + public String toString() { + return netSource != null ? netSource.get_SourceName() : name; + } + } } |