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