Mercurial > projects > dwt-mac
diff dwt/printing/Printer.d @ 45:d8635bb48c7c
Merge with SWT 3.5
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Mon, 01 Dec 2008 17:07:00 +0100 |
parents | db5a898b2119 |
children | cfa563df4fdd |
line wrap: on
line diff
--- a/dwt/printing/Printer.d Tue Oct 21 15:20:04 2008 +0200 +++ b/dwt/printing/Printer.d Mon Dec 01 17:07:00 2008 +0100 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. + * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -20,9 +20,22 @@ import dwt.graphics.GCData; import dwt.graphics.Point; import dwt.graphics.Rectangle; +import dwt.internal.cocoa.NSAffineTransform; import dwt.internal.cocoa.NSArray; +import dwt.internal.cocoa.NSBezierPath; +import dwt.internal.cocoa.NSData; +import dwt.internal.cocoa.NSGraphicsContext; +import dwt.internal.cocoa.NSKeyedUnarchiver; +import dwt.internal.cocoa.NSPoint; +import dwt.internal.cocoa.NSPrintInfo; +import dwt.internal.cocoa.NSPrintOperation; import dwt.internal.cocoa.NSPrinter; +import dwt.internal.cocoa.NSRect; +import dwt.internal.cocoa.NSSize; import dwt.internal.cocoa.NSString; +import dwt.internal.cocoa.NSView; +import dwt.internal.cocoa.NSWindow; +import dwt.internal.cocoa.OS; /** * Instances of this class are used to print to a printer. @@ -43,17 +56,19 @@ * * @see PrinterData * @see PrintDialog + * @see <a href="http://www.eclipse.org/swt/snippets/#printing">Printing snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> */ -public final class Printer : Device { +public final class Printer extends Device { PrinterData data; NSPrinter printer; - bool inPage, isGCCreated; + NSPrintInfo printInfo; + NSPrintOperation operation; + NSView view; + NSWindow window; + bool isGCCreated; static final String DRIVER = "Mac"; - static final String PRINTER_DRIVER = "Printer"; - static final String FILE_DRIVER = "File"; - static final String PREVIEW_DRIVER = "Preview"; - static final String FAX_DRIVER = "Fax"; /** * Returns an array of <code>PrinterData</code> objects @@ -63,13 +78,11 @@ */ public static PrinterData[] getPrinterList() { NSArray printers = NSPrinter.printerNames(); - int count = printers.count(); + int count = (int)/*64*/printers.count(); PrinterData[] result = new PrinterData[count]; for (int i = 0; i < count; i++) { NSString str = new NSString(printers.objectAtIndex(i)); - char[] buffer = new char[str.length()]; - str.getCharacters_(buffer); - result[i] = new PrinterData(DRIVER, new String(buffer)); + result[i] = new PrinterData(DRIVER, str.getString()); } return result; } @@ -84,43 +97,12 @@ * @since 2.1 */ public static PrinterData getDefaultPrinterData() { - //TODO - get default - PrinterData[] printers = getPrinterList(); - if (printers.length > 0) return printers[0]; - return null; + NSPrinter printer = NSPrintInfo.defaultPrinter(); + if (printer is null) return null; + NSString str = printer.name(); + return new PrinterData(DRIVER, str.getString()); + } -//static int packData(int handle, byte[] buffer, int offset) { -// int length = OS.GetHandleSize (handle); -// buffer[offset++] = cast(byte)((length & 0xFF) >> 0); -// buffer[offset++] = cast(byte)((length & 0xFF00) >> 8); -// buffer[offset++] = cast(byte)((length & 0xFF0000) >> 16); -// buffer[offset++] = cast(byte)((length & 0xFF000000) >> 24); -// int [] ptr = new int [1]; -// OS.HLock(handle); -// OS.memmove(ptr, handle, 4); -// byte[] buffer1 = new byte[length]; -// OS.memmove(buffer1, ptr [0], length); -// OS.HUnlock(handle); -// System.arraycopy(buffer1, 0, buffer, offset, length); -// return offset + length; -//} -//static int unpackData(int[] handle, byte[] buffer, int offset) { -// int length = -// ((buffer[offset++] & 0xFF) << 0) | -// ((buffer[offset++] & 0xFF) << 8) | -// ((buffer[offset++] & 0xFF) << 16) | -// ((buffer[offset++] & 0xFF) << 24); -// handle[0] = OS.NewHandle(length); -// if (handle[0] is 0) DWT.error(DWT.ERROR_NO_HANDLES); -// int[] ptr = new int[1]; -// OS.HLock(handle[0]); -// OS.memmove(ptr, handle[0], 4); -// byte[] buffer1 = new byte[length]; -// System.arraycopy(buffer, offset, buffer1, 0, length); -// OS.memmove(ptr[0], buffer1, length); -// OS.HUnlock(handle[0]); -// return offset + length; -//} /** * Constructs a new printer representing the default printer. @@ -134,7 +116,7 @@ * * @see Device#dispose */ -public this() { +public Printer() { this(null); } @@ -156,33 +138,37 @@ * * @see Device#dispose */ -public this(PrinterData data) { +public Printer(PrinterData data) { super (checkNull(data)); } /** - * Given a desired <em>client area</em> for the receiver - * (as described by the arguments), returns the bounding - * rectangle which would be required to produce that client - * area. + * Given a <em>client area</em> (as described by the arguments), + * returns a rectangle, relative to the client area's coordinates, + * that is the client area expanded by the printer's trim (or minimum margins). * <p> - * In other words, it returns a rectangle such that, if the - * receiver's bounds were set to that rectangle, the area - * of the receiver which is capable of displaying data - * (that is, not covered by the "trimmings") would be the - * rectangle described by the arguments (relative to the - * receiver's parent). - * </p><p> - * Note that there is no setBounds for a printer. This method - * is usually used by passing in the client area (the 'printable - * area') of the printer. It can also be useful to pass in 0, 0, 0, 0. + * Most printers have a minimum margin on each edge of the paper where the + * printer device is unable to print. This margin is known as the "trim." + * This method can be used to calculate the printer's minimum margins + * by passing in a client area of 0, 0, 0, 0 and then using the resulting + * x and y coordinates (which will be <= 0) to determine the minimum margins + * for the top and left edges of the paper, and the resulting width and height + * (offset by the resulting x and y) to determine the minimum margins for the + * bottom and right edges of the paper, as follows: + * <ul> + * <li>The left trim width is -x pixels</li> + * <li>The top trim height is -y pixels</li> + * <li>The right trim width is (x + width) pixels</li> + * <li>The bottom trim height is (y + height) pixels</li> + * </ul> * </p> * - * @param x the desired x coordinate of the client area - * @param y the desired y coordinate of the client area - * @param width the desired width of the client area - * @param height the desired height of the client area - * @return the required bounds to produce the given client area + * @param x the x coordinate of the client area + * @param y the y coordinate of the client area + * @param width the width of the client area + * @param height the height of the client area + * @return a rectangle, relative to the client area's coordinates, that is + * the client area expanded by the printer's trim (or minimum margins) * * @exception DWTException <ul> * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li> @@ -193,12 +179,14 @@ */ public Rectangle computeTrim(int x, int y, int width, int height) { checkDevice(); -// PMRect pageRect = new PMRect(); -// PMRect paperRect = new PMRect(); -// OS.PMGetAdjustedPageRect(pageFormat, pageRect); -// OS.PMGetAdjustedPaperRect(pageFormat, paperRect); -// return new Rectangle(x+cast(int)paperRect.left, y+cast(int)paperRect.top, width+cast(int)(paperRect.right-pageRect.right), height+cast(int)(paperRect.bottom-pageRect.bottom)); - return null; + NSSize paperSize = printInfo.paperSize(); + NSRect bounds = printInfo.imageablePageBounds(); + Point dpi = getDPI (), screenDPI = getIndependentDPI(); + x -= (bounds.x * dpi.x / screenDPI.x); + y -= (bounds.y * dpi.y / screenDPI.y); + width += (paperSize.width - bounds.width) * dpi.x / screenDPI.x; + height += (paperSize.height - bounds.height) * dpi.y / screenDPI.y; + return new Rectangle(x, y, width, height); } /** @@ -208,65 +196,37 @@ * @param deviceData the device data */ protected void create(DeviceData deviceData) { - data = cast(PrinterData)deviceData; - - printer = NSPrinter.static_printerWithName_(NSString.stringWith(data.name)); - printer.retain(); - -// int[] buffer = new int[1]; -// if (OS.PMCreateSession(buffer) !is OS.noErr) DWT.error(DWT.ERROR_NO_HANDLES); -// printSession = buffer[0]; -// if (printSession is 0) DWT.error(DWT.ERROR_NO_HANDLES); -// -// if (data.otherData !is null) { -// /* Deserialize settings */ -// int offset = 0; -// byte[] otherData = data.otherData; -// offset = unpackData(buffer, otherData, offset); -// int flatSettings = buffer[0]; -// offset = unpackData(buffer, otherData, offset); -// int flatFormat = buffer[0]; -// if (OS.PMUnflattenPrintSettings(flatSettings, buffer) !is OS.noErr) DWT.error(DWT.ERROR_NO_HANDLES); -// printSettings = buffer[0]; -// if (printSettings is 0) DWT.error(DWT.ERROR_NO_HANDLES); -// if (OS.PMUnflattenPageFormat(flatFormat, buffer) !is OS.noErr) DWT.error(DWT.ERROR_NO_HANDLES); -// pageFormat = buffer[0]; -// if (pageFormat is 0) DWT.error(DWT.ERROR_NO_HANDLES); -// OS.DisposeHandle(flatSettings); -// OS.DisposeHandle(flatFormat); -// } else { -// /* Create default settings */ -// if (OS.PMCreatePrintSettings(buffer) !is OS.noErr) DWT.error(DWT.ERROR_NO_HANDLES); -// printSettings = buffer[0]; -// if (printSettings is 0) DWT.error(DWT.ERROR_NO_HANDLES); -// OS.PMSessionDefaultPrintSettings(printSession, printSettings); -// if (OS.PMCreatePageFormat(buffer) !is OS.noErr) DWT.error(DWT.ERROR_NO_HANDLES); -// pageFormat = buffer[0]; -// if (pageFormat is 0) DWT.error(DWT.ERROR_NO_HANDLES); -// OS.PMSessionDefaultPageFormat(printSession, pageFormat); -// } -// -// if (PREVIEW_DRIVER.equals(data.driver)) { -// OS.PMSessionSetDestination(printSession, printSettings, cast(short) OS.kPMDestinationPreview, 0, 0); -// } -// String name = data.name; -// char[] buffer1 = new char[name.length ()]; -// name.getChars(0, buffer1.length, buffer1, 0); -// int ptr = OS.CFStringCreateWithCharacters(OS.kCFAllocatorDefault, buffer1, buffer1.length); -// if (ptr !is 0) { -// OS.PMSessionSetCurrentPrinter(printSession, ptr); -// OS.CFRelease(ptr); -// } -// -// OS.PMSessionValidatePrintSettings(printSession, printSettings, null); -// OS.PMSessionValidatePageFormat(printSession, pageFormat, null); -// -// int graphicsContextsArray = OS.CFArrayCreateMutable(OS.kCFAllocatorDefault, 1, 0); -// if (graphicsContextsArray !is 0) { -// OS.CFArrayAppendValue(graphicsContextsArray, OS.kPMGraphicsContextCoreGraphics()); -// OS.PMSessionSetDocumentFormatGeneration(printSession, OS.kPMDocumentFormatPDF(), graphicsContextsArray, 0); -// OS.CFRelease(graphicsContextsArray); -// } + data = (PrinterData)deviceData; + if (data.otherData !is null) { + NSData nsData = NSData.dataWithBytes(data.otherData, data.otherData.length); + printInfo = new NSPrintInfo(NSKeyedUnarchiver.unarchiveObjectWithData(nsData).id); + } else { + printInfo = NSPrintInfo.sharedPrintInfo(); + } + printInfo.retain(); + printer = NSPrinter.printerWithName(NSString.stringWith(data.name)); + if (printer !is null) { + printer.retain(); + printInfo.setPrinter(printer); + } + /* + * Bug in Cocoa. For some reason, the output still goes to the printer when + * the user chooses the preview button. The fix is to reset the job disposition. + */ + NSString job = printInfo.jobDisposition(); + if (job.isEqual(new NSString(OS.NSPrintPreviewJob()))) { + printInfo.setJobDisposition(job); + } + NSRect rect = new NSRect(); + window = (NSWindow)new NSWindow().alloc(); + window.initWithContentRect(rect, OS.NSBorderlessWindowMask, OS.NSBackingStoreBuffered, false); + view = (NSView)new NSView().alloc(); + view.initWithFrame(rect); + window.setContentView(view); + operation = NSPrintOperation.printOperationWithView(view, printInfo); + operation.retain(); + operation.setShowsPrintPanel(false); + operation.setShowsProgressPanel(false); } /** @@ -276,7 +236,14 @@ */ protected void destroy() { if (printer !is null) printer.release(); + if (printInfo !is null) printInfo.release(); + if (view !is null) view.release(); + if (window !is null) window.release(); + if (operation !is null) operation.release(); printer = null; + printInfo = null; + view = null; + operation = null; } /** @@ -292,31 +259,22 @@ * @param data the platform specific GC data * @return the platform specific GC handle */ -public int internal_new_GC(GCData data) { +public int /*long*/ internal_new_GC(GCData data) { if (isDisposed()) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED); - setupNewPage(); -// if (data !is null) { -// if (isGCCreated) DWT.error(DWT.ERROR_INVALID_ARGUMENT); -// data.device = this; -// data.background = getSystemColor(DWT.COLOR_WHITE).handle; -// data.foreground = getSystemColor(DWT.COLOR_BLACK).handle; -// data.font = getSystemFont (); -// PMRect paperRect= new PMRect(); -// OS.PMGetAdjustedPaperRect(pageFormat, paperRect); -// Rect portRect = new Rect(); -// portRect.left = cast(short)paperRect.left; -// portRect.right = cast(short)paperRect.right; -// portRect.top = cast(short)paperRect.top; -// portRect.bottom = cast(short)paperRect.bottom; -// data.portRect = portRect; -// isGCCreated = true; -// } -// return context; - return 0; + if (data !is null) { + if (isGCCreated) DWT.error(DWT.ERROR_INVALID_ARGUMENT); + data.device = this; + data.background = getSystemColor(DWT.COLOR_WHITE).handle; + data.foreground = getSystemColor(DWT.COLOR_BLACK).handle; + data.font = getSystemFont (); + data.size = printInfo.paperSize(); + isGCCreated = true; + } + return operation.context().id; } -protected void init_ () { - super.init_(); +protected void init () { + super.init(); } /** @@ -332,7 +290,7 @@ * @param hDC the platform specific GC handle * @param data the platform specific GC data */ -public void internal_dispose_GC(int context, GCData data) { +public void internal_dispose_GC(int /*long*/ context, GCData data) { if (data !is null) isGCCreated = false; } @@ -368,16 +326,16 @@ */ public bool startJob(String jobName) { checkDevice(); -// if (jobName !is null && jobName.length() !is 0) { -// char[] buffer = new char[jobName.length ()]; -// jobName.getChars(0, buffer.length, buffer, 0); -// int ptr = OS.CFStringCreateWithCharacters(OS.kCFAllocatorDefault, buffer, buffer.length); -// if (ptr !is 0) { -// OS.PMSetJobNameCFString(printSettings, ptr); -// OS.CFRelease (ptr); -// } -// } -// return OS.PMSessionBeginDocumentNoDialog(printSession, printSettings, pageFormat) is OS.noErr; + if (jobName !is null && jobName.length() !is 0) { + operation.setJobTitle(NSString.stringWith(jobName)); + } + printInfo.setUpPrintOperationDefaultValues(); + NSPrintOperation.setCurrentOperation(operation); + NSGraphicsContext context = operation.createContext(); + if (context !is null) { + view.beginDocument(); + return true; + } return false; } @@ -394,12 +352,10 @@ */ public void endJob() { checkDevice(); -// if (inPage) { -// OS.PMSessionEndPageNoDialog(printSession); -// inPage = false; -// } -// OS.PMSessionEndDocumentNoDialog(printSession); -// context = 0; + view.endDocument(); + operation.deliverResult(); + operation.destroyContext(); + operation.cleanUpOperation(); } /** @@ -411,13 +367,8 @@ */ public void cancelJob() { checkDevice(); -// OS.PMSessionSetError(printSession, OS.kPMCancel); -// if (inPage) { -// OS.PMSessionEndPageNoDialog(printSession); -// inPage = false; -// } -// OS.PMSessionEndDocumentNoDialog(printSession); -// context = 0; + operation.destroyContext(); + operation.cleanUpOperation(); } static DeviceData checkNull (PrinterData data) { @@ -451,10 +402,20 @@ */ public bool startPage() { checkDevice(); -// if (OS.PMSessionError(printSession) !is OS.noErr) return false; -// setupNewPage(); -// return context !is 0; - return false; + NSSize paperSize = printInfo.paperSize(); + NSRect rect = new NSRect(); + rect.width = paperSize.width; + rect.height = paperSize.height; + view.beginPageInRect(rect, new NSPoint()); + NSRect imageBounds = printInfo.imageablePageBounds(); + NSBezierPath.bezierPathWithRect(imageBounds).setClip(); + NSAffineTransform transform = NSAffineTransform.transform(); + transform.translateXBy(imageBounds.x, rect.height - imageBounds.y); + transform.scaleXBy(1, -1); + Point dpi = getDPI (), screenDPI = getIndependentDPI(); + transform.scaleXBy(screenDPI.x / (float)dpi.x, screenDPI.y / (float)dpi.y); + transform.concat(); + return true; } /** @@ -470,10 +431,7 @@ */ public void endPage() { checkDevice(); -// if (inPage) { -// OS.PMSessionEndPageNoDialog(printSession); -// inPage = false; -// } + view.endPage(); } /** @@ -489,15 +447,19 @@ */ public Point getDPI() { checkDevice(); -// PMResolution resolution = new PMResolution(); -// OS.PMGetResolution(pageFormat, resolution); -// return new Point(cast(int)resolution.hRes, cast(int)resolution.vRes); - return null; + //TODO get output resolution + return getIndependentDPI(); +} + +Point getIndependentDPI() { + return super.getDPI(); } /** * Returns a rectangle describing the receiver's size and location. - * For a printer, this is the size of a physical page, in pixels. + * <p> + * For a printer, this is the size of the physical page, in pixels. + * </p> * * @return the bounding rectangle * @@ -510,17 +472,18 @@ */ public Rectangle getBounds() { checkDevice(); -// PMRect paperRect = new PMRect(); -// OS.PMGetAdjustedPaperRect(pageFormat, paperRect); -// return new Rectangle(0, 0, cast(int)(paperRect.right-paperRect.left), cast(int)(paperRect.bottom-paperRect.top)); - return null; + NSSize size = printInfo.paperSize(); + Point dpi = getDPI (), screenDPI = getIndependentDPI(); + return new Rectangle (0, 0, (int)(size.width * dpi.x / screenDPI.x), (int)(size.height * dpi.y / screenDPI.y)); } /** * Returns a rectangle which describes the area of the * receiver which is capable of displaying data. + * <p> * For a printer, this is the size of the printable area - * of a page, in pixels. + * of the page, in pixels. + * </p> * * @return the client area * @@ -533,10 +496,9 @@ */ public Rectangle getClientArea() { checkDevice(); -// PMRect pageRect = new PMRect(); -// OS.PMGetAdjustedPageRect(pageFormat, pageRect); -// return new Rectangle(0, 0, cast(int)(pageRect.right-pageRect.left), cast(int)(pageRect.bottom-pageRect.top)); - return null; + NSRect rect = printInfo.imageablePageBounds(); + Point dpi = getDPI (), screenDPI = getIndependentDPI(); + return new Rectangle(0, 0, (int)(rect.width * dpi.x / screenDPI.x), (int)(rect.height * dpi.y / screenDPI.y)); } /** @@ -549,61 +511,4 @@ checkDevice(); return data; } - -/** - * On the Mac the core graphics context for printing is only valid between PMSessionBeginPage and PMSessionEndPage, - * so printing code has to retrieve and initializes a graphic context for every page like this: - * - * <pre> - * PMSessionBeginDocument - * PMSessionBeginPage - * PMSessionGetGraphicsContext - * // ... use context - * PMSessionEndPage - * PMSessionEndDocument - * </pre> - * - * In DWT it is OK to create a GC once between startJob / endJob and use it for all pages in between: - * - * <pre> - * startJob(...); - * GC gc= new GC(printer); - * startPage(); - * // ... use gc - * endPage(); - * gc.dispose(); - * endJob(); - * </pre> - * - * The solution to resolve this difference is to rely on the fact that Mac OS X returns the same but - * reinitialized graphics context for every page. So we only have to account for the fact that DWT assumes - * that the graphics context keeps it settings across a page break when it actually does not. - * So we have to copy some settings that exist in the CGC before a PMSessionEndPage to the CGC after a PMSessionBeginPage. - * <p> - * In addition to this we have to cope with the situation that in DWT we can create a GC before a call to - * PMSessionBeginPage. For this we decouple the call to PMSessionBeginPage from - * DWT's method startPage as follows: if a new GC is created before a call to startPage, internal_new_GC - * does the PMSessionBeginPage and the next following startPage does nothing. - * </p> - */ -void setupNewPage() { -// if (!inPage) { -// inPage= true; -// OS.PMSessionBeginPageNoDialog(printSession, pageFormat, null); -// int[] buffer = new int[1]; -// OS.PMSessionGetGraphicsContext(printSession, 0, buffer); -// if (context is 0) { -// context = buffer[0]; -// } else { -// if (context !is buffer[0]) DWT.error(DWT.ERROR_UNSPECIFIED); -// } -// PMRect paperRect= new PMRect(); -// OS.PMGetAdjustedPaperRect(pageFormat, paperRect); -// OS.CGContextScaleCTM(context, 1, -1); -// OS.CGContextTranslateCTM(context, 0, -cast(float)(paperRect.bottom-paperRect.top)); -// OS.CGContextSetStrokeColorSpace(context, colorspace); -// OS.CGContextSetFillColorSpace(context, colorspace); -// } } - -}