root/dwt/printing/Printer.d

Revision 246:fd9c62a2998e, 17.4 kB (checked in by Frank Benoit <benoit@tionex.de>, 5 months ago)

Updater SWT 3.4M7 to 3.4

Line 
1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module dwt.printing.Printer;
14
15
16 import dwt.DWT;
17 import dwt.DWTError;
18 import dwt.DWTException;
19 import dwt.graphics.Device;
20 import dwt.graphics.DeviceData;
21 import dwt.graphics.Font;
22 import dwt.graphics.GCData;
23 import dwt.graphics.Point;
24 import dwt.graphics.Rectangle;
25 import dwt.internal.win32.OS;
26
27 import dwt.printing.PrinterData;
28
29 import dwt.dwthelper.utils;
30
31 /**
32  * Instances of this class are used to print to a printer.
33  * Applications create a GC on a printer using <code>new GC(printer)</code>
34  * and then draw on the printer GC using the usual graphics calls.
35  * <p>
36  * A <code>Printer</code> object may be constructed by providing
37  * a <code>PrinterData</code> object which identifies the printer.
38  * A <code>PrintDialog</code> presents a print dialog to the user
39  * and returns an initialized instance of <code>PrinterData</code>.
40  * Alternatively, calling <code>new Printer()</code> will construct a
41  * printer object for the user's default printer.
42  * </p><p>
43  * Application code must explicitly invoke the <code>Printer.dispose()</code>
44  * method to release the operating system resources managed by each instance
45  * when those instances are no longer required.
46  * </p>
47  *
48  * @see PrinterData
49  * @see PrintDialog
50  * @see <a href="http://www.eclipse.org/swt/snippets/#printing">Printing snippets</a>
51  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
52  */
53 public final class Printer : Device {
54     /**
55      * the handle to the printer DC
56      * (Warning: This field is platform dependent)
57      * <p>
58      * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
59      * public API. It is marked public only so that it can be shared
60      * within the packages provided by DWT. It is not available on all
61      * platforms and should never be accessed from application code.
62      * </p>
63      */
64     public HANDLE handle;
65
66     /**
67      * the printer data describing this printer
68      */
69     PrinterData data;
70
71     /**
72      * whether or not a GC was created for this printer
73      */
74     bool isGCCreated = false;
75
76     /**
77      * strings used to access the Windows registry
78      */
79     static TCHAR[] profile;
80     static TCHAR[] appName;
81     static TCHAR[] keyName;
82     static this() {
83         profile = StrToTCHARs(0, "PrinterPorts", true); //$NON-NLS-1$
84         appName = StrToTCHARs(0, "windows", true); //$NON-NLS-1$
85         keyName = StrToTCHARs(0, "device", true); //$NON-NLS-1$
86     }
87
88 /**
89  * Returns an array of <code>PrinterData</code> objects
90  * representing all available printers.
91  *
92  * @return the list of available printers
93  */
94 public static PrinterData[] getPrinterList() {
95     int length = 1024;
96     /* Use the character encoding for the default locale */
97     String buf = new String(length);
98     int n = OS.GetProfileString( TCHARsToStr(profile), null, null, buf, length);
99     if (n is 0) return null;
100     String[] deviceNames = new String[](5);
101     int nameCount = 0;
102     int index = 0;
103     for (int i = 0; i < n; i++) {
104         if (buf[i] is 0) {
105             if (nameCount is deviceNames.length) {
106                 String[] newNames = new String[](deviceNames.length + 5);
107                 System.arraycopy(deviceNames, 0, newNames, 0, deviceNames.length);
108                 deviceNames = newNames;
109             }
110             deviceNames[nameCount] = buf[index .. i ].dup;
111             nameCount++;
112             index = i + 1;
113         }
114     }
115     PrinterData printerList[] = new PrinterData[nameCount];
116     for (int p = 0; p < nameCount; p++) {
117         String device = deviceNames[p];
118         String driver = ""; //$NON-NLS-1$
119         if (OS.GetProfileString(TCHARsToStr(profile), device, null, buf, length) > 0) {
120             int commaIndex = 0;
121             while (buf[commaIndex] !is ',' && commaIndex < length) commaIndex++;
122             if (commaIndex < length) {
123                 driver = buf[0 .. commaIndex].dup;
124             }
125         }
126         printerList[p] = new PrinterData(driver, device);
127     }
128     return printerList;
129 }
130
131 /**
132  * Returns a <code>PrinterData</code> object representing
133  * the default printer or <code>null</code> if there is no
134  * printer available on the System.
135  *
136  * @return the default printer data or null
137  *
138  * @since 2.1
139  */
140 public static PrinterData getDefaultPrinterData() {
141     String deviceName = null;
142     int length = 1024;
143     /* Use the character encoding for the default locale */
144     String buf = new String(length);
145     int n = OS.GetProfileString(TCHARsToStr(appName), TCHARsToStr(keyName), null, buf, length);
146     if (n is 0) return null;
147     int commaIndex = 0;
148     while(buf[commaIndex] !is ',' && commaIndex < length) commaIndex++;
149     if (commaIndex < length) {
150         deviceName = buf[0 .. commaIndex].dup;
151     }
152     String driver = ""; //$NON-NLS-1$
153     if (OS.GetProfileString(TCHARsToStr(profile), deviceName, null, buf, length) > 0) {
154         commaIndex = 0;
155         while (buf[commaIndex] !is ',' && commaIndex < length) commaIndex++;
156         if (commaIndex < length) {
157             driver = buf[0 .. commaIndex].dup;
158         }
159     }
160     return new PrinterData(driver, deviceName);
161 }
162
163 static DeviceData checkNull (PrinterData data) {
164     if (data is null) data = new PrinterData();
165     if (data.driver is null || data.name is null) {
166         PrinterData defaultPrinter = getDefaultPrinterData();
167         if (defaultPrinter is null) DWT.error(DWT.ERROR_NO_HANDLES);
168         data.driver = defaultPrinter.driver;
169         data.name = defaultPrinter.name;
170     }
171     return data;
172 }
173
174 /**
175  * Constructs a new printer representing the default printer.
176  * <p>
177  * You must dispose the printer when it is no longer required.
178  * </p>
179  *
180  * @exception DWTError <ul>
181  *    <li>ERROR_NO_HANDLES - if there are no valid printers
182  * </ul>
183  *
184  * @see Device#dispose
185  */
186 public this() {
187     this(null);
188 }
189
190 /**
191  * Constructs a new printer given a <code>PrinterData</code>
192  * object representing the desired printer.
193  * <p>
194  * You must dispose the printer when it is no longer required.
195  * </p>
196  *
197  * @param data the printer data for the specified printer
198  *
199  * @exception IllegalArgumentException <ul>
200  *    <li>ERROR_INVALID_ARGUMENT - if the specified printer data does not represent a valid printer
201  * </ul>
202  * @exception DWTError <ul>
203  *    <li>ERROR_NO_HANDLES - if there are no valid printers
204  * </ul>
205  *
206  * @see Device#dispose
207  */
208 public this(PrinterData data) {
209     super(checkNull(data));
210 }
211
212 /**
213  * Creates the printer handle.
214  * This method is called internally by the instance creation
215  * mechanism of the <code>Device</code> class.
216  * @param deviceData the device data
217  */
218 protected void create(DeviceData deviceData) {
219     data = cast(PrinterData)deviceData;
220     /* Use the character encoding for the default locale */
221     TCHAR[] driver = StrToTCHARs(0, data.driver, true);
222     TCHAR[] device = StrToTCHARs(0, data.name, true);
223     DEVMODE* lpInitData;
224     byte buffer [] = data.otherData;
225     auto hHeap = OS.GetProcessHeap();
226     if (buffer !is null && buffer.length !is 0) {
227         /* If user setup info from a print dialog was specified, restore the DEVMODE struct. */
228         lpInitData = cast(DEVMODE*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, buffer.length);
229         OS.MoveMemory(lpInitData, buffer.ptr, buffer.length);
230     }
231     handle = OS.CreateDC(driver.ptr, device.ptr, null, lpInitData);
232     if (lpInitData !is null) OS.HeapFree(hHeap, 0, lpInitData);
233     if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
234 }
235
236 /**
237  * Invokes platform specific functionality to allocate a new GC handle.
238  * <p>
239  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
240  * API for <code>Printer</code>. It is marked public only so that it
241  * can be shared within the packages provided by DWT. It is not
242  * available on all platforms, and should never be called from
243  * application code.
244  * </p>
245  *
246  * @param data the platform specific GC data
247  * @return the platform specific GC handle
248  */
249 public HDC internal_new_GC(GCData data) {
250     if (handle is null) DWT.error(DWT.ERROR_NO_HANDLES);
251     if (data !is null) {
252         if (isGCCreated) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
253         int mask = DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT;
254         if ((data.style & mask) !is 0) {
255             data.layout = (data.style & DWT.RIGHT_TO_LEFT) !is 0 ? OS.LAYOUT_RTL : 0;
256         } else {
257             data.style |= DWT.LEFT_TO_RIGHT;
258         }
259         data.device = this;
260         data.font = Font.win32_new(this, OS.GetCurrentObject(handle, OS.OBJ_FONT));
261         isGCCreated = true;
262     }
263     return handle;
264 }
265
266 /**
267  * Invokes platform specific functionality to dispose a GC handle.
268  * <p>
269  * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
270  * API for <code>Printer</code>. It is marked public only so that it
271  * can be shared within the packages provided by DWT. It is not
272  * available on all platforms, and should never be called from
273  * application code.
274  * </p>
275  *
276  * @param hDC the platform specific GC handle
277  * @param data the platform specific GC data
278  */
279 public void internal_dispose_GC(HDC hDC, GCData data) {
280     if (data !is null) isGCCreated = false;
281 }
282
283 /**
284  * Starts a print job and returns true if the job started successfully
285  * and false otherwise.
286  * <p>
287  * This must be the first method called to initiate a print job,
288  * followed by any number of startPage/endPage calls, followed by
289  * endJob. Calling startPage, endPage, or endJob before startJob
290  * will result in undefined behavior.
291  * </p>
292  *
293  * @param jobName the name of the print job to start
294  * @return true if the job started successfully and false otherwise.
295  *
296  * @exception DWTException <ul>
297  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
298  * </ul>
299  *
300  * @see #startPage
301  * @see #endPage
302  * @see #endJob
303  */
304 public bool startJob(String jobName) {
305     checkDevice();
306     DOCINFO di;
307     di.cbSize = DOCINFO.sizeof;
308     auto hHeap = OS.GetProcessHeap();
309     TCHAR* lpszDocName;
310     if (jobName !is null && jobName.length !is 0) {
311         /* Use the character encoding for the default locale */
312         TCHAR[] buffer = StrToTCHARs(0, jobName, true);
313         int byteCount = buffer.length * TCHAR.sizeof;
314         lpszDocName = cast(TCHAR*) OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
315         OS.MoveMemory(lpszDocName, buffer.ptr, byteCount);
316         di.lpszDocName = lpszDocName;
317     }
318     TCHAR* lpszOutput;
319     if (data.printToFile && data.fileName !is null) {
320         /* Use the character encoding for the default locale */
321         TCHAR[] buffer = StrToTCHARs(0, data.fileName, true);
322         int byteCount = buffer.length * TCHAR.sizeof;
323         lpszOutput = cast(TCHAR*) OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
324         OS.MoveMemory(lpszOutput, buffer.ptr, byteCount);
325         di.lpszOutput = lpszOutput;
326     }
327     int rc = OS.StartDoc(handle, &di);
328     if (lpszDocName !is null) OS.HeapFree(hHeap, 0, lpszDocName);
329     if (lpszOutput !is null) OS.HeapFree(hHeap, 0, lpszOutput);
330     return rc > 0;
331 }
332
333 /**
334  * Ends the current print job.
335  *
336  * @exception DWTException <ul>
337  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
338  * </ul>
339  *
340  * @see #startJob
341  * @see #startPage
342  * @see #endPage
343  */
344 public void endJob() {
345     checkDevice();
346     OS.EndDoc(handle);
347 }
348
349 /**
350  * Cancels a print job in progress.
351  *
352  * @exception DWTException <ul>
353  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
354  * </ul>
355  */
356 public void cancelJob() {
357     checkDevice();
358     OS.AbortDoc(handle);
359 }
360
361 /**
362  * Starts a page and returns true if the page started successfully
363  * and false otherwise.
364  * <p>
365  * After calling startJob, this method may be called any number of times
366  * along with a matching endPage.
367  * </p>
368  *
369  * @return true if the page started successfully and false otherwise.
370  *
371  * @exception DWTException <ul>
372  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
373  * </ul>
374  *
375  * @see #endPage
376  * @see #startJob
377  * @see #endJob
378  */
379 public bool startPage() {
380     checkDevice();
381     int rc = OS.StartPage(handle);
382     if (rc <= 0) OS.AbortDoc(handle);
383     return rc > 0;
384 }
385
386 /**
387  * Ends the current page.
388  *
389  * @exception DWTException <ul>
390  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
391  * </ul>
392  *
393  * @see #startPage
394  * @see #startJob
395  * @see #endJob
396  */
397 public void endPage() {
398     checkDevice();
399     OS.EndPage(handle);
400 }
401
402 /**
403  * Returns a point whose x coordinate is the horizontal
404  * dots per inch of the printer, and whose y coordinate
405  * is the vertical dots per inch of the printer.
406  *
407  * @return the horizontal and vertical DPI
408  *
409  * @exception DWTException <ul>
410  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
411  * </ul>
412  */
413 public Point getDPI() {
414     checkDevice();
415     int dpiX = OS.GetDeviceCaps(handle, OS.LOGPIXELSX);
416     int dpiY = OS.GetDeviceCaps(handle, OS.LOGPIXELSY);
417     return new Point(dpiX, dpiY);
418 }
419
420 /**
421  * Returns a rectangle describing the receiver's size and location.
422  * <p>
423  * For a printer, this is the size of the physical page, in pixels.
424  * </p>
425  *
426  * @return the bounding rectangle
427  *
428  * @exception DWTException <ul>
429  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
430  * </ul>
431  *
432  * @see #getClientArea
433  * @see #computeTrim
434  */
435 public Rectangle getBounds() {
436     checkDevice();
437     int width = OS.GetDeviceCaps(handle, OS.PHYSICALWIDTH);
438     int height = OS.GetDeviceCaps(handle, OS.PHYSICALHEIGHT);
439     return new Rectangle(0, 0, width, height);
440 }
441
442 /**
443  * Returns a rectangle which describes the area of the
444  * receiver which is capable of displaying data.
445  * <p>
446  * For a printer, this is the size of the printable area
447  * of the page, in pixels.
448  * </p>
449  *
450  * @return the client area
451  *
452  * @exception DWTException <ul>
453  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
454  * </ul>
455  *
456  * @see #getBounds
457  * @see #computeTrim
458  */
459 public Rectangle getClientArea() {
460     checkDevice();
461     int width = OS.GetDeviceCaps(handle, OS.HORZRES);
462     int height = OS.GetDeviceCaps(handle, OS.VERTRES);
463     return new Rectangle(0, 0, width, height);
464 }
465
466 /**
467  * Given a <em>client area</em> (as described by the arguments),
468  * returns a rectangle, relative to the client area's coordinates,
469  * that is the client area expanded by the printer's trim (or minimum margins).
470  * <p>
471  * Most printers have a minimum margin on each edge of the paper where the
472  * printer device is unable to print.  This margin is known as the "trim."
473  * This method can be used to calculate the printer's minimum margins
474  * by passing in a client area of 0, 0, 0, 0 and then using the resulting
475  * x and y coordinates (which will be <= 0) to determine the minimum margins
476  * for the top and left edges of the paper, and the resulting width and height
477  * (offset by the resulting x and y) to determine the minimum margins for the
478  * bottom and right edges of the paper, as follows:
479  * <ul>
480  *      <li>The left trim width is -x pixels</li>
481  *      <li>The top trim height is -y pixels</li>
482  *      <li>The right trim width is (x + width) pixels</li>
483  *      <li>The bottom trim height is (y + height) pixels</li>
484  * </ul>
485  * </p>
486  *
487  * @param x the x coordinate of the client area
488  * @param y the y coordinate of the client area
489  * @param width the width of the client area
490  * @param height the height of the client area
491  * @return a rectangle, relative to the client area's coordinates, that is
492  *      the client area expanded by the printer's trim (or minimum margins)
493  *
494  * @exception DWTException <ul>
495  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
496  * </ul>
497  *
498  * @see #getBounds
499  * @see #getClientArea
500  */
501 public Rectangle computeTrim(int x, int y, int width, int height) {
502     checkDevice();
503     int printX = -OS.GetDeviceCaps(handle, OS.PHYSICALOFFSETX);
504     int printY = -OS.GetDeviceCaps(handle, OS.PHYSICALOFFSETY);
505     int printWidth = OS.GetDeviceCaps(handle, OS.HORZRES);
506     int printHeight = OS.GetDeviceCaps(handle, OS.VERTRES);
507     int paperWidth = OS.GetDeviceCaps(handle, OS.PHYSICALWIDTH);
508     int paperHeight = OS.GetDeviceCaps(handle, OS.PHYSICALHEIGHT);
509     int hTrim = paperWidth - printWidth;
510     int vTrim = paperHeight - printHeight;
511     return new Rectangle(x + printX, y + printY, width + hTrim, height + vTrim);
512 }
513
514 /**
515  * Returns a <code>PrinterData</code> object representing the
516  * target printer for this print job.
517  *
518  * @return a PrinterData object describing the receiver
519  */
520 public PrinterData getPrinterData() {
521     return data;
522 }
523
524 /**
525  * Checks the validity of this device.
526  *
527  * @exception DWTException <ul>
528  *    <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
529  * </ul>
530  */
531 protected void checkDevice() {
532     if (handle is null) DWT.error(DWT.ERROR_DEVICE_DISPOSED);
533 }
534
535 /**
536  * Releases any internal state prior to destroying this printer.
537  * This method is called internally by the dispose
538  * mechanism of the <code>Device</code> class.
539  */
540 protected void release() {
541     super.release();
542     data = null;
543 }
544
545 /**
546  * Destroys the printer handle.
547  * This method is called internally by the dispose
548  * mechanism of the <code>Device</code> class.
549  */
550 protected void destroy() {
551     if (handle !is null) OS.DeleteDC(handle);
552     handle = null;
553 }
554
555 }
Note: See TracBrowser for help on using the browser.