]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/DirectoryDialog.java
Remove invalid SHA-256-Digests
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / DirectoryDialog.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2017 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  *     Martin Karpisek <martin.karpisek@gmail.com> - Bug 443250
14  *******************************************************************************/
15 package org.eclipse.swt.widgets;
16
17
18 import org.eclipse.swt.*;
19 import org.eclipse.swt.internal.*;
20 import org.eclipse.swt.internal.ole.win32.*;
21 import org.eclipse.swt.internal.win32.*;
22
23 /**
24  * Instances of this class allow the user to navigate
25  * the file system and select a directory.
26  * <dl>
27  * <dt><b>Styles:</b></dt>
28  * <dd>(none)</dd>
29  * <dt><b>Events:</b></dt>
30  * <dd>(none)</dd>
31  * </dl>
32  * <p>
33  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
34  * </p>
35  *
36  * @see <a href="http://www.eclipse.org/swt/snippets/#directorydialog">DirectoryDialog snippets</a>
37  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample, Dialog tab</a>
38  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
39  * @noextend This class is not intended to be subclassed by clients.
40  */
41 public class DirectoryDialog extends Dialog {
42         String message = "", filterPath = "";  //$NON-NLS-1$//$NON-NLS-2$
43         String directoryPath;
44
45 /**
46  * Constructs a new instance of this class given only its parent.
47  *
48  * @param parent a shell which will be the parent of the new instance
49  *
50  * @exception IllegalArgumentException <ul>
51  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
52  * </ul>
53  * @exception SWTException <ul>
54  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
55  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
56  * </ul>
57  */
58 public DirectoryDialog (Shell parent) {
59         this (parent, SWT.APPLICATION_MODAL);
60 }
61
62 /**
63  * Constructs a new instance of this class given its parent
64  * and a style value describing its behavior and appearance.
65  * <p>
66  * The style value is either one of the style constants defined in
67  * class <code>SWT</code> which is applicable to instances of this
68  * class, or must be built by <em>bitwise OR</em>'ing together
69  * (that is, using the <code>int</code> "|" operator) two or more
70  * of those <code>SWT</code> style constants. The class description
71  * lists the style constants that are applicable to the class.
72  * Style bits are also inherited from superclasses.
73  * </p>
74  *
75  * @param parent a shell which will be the parent of the new instance
76  * @param style the style of dialog to construct
77  *
78  * @exception IllegalArgumentException <ul>
79  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
80  * </ul>
81  * @exception SWTException <ul>
82  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
83  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
84  * </ul>
85  */
86 public DirectoryDialog (Shell parent, int style) {
87         super (parent, checkStyle (parent, style));
88         checkSubclass ();
89 }
90
91 long BrowseCallbackProc (long hwnd, long uMsg, long lParam, long lpData) {
92         switch ((int)uMsg) {
93                 case OS.BFFM_INITIALIZED:
94                         if (filterPath != null && filterPath.length () != 0) {
95                                 /* Use the character encoding for the default locale */
96                                 TCHAR buffer = new TCHAR (0, filterPath.replace ('/', '\\'), true);
97                                 OS.SendMessage (hwnd, OS.BFFM_SETSELECTION, 1, buffer);
98                         }
99                         if (title != null && title.length () != 0) {
100                                 /* Use the character encoding for the default locale */
101                                 TCHAR buffer = new TCHAR (0, title, true);
102                                 OS.SetWindowText (hwnd, buffer);
103                         }
104                         break;
105                 case OS.BFFM_VALIDATEFAILED:
106                         /* Use the character encoding for the default locale */
107                         int length = OS.wcslen (lParam);
108                         TCHAR buffer = new TCHAR (0, length);
109                         int byteCount = buffer.length () * TCHAR.sizeof;
110                         OS.MoveMemory (buffer, lParam, byteCount);
111                         directoryPath = buffer.toString (0, length);
112                         break;
113         }
114         return 0;
115 }
116
117 /**
118  * Returns the path which the dialog will use to filter
119  * the directories it shows.
120  *
121  * @return the filter path
122  *
123  * @see #setFilterPath
124  */
125 public String getFilterPath () {
126         return filterPath;
127 }
128
129 /**
130  * Returns the dialog's message, which is a description of
131  * the purpose for which it was opened. This message will be
132  * visible on the dialog while it is open.
133  *
134  * @return the message
135  */
136 public String getMessage () {
137         return message;
138 }
139
140 /**
141  * Makes the dialog visible and brings it to the front
142  * of the display.
143  *
144  * @return a string describing the absolute path of the selected directory,
145  *         or null if the dialog was cancelled or an error occurred
146  *
147  * @exception SWTException <ul>
148  *    <li>ERROR_WIDGET_DISPOSED - if the dialog has been disposed</li>
149  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the dialog</li>
150  * </ul>
151  */
152 public String open() {
153         if (OS.WIN32_VERSION >= OS.VERSION (6, 0)) {
154                 return openCommonItemDialog();
155         }
156         return openCommonFileDialog();
157 }
158
159 private String openCommonFileDialog () {
160         long hHeap = OS.GetProcessHeap ();
161
162         /* Get the owner HWND for the dialog */
163         long hwndOwner = 0;
164         if (parent != null) hwndOwner = parent.handle;
165
166         /* Copy the message to OS memory */
167         long lpszTitle = 0;
168         if (message.length () != 0) {
169                 String string = message;
170                 if (string.indexOf ('&') != -1) {
171                         int length = string.length ();
172                         char [] buffer = new char [length * 2];
173                         int index = 0;
174                         for (int i=0; i<length; i++) {
175                                 char ch = string.charAt (i);
176                                 if (ch == '&') buffer [index++] = '&';
177                                 buffer [index++] = ch;
178                         }
179                         string = new String (buffer, 0, index);
180                 }
181                 /* Use the character encoding for the default locale */
182                 TCHAR buffer = new TCHAR (0, string, true);
183                 int byteCount = buffer.length () * TCHAR.sizeof;
184                 lpszTitle = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount);
185                 OS.MoveMemory (lpszTitle, buffer, byteCount);
186         }
187
188         /* Create the BrowseCallbackProc */
189         Callback callback = new Callback (this, "BrowseCallbackProc", 4); //$NON-NLS-1$
190         long lpfn = callback.getAddress ();
191         if (lpfn == 0) error (SWT.ERROR_NO_MORE_CALLBACKS);
192
193         /* Make the parent shell be temporary modal */
194         Dialog oldModal = null;
195         Display display = parent.getDisplay ();
196         if ((style & (SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) != 0) {
197                 oldModal = display.getModalDialog ();
198                 display.setModalDialog (this);
199         }
200
201         directoryPath = null;
202         BROWSEINFO lpbi = new BROWSEINFO ();
203         lpbi.hwndOwner = hwndOwner;
204         lpbi.lpszTitle = lpszTitle;
205         lpbi.ulFlags = OS.BIF_NEWDIALOGSTYLE | OS.BIF_RETURNONLYFSDIRS | OS.BIF_EDITBOX | OS.BIF_VALIDATE;
206         lpbi.lpfn = lpfn;
207         /*
208         * Bug in Windows.  On some hardware configurations, SHBrowseForFolder()
209         * causes warning dialogs with the message "There is no disk in the drive
210         * Please insert a disk into \Device\Harddisk0\DR0".  This is possibly
211         * caused by SHBrowseForFolder() calling internally GetVolumeInformation().
212         * MSDN for GetVolumeInformation() says:
213         *
214         * "If you are attempting to obtain information about a floppy drive
215         * that does not have a floppy disk or a CD-ROM drive that does not
216         * have a compact disc, the system displays a message box asking the
217         * user to insert a floppy disk or a compact disc, respectively.
218         * To prevent the system from displaying this message box, call the
219         * SetErrorMode function with SEM_FAILCRITICALERRORS."
220         *
221         * The fix is to save and restore the error mode using SetErrorMode()
222         * with the SEM_FAILCRITICALERRORS flag around SHBrowseForFolder().
223         */
224         int oldErrorMode = OS.SetErrorMode (OS.SEM_FAILCRITICALERRORS);
225
226         display.sendPreExternalEventDispatchEvent ();
227         display.externalEventLoop = true;
228         long lpItemIdList = OS.SHBrowseForFolder (lpbi);
229         display.externalEventLoop = false;
230         display.sendPostExternalEventDispatchEvent ();
231         OS.SetErrorMode (oldErrorMode);
232
233         /* Clear the temporary dialog modal parent */
234         if ((style & (SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL)) != 0) {
235                 display.setModalDialog (oldModal);
236         }
237
238         boolean success = lpItemIdList != 0;
239         if (success) {
240                 /* Use the character encoding for the default locale */
241                 TCHAR buffer = new TCHAR (0, OS.MAX_PATH);
242                 if (OS.SHGetPathFromIDList (lpItemIdList, buffer)) {
243                         directoryPath = buffer.toString (0, buffer.strlen ());
244                         filterPath = directoryPath;
245                 }
246         }
247
248         /* Free the BrowseCallbackProc */
249         callback.dispose ();
250
251         /* Free the OS memory */
252         if (lpszTitle != 0) OS.HeapFree (hHeap, 0, lpszTitle);
253
254         /* Free the pointer to the ITEMIDLIST */
255         long [] ppMalloc = new long [1];
256         if (OS.SHGetMalloc (ppMalloc) == OS.S_OK) {
257                 /* void Free (struct IMalloc *this, void *pv); */
258                 COM.VtblCall (5, ppMalloc [0], lpItemIdList);
259         }
260
261         /*
262         * This code is intentionally commented.  On some
263         * platforms, the owner window is repainted right
264         * away when a dialog window exits.  This behavior
265         * is currently unspecified.
266         */
267 //      if (hwndOwner != 0) OS.UpdateWindow (hwndOwner);
268
269         /* Return the directory path */
270         if (!success) return null;
271         return directoryPath;
272 }
273
274 private String openCommonItemDialog() {
275         this.directoryPath = null;
276
277         long [] ppv = new long [1];
278         if (COM.CoCreateInstance(COM.CLSID_FileOpenDialog, 0, COM.CLSCTX_INPROC_SERVER, COM.IID_IFileOpenDialog, ppv) == OS.S_OK) {
279                 IFileDialog fileDialog = new IFileDialog(ppv[0]);
280
281                 int[] options = new int[1];
282                 if (fileDialog.GetOptions(options) == OS.S_OK) {
283                         options[0] |= OS.FOS_PICKFOLDERS | OS.FOS_FORCEFILESYSTEM | OS.FOS_NOCHANGEDIR;
284                         fileDialog.SetOptions(options[0]);
285                 }
286
287                 if (title == null) title = "";
288                 if (title.length() > 0) {
289                         char[] buffer = new char[title.length() + 1];
290                         title.getChars(0, title.length(), buffer, 0);
291                         fileDialog.SetTitle(buffer);
292                 }
293
294                 if (filterPath != null && filterPath.length() > 0) {
295                         String path = filterPath.replace('/', '\\');
296                         char[] buffer = new char[path.length() + 1];
297                         path.getChars(0, path.length(), buffer, 0);
298                         if (COM.SHCreateItemFromParsingName(buffer, 0, COM.IID_IShellItem, ppv) == OS.S_OK) {
299                                 IShellItem psi = new IShellItem(ppv[0]);
300                                 /*
301                                  * SetDefaultDirectory does not work if the dialog has
302                                  * persisted recently used folder. The fix is to clear the
303                                  * persisted data.
304                                  */
305                                 fileDialog.ClearClientData();
306                                 fileDialog.SetDefaultFolder(psi);
307                                 psi.Release();
308                         }
309                 }
310
311                 Display display = parent.getDisplay();
312                 long hwndOwner = parent.handle;
313                 display.externalEventLoop = true;
314                 if (fileDialog.Show(hwndOwner) == OS.S_OK) {
315                         if (fileDialog.GetResult(ppv) == OS.S_OK) {
316                                 IShellItem psi = new IShellItem(ppv[0]);
317                                 if (psi.GetDisplayName(OS.SIGDN_FILESYSPATH, ppv) == OS.S_OK) {
318                                         long wstr = ppv[0];
319                                         int length = OS.wcslen(wstr);
320                                         char[] buffer = new char[length];
321                                         OS.MoveMemory(buffer, wstr, length * 2);
322                                         OS.CoTaskMemFree(wstr);
323
324                                         directoryPath = new String(buffer);
325                                 }
326                                 psi.Release();
327                         }
328                 }
329                 display.externalEventLoop = false;
330
331                 fileDialog.Release();
332         }
333
334         return directoryPath;
335 }
336
337 /**
338  * Sets the path that the dialog will use to filter
339  * the directories it shows to the argument, which may
340  * be null. If the string is null, then the operating
341  * system's default filter path will be used.
342  * <p>
343  * Note that the path string is platform dependent.
344  * For convenience, either '/' or '\' can be used
345  * as a path separator.
346  * </p>
347  *
348  * @param string the filter path
349  */
350 public void setFilterPath (String string) {
351         filterPath = string;
352 }
353
354 /**
355  * Sets the dialog's message, which is a description of
356  * the purpose for which it was opened. This message will be
357  * visible on the dialog while it is open.
358  * <p>
359  * NOTE: This operation is a hint and is not supported on some platforms. For
360  * example, on Windows (Vista and later), the <code>DirectoryDialog</code>
361  * doesn't have any provision to set a message.
362  * </p>
363  *
364  * @param string the message
365  *
366  * @exception IllegalArgumentException <ul>
367  *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
368  * </ul>
369  */
370 public void setMessage (String string) {
371         if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
372         message = string;
373 }
374
375 }