Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / filebrowse.cpp
blobdd8bb4ca5f8da11acec79a1c8e5fbe222990bc6b
1 // todo: support win7/vista extensions rather than GetOpenFileName? -- merge win7filedialog into here.
4 #include "filebrowse.h"
6 #include "win32_utf8.h"
7 #include "wdlcstring.h"
10 #ifdef _WIN32
11 #ifdef _MSC_VER // todo: win7filedialog.cpp support for mingw32
12 #define WDL_FILEBROWSE_WIN7VISTAMODE
13 #endif
14 #endif
19 #ifdef WDL_FILEBROWSE_WIN7VISTAMODE // win7/vista file dialog support
20 #include "win7filedialog.cpp"
22 // stuff since win7filedialog.h collides with shlobj.h below
23 #define tagSHCONTF tagSHCONTF___
24 #define SHCONTF SHCONTF___
25 #define SHCONTF_FOLDERS SHCONTF_FOLDERS___
26 #define SHCONTF_NONFOLDERS SHCONTF_NONFOLDERS___
27 #define SHCONTF_INCLUDEHIDDEN SHCONTF_INCLUDEHIDDEN___
28 #define SHCONTF_SHAREABLE SHCONTF_SHAREABLE__
29 #define SHCONTF_INIT_ON_FIRST_NEXT SHCONTF_INIT_ON_FIRST_NEXT__
30 #define SHCONTF_NETPRINTERSRCH SHCONTF_NETPRINTERSRCH__
31 #define SHCONTF_STORAGE SHCONTF_STORAGE__
32 #endif
35 #ifdef _WIN32
36 // include after win7filedialog.*
38 #include <commctrl.h>
39 #include <shlobj.h>
40 #endif
42 #ifndef BIF_NEWDIALOGSTYLE
43 #define BIF_NEWDIALOGSTYLE 0x40
44 #endif
47 static void WDL_fixfnforopenfn(char *buf)
49 char *p=buf;
50 while (*p)
52 if (WDL_IS_DIRCHAR(*p)) *p = WDL_DIRCHAR;
53 p++;
55 #ifdef _WIN32
56 if (buf[0] && buf[1] == ':')
58 p=buf+2;
59 char *op=p;
60 while (*p)
62 while (p[0]==WDL_DIRCHAR && p[1] == WDL_DIRCHAR) p++;
63 *op++ = *p++;
65 *op=0;
67 #endif
71 #ifdef _WIN32
72 static int CALLBACK WINAPI WDL_BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
74 switch (uMsg)
76 case BFFM_INITIALIZED:
78 if (lpData && ((char *)lpData)[0])
80 #ifndef WDL_NO_SUPPORT_UTF8
81 WDL_UTF8_SendBFFM_SETSEL(hwnd, (const char *)lpData);
82 #else
83 SendMessage(hwnd, BFFM_SETSELECTION, 1, lpData);
84 #endif
86 break;
89 return 0;
91 #endif
94 bool WDL_ChooseDirectory(HWND parent, const char *text, const char *initialdir, char *fn, int fnsize, bool preservecwd)
96 char olddir[2048];
97 GetCurrentDirectory(sizeof(olddir),olddir);
98 #ifdef _WIN32
99 char name[4096];
100 lstrcpyn_safe(name,initialdir?initialdir:"",sizeof(name));
101 BROWSEINFO bi={parent,NULL, name, text, BIF_RETURNONLYFSDIRS|BIF_NEWDIALOGSTYLE, WDL_BrowseCallbackProc, (LPARAM)name,};
102 LPITEMIDLIST idlist = SHBrowseForFolderUTF8( &bi );
103 if (idlist && SHGetPathFromIDListUTF8(idlist, name, sizeof(name)))
105 IMalloc *m;
106 SHGetMalloc(&m);
107 m->Free(idlist);
108 lstrcpyn_safe(fn,name,fnsize);
109 return true;
111 return false;
113 #else
114 bool r = BrowseForDirectory(text,initialdir,fn,fnsize);
115 if (preservecwd) SetCurrentDirectory(olddir);
116 return r;
117 #endif
120 static const char *stristr(const char* a, const char* b)
122 const size_t n = strlen(a), len = strlen(b);
123 for (size_t i = 0; i+len <= n; ++i) if (!strnicmp(a+i, b, len)) return a+i;
124 return NULL;
127 bool WDL_ChooseFileForSave(HWND parent,
128 const char *text,
129 const char *initialdir,
130 const char *initialfile,
131 const char *extlist,
132 const char *defext,
133 bool preservecwd,
134 char *fn,
135 int fnsize,
136 const char *dlgid,
137 void *dlgProc,
138 #ifdef _WIN32
139 HINSTANCE hInstance
140 #else
141 struct SWELL_DialogResourceIndex *reshead
142 #endif
145 char cwd[2048];
146 GetCurrentDirectory(sizeof(cwd),cwd);
148 #ifdef _WIN32
149 char temp[4096];
150 memset(temp,0,sizeof(temp));
151 if (initialfile) lstrcpyn_safe(temp,initialfile,sizeof(temp));
152 WDL_fixfnforopenfn(temp);
154 #ifdef WDL_FILEBROWSE_WIN7VISTAMODE
156 Win7FileDialog fd(text, 1);
157 if(fd.inited())
159 fd.addOptions(FOS_DONTADDTORECENT);
160 //vista+ file open dialog
161 char olddir[2048];
162 GetCurrentDirectory(sizeof(olddir),olddir);
164 fd.setFilterList(extlist);
165 if (defext)
167 fd.setDefaultExtension(defext);
169 int i = 0;
170 const char *p = extlist;
171 while(*p)
173 if(*p) p+=strlen(p)+1;
174 if(!*p) break;
175 if(stristr(p, defext))
177 fd.setFileTypeIndex(i+1);
178 break;
180 i++;
181 p+=strlen(p)+1;
184 fd.setFolder(initialdir?initialdir:olddir, 0);
185 if(initialfile)
187 //check for folder name
188 if (WDL_remove_filepart(temp))
190 //folder found
191 fd.setFolder(temp, 0);
192 fd.setFilename(temp + strlen(temp) + 1);
194 else
195 fd.setFilename(*temp ? temp : initialfile);
197 fd.setTemplate(hInstance, dlgid, (LPOFNHOOKPROC)dlgProc);
199 if(fd.show(parent))
201 //ifilesavedialog saves the last folder automatically
202 fd.getResult(fn, fnsize);
204 if (preservecwd) SetCurrentDirectory(olddir);
205 return true;
208 if (preservecwd) SetCurrentDirectory(olddir);
209 return NULL;
212 #endif
215 OPENFILENAME l={sizeof(l),parent, hInstance, extlist, NULL,0, 0, temp, sizeof(temp)-1, NULL, 0, initialdir&&initialdir[0] ? initialdir : cwd, text,
216 OFN_HIDEREADONLY|OFN_EXPLORER|OFN_OVERWRITEPROMPT,0,0,defext, 0, (LPOFNHOOKPROC)dlgProc, dlgid};
218 if (hInstance&&dlgProc&&dlgid) l.Flags |= OFN_ENABLEHOOK|OFN_ENABLETEMPLATE|OFN_ENABLESIZING;
219 if (preservecwd) l.Flags |= OFN_NOCHANGEDIR;
221 if (!GetSaveFileName(&l)||!temp[0])
223 if (preservecwd) SetCurrentDirectory(cwd);
224 return false;
226 if (preservecwd) SetCurrentDirectory(cwd);
227 lstrcpyn_safe(fn,temp,fnsize);
228 return true;
230 #else
231 BrowseFile_SetTemplate(dlgid,(DLGPROC)dlgProc,reshead);
232 char if_temp[4096];
233 if (initialfile && *initialfile)
235 lstrcpyn_safe(if_temp,initialfile,sizeof(if_temp));
236 WDL_fixfnforopenfn(if_temp);
237 initialfile = if_temp;
239 else
241 if (defext && *defext == '.') initialfile = defext; // SWELL supports default extension in filename field
244 bool r = BrowseForSaveFile(text,initialdir,initialfile,extlist,fn,fnsize);
246 if (preservecwd) SetCurrentDirectory(cwd);
248 return r;
249 #endif
253 char *WDL_ChooseFileForOpen2(HWND parent,
254 const char *text,
255 const char *initialdir,
256 const char *initialfile,
257 const char *extlist,
258 const char *defext,
260 bool preservecwd,
261 int allowmul,
263 const char *dlgid,
264 void *dlgProc,
265 #ifdef _WIN32
266 HINSTANCE hInstance
267 #else
268 struct SWELL_DialogResourceIndex *reshead
269 #endif
272 char olddir[2048];
273 GetCurrentDirectory(sizeof(olddir),olddir);
275 #ifdef _WIN32
277 #ifdef WDL_FILEBROWSE_WIN7VISTAMODE
278 if (allowmul!=1)
280 Win7FileDialog fd(text);
281 if(fd.inited())
283 //vista+ file open dialog
284 fd.addOptions(FOS_FILEMUSTEXIST|(allowmul?FOS_ALLOWMULTISELECT:0));
285 fd.setFilterList(extlist);
286 if (defext)
288 fd.setDefaultExtension(defext);
290 int i = 0;
291 const char *p = extlist;
292 while(*p)
294 if(*p) p+=strlen(p)+1;
295 if(!*p) break;
296 if(stristr(p, defext))
298 fd.setFileTypeIndex(i+1);
299 break;
301 i++;
302 p+=strlen(p)+1;
305 fd.setFolder(initialdir?initialdir:olddir, 0);
306 fd.setTemplate(hInstance, dlgid, (LPOFNHOOKPROC)dlgProc);
307 if(initialfile)
309 char temp[4096];
310 lstrcpyn_safe(temp,initialfile,sizeof(temp));
311 //check for folder name
312 if (WDL_remove_filepart(temp))
314 //folder found
315 fd.setFolder(temp, 0);
316 fd.setFilename(temp + strlen(temp) + 1);
318 else
319 fd.setFilename(temp);
322 if(fd.show(parent))
324 char *ret=NULL;
325 char temp[4096];
326 temp[0]=0;
328 //ifileopendialog saves the last folder automatically
329 if (!allowmul)
331 fd.getResult(temp, sizeof(temp)-1);
332 ret= temp[0] ? strdup(temp) : NULL;
334 else
336 char* p=NULL;
337 int totallen=0, cnt=fd.getResultCount();
338 if (cnt>1)
340 // sets an empty path as 1st returned string for multipath support
341 // (when selecting files among search results for ex.)
342 ret = strdup("");
343 totallen=1;
346 int i;
347 for (i=0; i<cnt; i++)
349 int len = fd.getResult(i, temp, sizeof(temp)-1);
350 p = len ? (char*)realloc(ret, totallen + len + ((i==cnt-1)?1:0)) : NULL;
351 if (p)
353 ret=p;
354 memcpy(ret+totallen, temp, len);
355 totallen+=len;
357 else
359 free(ret);
360 ret=NULL;
361 break;
364 if (ret) p[totallen]=0;
367 if (preservecwd) SetCurrentDirectory(olddir);
368 return ret;
371 if (preservecwd) SetCurrentDirectory(olddir);
372 return NULL;
375 #endif
377 int temp_size = allowmul ? 256*1024-1 : 4096-1;
378 char *temp = (char *)calloc(temp_size+1,1);
380 OPENFILENAME l={sizeof(l), parent, hInstance, extlist, NULL, 0, 0, temp, temp_size, NULL, 0, initialdir, text,
381 OFN_HIDEREADONLY|OFN_EXPLORER|OFN_FILEMUSTEXIST,0,0, (char *)(defext ? defext : ""), 0, (LPOFNHOOKPROC)dlgProc, dlgid};
383 if (hInstance&&dlgProc&&dlgid) l.Flags |= OFN_ENABLEHOOK|OFN_ENABLETEMPLATE|OFN_ENABLESIZING;
384 if (allowmul) l.Flags|=OFN_ALLOWMULTISELECT;
385 if (preservecwd) l.Flags|=OFN_NOCHANGEDIR;
387 if (initialfile) lstrcpyn_safe(temp,initialfile,temp_size);
389 WDL_fixfnforopenfn(temp);
391 if (!l.lpstrInitialDir||!l.lpstrInitialDir[0]) l.lpstrInitialDir=olddir;
393 int r = GetOpenFileName(&l);
394 if (preservecwd) SetCurrentDirectory(olddir);
396 if (!r) free(temp);
397 return r?temp:NULL;
399 #else
400 char if_temp[4096];
401 if (initialfile)
403 lstrcpyn_safe(if_temp,initialfile,sizeof(if_temp));
404 WDL_fixfnforopenfn(if_temp);
405 initialfile = if_temp;
408 // defext support?
409 BrowseFile_SetTemplate(dlgid,(DLGPROC)dlgProc,reshead);
410 char *ret = BrowseForFiles(text,initialdir,initialfile,allowmul,extlist);
411 if (preservecwd) SetCurrentDirectory(olddir);
413 return ret;
414 #endif
417 char *WDL_ChooseFileForOpen(HWND parent,
418 const char *text,
419 const char *initialdir,
420 const char *initialfile,
421 const char *extlist,
422 const char *defext,
424 bool preservecwd,
425 bool allowmul,
427 const char *dlgid,
428 void *dlgProc,
429 #ifdef _WIN32
430 HINSTANCE hInstance
431 #else
432 struct SWELL_DialogResourceIndex *reshead
433 #endif
436 return WDL_ChooseFileForOpen2(parent,text, initialdir,initialfile,extlist,defext,preservecwd,allowmul?1:0,dlgid,dlgProc,
437 #ifdef _WIN32
438 hInstance
439 #else
440 reshead
441 #endif