]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/printing/PrintDialog.java
Remove invalid SHA-256-Digests
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / printing / PrintDialog.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2014 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.internal.win32.*;
19 import org.eclipse.swt.widgets.*;
20
21 /**
22  * Instances of this class allow the user to select
23  * a printer and various print-related parameters
24  * prior to starting a print job.
25  * <p>
26  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
27  * </p>
28  *
29  * @see <a href="http://www.eclipse.org/swt/snippets/#printing">Printing snippets</a>
30  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample, Dialog tab</a>
31  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
32  * @noextend This class is not intended to be subclassed by clients.
33  */
34 public class PrintDialog extends Dialog {
35         static final TCHAR DialogClass = new TCHAR (0, "#32770", true);
36         PrinterData printerData = new PrinterData();
37
38 /**
39  * Constructs a new instance of this class given only its parent.
40  *
41  * @param parent a composite control which will be the parent of the new instance (cannot be null)
42  *
43  * @exception IllegalArgumentException <ul>
44  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
45  * </ul>
46  * @exception SWTException <ul>
47  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
48  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
49  * </ul>
50  *
51  * @see SWT
52  * @see Widget#checkSubclass
53  * @see Widget#getStyle
54  */
55 public PrintDialog (Shell parent) {
56         this (parent, SWT.PRIMARY_MODAL);
57 }
58
59 /**
60  * Constructs a new instance of this class given its parent
61  * and a style value describing its behavior and appearance.
62  * <p>
63  * The style value is either one of the style constants defined in
64  * class <code>SWT</code> which is applicable to instances of this
65  * class, or must be built by <em>bitwise OR</em>'ing together
66  * (that is, using the <code>int</code> "|" operator) two or more
67  * of those <code>SWT</code> style constants. The class description
68  * lists the style constants that are applicable to the class.
69  * Style bits are also inherited from superclasses.
70  * </p>
71  *
72  * @param parent a composite control which will be the parent of the new instance (cannot be null)
73  * @param style the style of control to construct
74  *
75  * @exception IllegalArgumentException <ul>
76  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
77  * </ul>
78  * @exception SWTException <ul>
79  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
80  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
81  * </ul>
82  *
83  * @see SWT
84  * @see Widget#checkSubclass
85  * @see Widget#getStyle
86  */
87 public PrintDialog (Shell parent, int style) {
88         super (parent, checkStyle(parent, style));
89         checkSubclass ();
90 }
91
92 static int checkBits (int style, int int0, int int1, int int2, int int3, int int4, int int5) {
93         int mask = int0 | int1 | int2 | int3 | int4 | int5;
94         if ((style & mask) == 0) style |= int0;
95         if ((style & int0) != 0) style = (style & ~mask) | int0;
96         if ((style & int1) != 0) style = (style & ~mask) | int1;
97         if ((style & int2) != 0) style = (style & ~mask) | int2;
98         if ((style & int3) != 0) style = (style & ~mask) | int3;
99         if ((style & int4) != 0) style = (style & ~mask) | int4;
100         if ((style & int5) != 0) style = (style & ~mask) | int5;
101         return style;
102 }
103
104 static int checkStyle (Shell parent, int style) {
105         int mask = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL;
106         if ((style & SWT.SHEET) != 0) {
107                 style &= ~SWT.SHEET;
108                 if ((style & mask) == 0) {
109                         style |= parent == null ? SWT.APPLICATION_MODAL : SWT.PRIMARY_MODAL;
110                 }
111         }
112         if ((style & mask) == 0) {
113                 style |= SWT.APPLICATION_MODAL;
114         }
115         style &= ~SWT.MIRRORED;
116         if ((style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT)) == 0) {
117                 if (parent != null) {
118                         if ((parent.getStyle () & SWT.LEFT_TO_RIGHT) != 0) style |= SWT.LEFT_TO_RIGHT;
119                         if ((parent.getStyle () & SWT.RIGHT_TO_LEFT) != 0) style |= SWT.RIGHT_TO_LEFT;
120                 }
121         }
122         return checkBits (style, SWT.LEFT_TO_RIGHT, SWT.RIGHT_TO_LEFT, 0, 0, 0, 0);
123 }
124
125 /**
126  * Sets the printer data that will be used when the dialog
127  * is opened.
128  * <p>
129  * Setting the printer data to null is equivalent to
130  * resetting all data fields to their default values.
131  * </p>
132  *
133  * @param data the data that will be used when the dialog is opened or null to use default data
134  *
135  * @since 3.4
136  */
137 public void setPrinterData(PrinterData data) {
138         if (data == null) data = new PrinterData();
139         this.printerData = data;
140 }
141
142 /**
143  * Returns the printer data that will be used when the dialog
144  * is opened.
145  *
146  * @return the data that will be used when the dialog is opened
147  *
148  * @since 3.4
149  */
150 public PrinterData getPrinterData() {
151         return printerData;
152 }
153
154 /**
155  * Returns the print job scope that the user selected
156  * before pressing OK in the dialog. This will be one
157  * of the following values:
158  * <dl>
159  * <dt><code>PrinterData.ALL_PAGES</code></dt>
160  * <dd>Print all pages in the current document</dd>
161  * <dt><code>PrinterData.PAGE_RANGE</code></dt>
162  * <dd>Print the range of pages specified by startPage and endPage</dd>
163  * <dt><code>PrinterData.SELECTION</code></dt>
164  * <dd>Print the current selection</dd>
165  * </dl>
166  *
167  * @return the scope setting that the user selected
168  */
169 public int getScope() {
170         return printerData.scope;
171 }
172
173 /**
174  * Sets the scope of the print job. The user will see this
175  * setting when the dialog is opened. This can have one of
176  * the following values:
177  * <dl>
178  * <dt><code>PrinterData.ALL_PAGES</code></dt>
179  * <dd>Print all pages in the current document</dd>
180  * <dt><code>PrinterData.PAGE_RANGE</code></dt>
181  * <dd>Print the range of pages specified by startPage and endPage</dd>
182  * <dt><code>PrinterData.SELECTION</code></dt>
183  * <dd>Print the current selection</dd>
184  * </dl>
185  *
186  * @param scope the scope setting when the dialog is opened
187  */
188 public void setScope(int scope) {
189         printerData.scope = scope;
190 }
191
192 /**
193  * Returns the start page setting that the user selected
194  * before pressing OK in the dialog.
195  * <p>
196  * This value can be from 1 to the maximum number of pages for the platform.
197  * Note that it is only valid if the scope is <code>PrinterData.PAGE_RANGE</code>.
198  * </p>
199  *
200  * @return the start page setting that the user selected
201  */
202 public int getStartPage() {
203         return printerData.startPage;
204 }
205
206 /**
207  * Sets the start page that the user will see when the dialog
208  * is opened.
209  * <p>
210  * This value can be from 1 to the maximum number of pages for the platform.
211  * Note that it is only valid if the scope is <code>PrinterData.PAGE_RANGE</code>.
212  * </p>
213  *
214  * @param startPage the startPage setting when the dialog is opened
215  */
216 public void setStartPage(int startPage) {
217         printerData.startPage = startPage;
218 }
219
220 /**
221  * Returns the end page setting that the user selected
222  * before pressing OK in the dialog.
223  * <p>
224  * This value can be from 1 to the maximum number of pages for the platform.
225  * Note that it is only valid if the scope is <code>PrinterData.PAGE_RANGE</code>.
226  * </p>
227  *
228  * @return the end page setting that the user selected
229  */
230 public int getEndPage() {
231         return printerData.endPage;
232 }
233
234 /**
235  * Sets the end page that the user will see when the dialog
236  * is opened.
237  * <p>
238  * This value can be from 1 to the maximum number of pages for the platform.
239  * Note that it is only valid if the scope is <code>PrinterData.PAGE_RANGE</code>.
240  * </p>
241  *
242  * @param endPage the end page setting when the dialog is opened
243  */
244 public void setEndPage(int endPage) {
245         printerData.endPage = endPage;
246 }
247
248 /**
249  * Returns the 'Print to file' setting that the user selected
250  * before pressing OK in the dialog.
251  *
252  * @return the 'Print to file' setting that the user selected
253  */
254 public boolean getPrintToFile() {
255         return printerData.printToFile;
256 }
257
258 /**
259  * Sets the 'Print to file' setting that the user will see
260  * when the dialog is opened.
261  *
262  * @param printToFile the 'Print to file' setting when the dialog is opened
263  */
264 public void setPrintToFile(boolean printToFile) {
265         printerData.printToFile = printToFile;
266 }
267
268 @Override
269 protected void checkSubclass() {
270         String name = getClass().getName();
271         String validName = PrintDialog.class.getName();
272         if (!validName.equals(name)) {
273                 SWT.error(SWT.ERROR_INVALID_SUBCLASS);
274         }
275 }
276
277 /**
278  * Makes the receiver visible and brings it to the front
279  * of the display.
280  *
281  * @return a printer data object describing the desired print job parameters,
282  *         or null if the dialog was canceled, no printers were found, or an error occurred
283  *
284  * @exception SWTException <ul>
285  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
286  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
287  * </ul>
288  */
289 public PrinterData open() {
290         /* Get the owner HWND for the dialog */
291         Control parent = getParent();
292         int style = getStyle();
293         long hwndOwner = parent.handle;
294         long hwndParent = parent.handle;
295
296         /*
297         * Feature in Windows.  There is no API to set the BIDI orientation
298         * of a print dialog.  It is always inherited from the parent.  The fix
299         * is to create a hidden parent and set the orientation in the hidden
300         * parent for the dialog to inherit.
301         */
302         boolean enabled = false;
303         int dialogOrientation = style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
304         int parentOrientation = parent.getStyle() & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
305         if (dialogOrientation != parentOrientation) {
306                 int exStyle = OS.WS_EX_NOINHERITLAYOUT;
307                 if (dialogOrientation == SWT.RIGHT_TO_LEFT) exStyle |= OS.WS_EX_LAYOUTRTL;
308                 hwndOwner = OS.CreateWindowEx (
309                         exStyle,
310                         DialogClass,
311                         null,
312                         0,
313                         OS.CW_USEDEFAULT, 0, OS.CW_USEDEFAULT, 0,
314                         hwndParent,
315                         0,
316                         OS.GetModuleHandle (null),
317                         null);
318                 enabled = OS.IsWindowEnabled (hwndParent);
319                 if (enabled) OS.EnableWindow (hwndParent, false);
320         }
321
322         PrinterData data = null;
323         PRINTDLG pd = new PRINTDLG();
324         pd.lStructSize = PRINTDLG.sizeof;
325         pd.hwndOwner = hwndOwner;
326
327         boolean success = false;
328         if (printerData.name != null) {
329                 /* Ensure that the printer name is in the current list of printers. */
330                 PrinterData printerList[] = Printer.getPrinterList();
331                 if (printerList.length > 0) {
332                         for (int p = 0; p < printerList.length; p++) {
333                                 if (printerList[p].name.equals(printerData.name)) {
334                                         success = true;
335                                         break;
336                                 }
337                         }
338                 }
339                 if (success) {
340                         /* Initialize PRINTDLG DEVNAMES for the specified printer. */
341                         TCHAR buffer = new TCHAR(0, printerData.name, true);
342                         int size = buffer.length() * TCHAR.sizeof;
343                         short[] offsets = new short[4]; // DEVNAMES (4 offsets)
344                         int offsetsSize = offsets.length * 2; // 2 bytes each
345                         offsets[1] = (short) offsets.length; // offset 1 points to wDeviceOffset
346                         long hMem = OS.GlobalAlloc(OS.GMEM_MOVEABLE | OS.GMEM_ZEROINIT, offsetsSize + size);
347                         long ptr = OS.GlobalLock(hMem);
348                         OS.MoveMemory(ptr, offsets, offsetsSize);
349                         OS.MoveMemory(ptr + offsetsSize, buffer, size);
350                         OS.GlobalUnlock(hMem);
351                         pd.hDevNames = hMem;
352                 }
353         }
354         Display display = parent.getDisplay();
355         String externalLoopKey = "org.eclipse.swt.internal.win32.externalEventLoop";
356         if (!success) {
357                 /* Initialize PRINTDLG fields, including DEVMODE, for the default printer. */
358                 pd.Flags = OS.PD_RETURNDEFAULT;
359                 display.setData(externalLoopKey, Boolean.TRUE);
360                 display.sendPreExternalEventDispatchEvent ();
361                 success = OS.PrintDlg(pd);
362                 display.setData(externalLoopKey, Boolean.FALSE);
363                 display.sendPostExternalEventDispatchEvent ();
364                 if (success) {
365                         if (pd.hDevNames != 0) {
366                                 OS.GlobalFree(pd.hDevNames);
367                                 pd.hDevNames = 0;
368                         }
369                 }
370         }
371
372         if (success) {
373                 /*
374                  * If user setup info from a previous print dialog was specified,
375                  * then restore the previous DEVMODE struct.
376                  */
377                 byte devmodeData [] = printerData.otherData;
378                 if (devmodeData != null && devmodeData.length != 0) {
379                         long hMem = OS.GlobalAlloc(OS.GMEM_MOVEABLE | OS.GMEM_ZEROINIT, devmodeData.length);
380                         long ptr = OS.GlobalLock(hMem);
381                         OS.MoveMemory(ptr, devmodeData, devmodeData.length);
382                         OS.GlobalUnlock(hMem);
383                         if (pd.hDevMode != 0) OS.GlobalFree(pd.hDevMode);
384                         pd.hDevMode = hMem;
385                 }
386
387                 /* Initialize the DEVMODE struct's fields from the printerData. */
388                 long hMem = pd.hDevMode;
389                 if (hMem == 0) {
390                         hMem = OS.GlobalAlloc(OS.GMEM_MOVEABLE | OS.GMEM_ZEROINIT, DEVMODE.sizeof);
391                         pd.hDevMode = hMem;
392                 }
393                 long ptr = OS.GlobalLock(hMem);
394                 DEVMODE devmode = new DEVMODE ();
395                 OS.MoveMemory(devmode, ptr, DEVMODE.sizeof);
396                 if (printerData.name != null) {
397                         /* Copy PRINTDLG DEVNAMES into DEVMODE dmDeviceName (truncate if necessary). */
398                         int max = Math.min(printerData.name.length(), OS.CCHDEVICENAME - 1);
399                         for (int i = 0; i < max; i++) {
400                                 devmode.dmDeviceName[i] = printerData.name.charAt(i);
401                         }
402                 }
403                 devmode.dmFields |= OS.DM_ORIENTATION;
404                 devmode.dmOrientation = printerData.orientation == PrinterData.PORTRAIT ? OS.DMORIENT_PORTRAIT : OS.DMORIENT_LANDSCAPE;
405                 if (printerData.copyCount != 1) {
406                         devmode.dmFields |= OS.DM_COPIES;
407                         devmode.dmCopies = (short)printerData.copyCount;
408                 }
409                 if (printerData.collate != false) {
410                         devmode.dmFields |= OS.DM_COLLATE;
411                         devmode.dmCollate = OS.DMCOLLATE_TRUE;
412                 }
413                 if (printerData.duplex != SWT.DEFAULT) {
414                         devmode.dmFields |= OS.DM_DUPLEX;
415                         switch (printerData.duplex) {
416                                 case PrinterData.DUPLEX_SHORT_EDGE: devmode.dmDuplex = OS.DMDUP_HORIZONTAL; break;
417                                 case PrinterData.DUPLEX_LONG_EDGE: devmode.dmDuplex = OS.DMDUP_VERTICAL; break;
418                                 default: devmode.dmDuplex = OS.DMDUP_SIMPLEX;
419                         }
420                 }
421                 OS.MoveMemory(ptr, devmode, DEVMODE.sizeof);
422                 OS.GlobalUnlock(hMem);
423
424                 pd.Flags = OS.PD_USEDEVMODECOPIESANDCOLLATE;
425                 if (printerData.printToFile) pd.Flags |= OS.PD_PRINTTOFILE;
426                 switch (printerData.scope) {
427                         case PrinterData.PAGE_RANGE: pd.Flags |= OS.PD_PAGENUMS; break;
428                         case PrinterData.SELECTION: pd.Flags |= OS.PD_SELECTION; break;
429                         default: pd.Flags |= OS.PD_ALLPAGES;
430                 }
431                 pd.nMinPage = 1;
432                 pd.nMaxPage = -1;
433                 pd.nFromPage = (short) Math.min (0xFFFF, Math.max (1, printerData.startPage));
434                 pd.nToPage = (short) Math.min (0xFFFF, Math.max (1, printerData.endPage));
435
436                 Shell [] shells = display.getShells();
437                 if ((getStyle() & (SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) != 0) {
438                         for (int i=0; i<shells.length; i++) {
439                                 if (shells[i].isEnabled() && shells[i] != parent) {
440                                         shells[i].setEnabled(false);
441                                 } else {
442                                         shells[i] = null;
443                                 }
444                         }
445                 }
446                 String key = "org.eclipse.swt.internal.win32.runMessagesInIdle"; //$NON-NLS-1$
447                 Object oldValue = display.getData(key);
448                 display.setData(key, Boolean.TRUE);
449                 display.setData(externalLoopKey, Boolean.TRUE);
450                 display.sendPreExternalEventDispatchEvent ();
451                 success = OS.PrintDlg(pd);
452                 display.setData(externalLoopKey, Boolean.FALSE);
453                 display.sendPostExternalEventDispatchEvent ();
454                 display.setData(key, oldValue);
455                 if ((getStyle() & (SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) != 0) {
456                         for (int i=0; i<shells.length; i++) {
457                                 if (shells[i] != null && !shells[i].isDisposed ()) {
458                                         shells[i].setEnabled(true);
459                                 }
460                         }
461                 }
462
463                 if (success) {
464                         /* Get driver and device from the DEVNAMES struct */
465                         hMem = pd.hDevNames;
466                         /* Ensure size is a multiple of 2 bytes on UNICODE platforms */
467                         int size = OS.GlobalSize(hMem) / TCHAR.sizeof * TCHAR.sizeof;
468                         ptr = OS.GlobalLock(hMem);
469                         short[] offsets = new short[4];
470                         OS.MoveMemory(offsets, ptr, 2 * offsets.length);
471                         char [] buffer = new char [size];
472                         OS.MoveMemory(buffer, ptr, size);
473                         OS.GlobalUnlock(hMem);
474
475                         int driverOffset = offsets[0];
476                         int i = 0;
477                         while (driverOffset + i < size) {
478                                 if (buffer [driverOffset + i] == 0) break;
479                                 i++;
480                         }
481                         String driver = new String(buffer, driverOffset, i);
482
483                         int deviceOffset = offsets[1];
484                         i = 0;
485                         while (deviceOffset + i < size) {
486                                 if (buffer [deviceOffset + i] == 0) break;
487                                 i++;
488                         }
489                         String device = new String(buffer, deviceOffset, i);
490
491                         /* Create PrinterData object and set fields from PRINTDLG */
492                         data = new PrinterData(driver, device);
493                         if ((pd.Flags & OS.PD_PAGENUMS) != 0) {
494                                 data.scope = PrinterData.PAGE_RANGE;
495                                 data.startPage = pd.nFromPage & 0xFFFF;
496                                 data.endPage = pd.nToPage & 0xFFFF;
497                         } else if ((pd.Flags & OS.PD_SELECTION) != 0) {
498                                 data.scope = PrinterData.SELECTION;
499                         }
500                         data.printToFile = (pd.Flags & OS.PD_PRINTTOFILE) != 0;
501                         if (data.printToFile) data.fileName = printerData.fileName;
502                         data.copyCount = pd.nCopies;
503                         data.collate = (pd.Flags & OS.PD_COLLATE) != 0;
504
505                         /* Bulk-save the printer-specific settings in the DEVMODE struct */
506                         hMem = pd.hDevMode;
507                         size = OS.GlobalSize(hMem);
508                         ptr = OS.GlobalLock(hMem);
509                         data.otherData = new byte[size];
510                         OS.MoveMemory(data.otherData, ptr, size);
511
512                         /* Set PrinterData fields from DEVMODE */
513                         devmode = new DEVMODE ();
514                         OS.MoveMemory(devmode, ptr, DEVMODE.sizeof);
515                         if ((devmode.dmFields & OS.DM_ORIENTATION) != 0) {
516                                 int dmOrientation = devmode.dmOrientation;
517                                 data.orientation = dmOrientation == OS.DMORIENT_LANDSCAPE ? PrinterData.LANDSCAPE : PrinterData.PORTRAIT;
518                         }
519                         if ((devmode.dmFields & OS.DM_DUPLEX) != 0) {
520                                 short dmDuplex = devmode.dmDuplex;
521                                 data.duplex = dmDuplex == OS.DMDUP_SIMPLEX ? PrinterData.DUPLEX_NONE : dmDuplex == OS.DMDUP_HORIZONTAL ? PrinterData.DUPLEX_SHORT_EDGE : PrinterData.DUPLEX_LONG_EDGE;
522                         }
523
524                         OS.GlobalUnlock(hMem);
525                         printerData = data;
526                 }
527         }
528         if (pd.hDevNames != 0) {
529                 OS.GlobalFree(pd.hDevNames);
530                 pd.hDevNames = 0;
531         }
532         if (pd.hDevMode != 0) {
533                 OS.GlobalFree(pd.hDevMode);
534                 pd.hDevMode = 0;
535         }
536         /* Destroy the BIDI orientation window */
537         if (hwndParent != hwndOwner) {
538                 if (enabled) OS.EnableWindow (hwndParent, true);
539                 OS.SetActiveWindow (hwndParent);
540                 OS.DestroyWindow (hwndOwner);
541         }
542         return data;
543 }
544 }