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