]> git.saurik.com Git - wxWidgets.git/blame - src/msw/filedlg.cpp
Add wxCALL_FOR_EACH() macro.
[wxWidgets.git] / src / msw / filedlg.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
f6bcfd97 2// Name: src/msw/filedlg.cpp
2bda0e17
KB
3// Purpose: wxFileDialog
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
f6bcfd97
BP
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2bda0e17
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
ba681060 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
3180bc0e 27#if wxUSE_FILEDLG && !(defined(__SMARTPHONE__) && defined(__WXWINCE__))
1e6feb95 28
949c9f74
WS
29#include "wx/filedlg.h"
30
2bda0e17 31#ifndef WX_PRECOMP
57bd4c60
WS
32 #include "wx/msw/wrapcdlg.h"
33 #include "wx/msw/missing.h"
ba681060
VZ
34 #include "wx/utils.h"
35 #include "wx/msgdlg.h"
2b5f62a0 36 #include "wx/filefn.h"
ba681060 37 #include "wx/intl.h"
2662e49e 38 #include "wx/log.h"
f6bcfd97 39 #include "wx/app.h"
18680f86 40 #include "wx/math.h"
8f177c8e 41#endif
2bda0e17 42
2bda0e17
KB
43#include <stdlib.h>
44#include <string.h>
45
30374272 46#include "wx/dynlib.h"
8ad9ca97 47#include "wx/filename.h"
30374272 48#include "wx/scopeguard.h"
8f177c8e
VZ
49#include "wx/tokenzr.h"
50
f6bcfd97
BP
51// ----------------------------------------------------------------------------
52// constants
53// ----------------------------------------------------------------------------
54
55#ifdef __WIN32__
2b5f62a0 56# define wxMAXPATH 65534
f6bcfd97
BP
57#else
58# define wxMAXPATH 1024
59#endif
60
61# define wxMAXFILE 1024
62
63# define wxMAXEXT 5
64
0b11099d
VZ
65// ----------------------------------------------------------------------------
66// globals
67// ----------------------------------------------------------------------------
68
0a7b0229 69// standard dialog size for the old Windows systems where the dialog wasn't
d13b34d3 70// resizable
0b11099d
VZ
71static wxRect gs_rectDialog(0, 0, 428, 266);
72
f6bcfd97
BP
73// ============================================================================
74// implementation
75// ============================================================================
76
f74172ab 77IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase)
2bda0e17 78
30374272
DS
79// ----------------------------------------------------------------------------
80
81namespace
82{
83
84#if wxUSE_DYNLIB_CLASS
85
86typedef BOOL (WINAPI *GetProcessUserModeExceptionPolicy_t)(LPDWORD);
87typedef BOOL (WINAPI *SetProcessUserModeExceptionPolicy_t)(DWORD);
88
89GetProcessUserModeExceptionPolicy_t gs_pfnGetProcessUserModeExceptionPolicy
90 = (GetProcessUserModeExceptionPolicy_t) -1;
91
92SetProcessUserModeExceptionPolicy_t gs_pfnSetProcessUserModeExceptionPolicy
93 = (SetProcessUserModeExceptionPolicy_t) -1;
94
95DWORD gs_oldExceptionPolicyFlags = 0;
96
97bool gs_changedPolicy = false;
98
99#endif // #if wxUSE_DYNLIB_CLASS
100
101/*
102Since Windows 7 by default (callback) exceptions aren't swallowed anymore
103with native x64 applications. Exceptions can occur in a file dialog when
104using the hook procedure in combination with third-party utilities.
105Since Windows 7 SP1 the swallowing of exceptions can be enabled again
106by using SetProcessUserModeExceptionPolicy.
107*/
108void ChangeExceptionPolicy()
109{
110#if wxUSE_DYNLIB_CLASS
111 gs_changedPolicy = false;
112
113 wxLoadedDLL dllKernel32(wxT("kernel32.dll"));
114
115 if ( gs_pfnGetProcessUserModeExceptionPolicy
116 == (GetProcessUserModeExceptionPolicy_t) -1)
117 {
118 wxDL_INIT_FUNC(gs_pfn, GetProcessUserModeExceptionPolicy, dllKernel32);
119 wxDL_INIT_FUNC(gs_pfn, SetProcessUserModeExceptionPolicy, dllKernel32);
120 }
121
122 if ( !gs_pfnGetProcessUserModeExceptionPolicy
123 || !gs_pfnSetProcessUserModeExceptionPolicy
124 || !gs_pfnGetProcessUserModeExceptionPolicy(&gs_oldExceptionPolicyFlags) )
125 {
126 return;
127 }
128
129 if ( gs_pfnSetProcessUserModeExceptionPolicy(gs_oldExceptionPolicyFlags
130 | 0x1 /* PROCESS_CALLBACK_FILTER_ENABLED */ ) )
131 {
132 gs_changedPolicy = true;
133 }
134
135#endif // wxUSE_DYNLIB_CLASS
136}
137
138void RestoreExceptionPolicy()
139{
140#if wxUSE_DYNLIB_CLASS
141 if (gs_changedPolicy)
142 {
143 gs_changedPolicy = false;
144 (void) gs_pfnSetProcessUserModeExceptionPolicy(gs_oldExceptionPolicyFlags);
145 }
146#endif // wxUSE_DYNLIB_CLASS
147}
148
149} // unnamed namespace
150
0b11099d
VZ
151// ----------------------------------------------------------------------------
152// hook function for moving the dialog
153// ----------------------------------------------------------------------------
154
106d80ad 155UINT_PTR APIENTRY
0b11099d
VZ
156wxFileDialogHookFunction(HWND hDlg,
157 UINT iMsg,
158 WPARAM WXUNUSED(wParam),
159 LPARAM lParam)
160{
cb80db46 161 switch ( iMsg )
0b11099d 162 {
d6dae1b4 163#ifndef __WXWINCE__
6fa6d659
VZ
164 case WM_INITDIALOG:
165 {
166 OPENFILENAME* ofn = reinterpret_cast<OPENFILENAME *>(lParam);
167 reinterpret_cast<wxFileDialog *>(ofn->lCustData)
168 ->MSWOnInitDialogHook((WXHWND)hDlg);
169 }
170 break;
d6dae1b4 171#endif // __WXWINCE__
6fa6d659 172
0b11099d
VZ
173 case WM_NOTIFY:
174 {
5c33522f 175 OFNOTIFY *pNotifyCode = reinterpret_cast<OFNOTIFY *>(lParam);
cb80db46 176 if ( pNotifyCode->hdr.code == CDN_INITDONE )
0b11099d 177 {
5c33522f 178 reinterpret_cast<wxFileDialog *>(
0a7b0229
VZ
179 pNotifyCode->lpOFN->lCustData)
180 ->MSWOnInitDone((WXHWND)hDlg);
0b11099d
VZ
181 }
182 }
183 break;
cb80db46
VZ
184
185 case WM_DESTROY:
186 // reuse the position used for the dialog the next time by default
187 //
188 // NB: at least under Windows 2003 this is useless as after the
189 // first time it's shown the dialog always remembers its size
190 // and position itself and ignores any later SetWindowPos calls
191 wxCopyRECTToRect(wxGetWindowRect(::GetParent(hDlg)), gs_rectDialog);
192 break;
0b11099d
VZ
193 }
194
195 // do the default processing
196 return 0;
197}
198
f6bcfd97 199// ----------------------------------------------------------------------------
b600ed13 200// wxFileDialog
f6bcfd97
BP
201// ----------------------------------------------------------------------------
202
2b5f62a0
VZ
203wxFileDialog::wxFileDialog(wxWindow *parent,
204 const wxString& message,
205 const wxString& defaultDir,
206 const wxString& defaultFileName,
207 const wxString& wildCard,
208 long style,
ff3e84ff
VZ
209 const wxPoint& pos,
210 const wxSize& sz,
211 const wxString& name)
0b11099d 212 : wxFileDialogBase(parent, message, defaultDir, defaultFileName,
ff3e84ff 213 wildCard, style, pos, sz, name)
f74172ab 214
2bda0e17 215{
556151f5 216 // NB: all style checks are done by wxFileDialogBase::Create
2bda0e17 217
0b11099d 218 m_bMovedWindow = false;
0a7b0229 219 m_centreDir = 0;
0b11099d
VZ
220
221 // Must set to zero, otherwise the wx routines won't size the window
222 // the second time you call the file dialog, because it thinks it is
223 // already at the requested size.. (when centering)
224 gs_rectDialog.x =
225 gs_rectDialog.y = 0;
0b11099d 226}
0a7b0229 227
c61f4f6d
VZ
228void wxFileDialog::GetPaths(wxArrayString& paths) const
229{
230 paths.Empty();
231
232 wxString dir(m_dir);
b39badac 233 if ( m_dir.empty() || m_dir.Last() != wxT('\\') )
9a83f860 234 dir += wxT('\\');
c61f4f6d
VZ
235
236 size_t count = m_fileNames.GetCount();
237 for ( size_t n = 0; n < count; n++ )
238 {
8ad9ca97
JS
239 if (wxFileName(m_fileNames[n]).IsAbsolute())
240 paths.Add(m_fileNames[n]);
241 else
242 paths.Add(dir + m_fileNames[n]);
c61f4f6d
VZ
243 }
244}
245
89654c9a
VZ
246void wxFileDialog::GetFilenames(wxArrayString& files) const
247{
248 files = m_fileNames;
249}
250
cb80db46 251void wxFileDialog::DoGetPosition(int *x, int *y) const
0b11099d 252{
cb80db46
VZ
253 if ( x )
254 *x = gs_rectDialog.x;
255 if ( y )
256 *y = gs_rectDialog.y;
0b11099d
VZ
257}
258
0b11099d
VZ
259void wxFileDialog::DoGetSize(int *width, int *height) const
260{
cb80db46
VZ
261 if ( width )
262 *width = gs_rectDialog.width;
263 if ( height )
264 *height = gs_rectDialog.height;
0b11099d
VZ
265}
266
cb80db46 267void wxFileDialog::DoMoveWindow(int x, int y, int WXUNUSED(w), int WXUNUSED(h))
0b11099d 268{
0b11099d
VZ
269 gs_rectDialog.x = x;
270 gs_rectDialog.y = y;
271
0a7b0229
VZ
272 // our HWND is only set when we're called from MSWOnInitDone(), test if
273 // this is the case
274 HWND hwnd = GetHwnd();
275 if ( hwnd )
276 {
277 // size of the dialog can't be changed because the controls are not
278 // laid out correctly then
279 ::SetWindowPos(hwnd, HWND_TOP, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
280 }
281 else // just remember that we were requested to move the window
282 {
283 m_bMovedWindow = true;
284
285 // if Centre() had been called before, it shouldn't be taken into
286 // account now
287 m_centreDir = 0;
288 }
289}
290
291void wxFileDialog::DoCentre(int dir)
292{
293 m_centreDir = dir;
294 m_bMovedWindow = true;
295
296 // it's unnecessary to do anything else at this stage as we'll redo it in
297 // MSWOnInitDone() anyhow
298}
299
300void wxFileDialog::MSWOnInitDone(WXHWND hDlg)
301{
4c51a665 302 // note the dialog is the parent window: hDlg is a child of it when
0a7b0229
VZ
303 // OFN_EXPLORER is used
304 HWND hFileDlg = ::GetParent((HWND)hDlg);
305
306 // set HWND so that our DoMoveWindow() works correctly
307 SetHWND((WXHWND)hFileDlg);
308
309 if ( m_centreDir )
310 {
311 // now we have the real dialog size, remember it
312 RECT rect;
313 GetWindowRect(hFileDlg, &rect);
314 gs_rectDialog = wxRectFromRECT(rect);
315
316 // and position the window correctly: notice that we must use the base
317 // class version as our own doesn't do anything except setting flags
318 wxFileDialogBase::DoCentre(m_centreDir);
319 }
320 else // need to just move it to the correct place
321 {
322 SetPosition(gs_rectDialog.GetPosition());
323 }
324
325 // we shouldn't destroy this HWND
326 SetHWND(NULL);
0b11099d
VZ
327}
328
fe048d77
VZ
329// helper used below in ShowCommFileDialog(): style is used to determine
330// whether to show the "Save file" dialog (if it contains wxFD_SAVE bit) or
331// "Open file" one; returns true on success or false on failure in which case
332// err is filled with the CDERR_XXX constant
c46c1fb8
VZ
333static bool DoShowCommFileDialog(OPENFILENAME *of, long style, DWORD *err)
334{
e031f1df 335 if ( style & wxFD_SAVE ? GetSaveFileName(of) : GetOpenFileName(of) )
c46c1fb8
VZ
336 return true;
337
338 if ( err )
339 {
340#ifdef __WXWINCE__
341 // according to MSDN, CommDlgExtendedError() should work under CE as
342 // well but apparently in practice it doesn't (anybody has more
343 // details?)
344 *err = GetLastError();
345#else
346 *err = CommDlgExtendedError();
347#endif
348 }
349
350 return false;
351}
352
04227efc
VZ
353// We want to use OPENFILENAME struct version 5 (Windows 2000/XP) but we don't
354// know if the OPENFILENAME declared in the currently used headers is a V5 or
355// V4 (smaller) one so we try to manually extend the struct in case it is the
356// old one.
5bb37216 357//
04227efc
VZ
358// We don't do this on Windows CE nor under Win64, however, as there are no
359// compilers with old headers for these architectures
360#if defined(__WXWINCE__) || defined(__WIN64__)
5bb37216
VZ
361 typedef OPENFILENAME wxOPENFILENAME;
362
04227efc
VZ
363 static const DWORD gs_ofStructSize = sizeof(OPENFILENAME);
364#else // !__WXWINCE__ || __WIN64__
365 #define wxTRY_SMALLER_OPENFILENAME
366
5bb37216
VZ
367 struct wxOPENFILENAME : public OPENFILENAME
368 {
369 // fields added in Windows 2000/XP comdlg32.dll version
370 void *pVoid;
371 DWORD dw1;
372 DWORD dw2;
373 };
374
375 // hardcoded sizeof(OPENFILENAME) in the Platform SDK: we have to do it
376 // because sizeof(OPENFILENAME) in the headers we use when compiling the
377 // library could be less if _WIN32_WINNT is not >= 0x500
378 static const DWORD wxOPENFILENAME_V5_SIZE = 88;
379
380 // this is hardcoded sizeof(OPENFILENAME_NT4) from Platform SDK
381 static const DWORD wxOPENFILENAME_V4_SIZE = 76;
5bb37216 382
04227efc
VZ
383 // always try the new one first
384 static DWORD gs_ofStructSize = wxOPENFILENAME_V5_SIZE;
385#endif // __WXWINCE__ || __WIN64__/!...
5bb37216 386
fe048d77
VZ
387static bool ShowCommFileDialog(OPENFILENAME *of, long style)
388{
389 DWORD errCode;
390 bool success = DoShowCommFileDialog(of, style, &errCode);
391
392#ifdef wxTRY_SMALLER_OPENFILENAME
393 // the system might be too old to support the new version file dialog
394 // boxes, try with the old size
395 if ( !success && errCode == CDERR_STRUCTSIZE &&
396 of->lStructSize != wxOPENFILENAME_V4_SIZE )
397 {
398 of->lStructSize = wxOPENFILENAME_V4_SIZE;
399
400 success = DoShowCommFileDialog(of, style, &errCode);
401
402 if ( success || !errCode )
403 {
404 // use this struct size for subsequent dialogs
405 gs_ofStructSize = of->lStructSize;
406 }
407 }
408#endif // wxTRY_SMALLER_OPENFILENAME
409
d4380371
VZ
410 if ( !success &&
411 // FNERR_INVALIDFILENAME is not defined under CE (besides we don't
412 // use CommDlgExtendedError() there anyhow)
413#ifndef __WXWINCE__
414 errCode == FNERR_INVALIDFILENAME &&
415#endif // !__WXWINCE__
416 of->lpstrFile[0] )
fe048d77
VZ
417 {
418 // this can happen if the default file name is invalid, try without it
419 // now
9a83f860 420 of->lpstrFile[0] = wxT('\0');
fe048d77
VZ
421 success = DoShowCommFileDialog(of, style, &errCode);
422 }
423
424 if ( !success )
425 {
426 // common dialog failed - why?
427 if ( errCode != 0 )
428 {
429 wxLogError(_("File dialog failed with error code %0lx."), errCode);
430 }
431 //else: it was just cancelled
432
433 return false;
434 }
435
436 return true;
437}
438
d6dae1b4 439#ifndef __WXWINCE__
6fa6d659
VZ
440void wxFileDialog::MSWOnInitDialogHook(WXHWND hwnd)
441{
442 SetHWND(hwnd);
443
444 CreateExtraControl();
445
446 SetHWND(NULL);
447}
d6dae1b4 448#endif // __WXWINCE__
6fa6d659 449
c61f4f6d 450int wxFileDialog::ShowModal()
2bda0e17 451{
1f2f0331
VZ
452 HWND hWnd = 0;
453 if (m_parent) hWnd = (HWND) m_parent->GetHWND();
f6bcfd97
BP
454 if (!hWnd && wxTheApp->GetTopWindow())
455 hWnd = (HWND) wxTheApp->GetTopWindow()->GetHWND();
2bda0e17 456
f6bcfd97
BP
457 static wxChar fileNameBuffer [ wxMAXPATH ]; // the file-name
458 wxChar titleBuffer [ wxMAXFILE+1+wxMAXEXT ]; // the file-name, without path
2bda0e17 459
223d09f6
KB
460 *fileNameBuffer = wxT('\0');
461 *titleBuffer = wxT('\0');
2bda0e17 462
21416306 463 long msw_flags = OFN_HIDEREADONLY;
21416306 464
b014db05 465 if ( HasFdFlag(wxFD_FILE_MUST_EXIST) )
1f2f0331 466 msw_flags |= OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
0b11099d
VZ
467 /*
468 If the window has been moved the programmer is probably
469 trying to center or position it. Thus we set the callback
470 or hook function so that we can actually adjust the position.
471 Without moving or centering the dlg, it will just stay
472 in the upper left of the frame, it does not center
5bb37216 473 automatically.
0b11099d 474 */
6fa6d659 475 if (m_bMovedWindow || HasExtraControlCreator()) // we need these flags.
503528dc 476 {
30374272 477 ChangeExceptionPolicy();
503528dc
JS
478 msw_flags |= OFN_EXPLORER|OFN_ENABLEHOOK;
479#ifndef __WXWINCE__
480 msw_flags |= OFN_ENABLESIZING;
481#endif
482 }
6e8aa701 483
30374272
DS
484 wxON_BLOCK_EXIT0(RestoreExceptionPolicy);
485
b014db05 486 if ( HasFdFlag(wxFD_MULTIPLE) )
6e8aa701
VZ
487 {
488 // OFN_EXPLORER must always be specified with OFN_ALLOWMULTISELECT
489 msw_flags |= OFN_EXPLORER | OFN_ALLOWMULTISELECT;
490 }
491
e031f1df 492 // if wxFD_CHANGE_DIR flag is not given we shouldn't change the CWD which the
af1f0a76
VZ
493 // standard dialog does by default (notice that under NT it does it anyhow,
494 // OFN_NOCHANGEDIR or not, see below)
b014db05 495 if ( !HasFdFlag(wxFD_CHANGE_DIR) )
6e8aa701
VZ
496 {
497 msw_flags |= OFN_NOCHANGEDIR;
498 }
ac95e671 499
b014db05 500 if ( HasFdFlag(wxFD_OVERWRITE_PROMPT) )
99d1b93d
VZ
501 {
502 msw_flags |= OFN_OVERWRITEPROMPT;
503 }
ac95e671 504
5bb37216 505 wxOPENFILENAME of;
f6bcfd97
BP
506 wxZeroMemory(of);
507
5bb37216 508 of.lStructSize = gs_ofStructSize;
e15e548b 509 of.hwndOwner = hWnd;
017dc06b 510 of.lpstrTitle = m_message.t_str();
e15e548b 511 of.lpstrFileTitle = titleBuffer;
5bb37216 512 of.nMaxFileTitle = wxMAXFILE + 1 + wxMAXEXT;
2bda0e17 513
6fa6d659
VZ
514#ifndef __WXWINCE__
515 GlobalPtr hgbl;
516 if ( HasExtraControlCreator() )
517 {
518 msw_flags |= OFN_ENABLETEMPLATEHANDLE;
519
520 hgbl.Init(256, GMEM_ZEROINIT);
521 GlobalPtrLock hgblLock(hgbl);
522 LPDLGTEMPLATE lpdt = static_cast<LPDLGTEMPLATE>(hgblLock.Get());
523
524 // Define a dialog box.
525
526 lpdt->style = DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS;
527 lpdt->cdit = 0; // Number of controls
528 lpdt->x = 0;
529 lpdt->y = 0;
530
c10c791b
VZ
531 // convert the size of the extra controls to the dialog units
532 const wxSize extraSize = GetExtraControlSize();
533 const LONG baseUnits = ::GetDialogBaseUnits();
534 lpdt->cx = ::MulDiv(extraSize.x, 4, LOWORD(baseUnits));
535 lpdt->cy = ::MulDiv(extraSize.y, 8, HIWORD(baseUnits));
6fa6d659
VZ
536
537 // after the DLGTEMPLATE there are 3 additional WORDs for dialog menu,
538 // class and title, all three set to zeros.
539
540 of.hInstance = (HINSTANCE)lpdt;
541 }
542#endif // __WXWINCE__
543
0bc9b25e 544 // Convert forward slashes to backslashes (file selector doesn't like
99d1b93d
VZ
545 // forward slashes) and also squeeze multiple consecutive slashes into one
546 // as it doesn't like two backslashes in a row neither
0627d091 547
cbe874bd
WS
548 wxString dir;
549 size_t i, len = m_dir.length();
99d1b93d 550 dir.reserve(len);
0627d091 551 for ( i = 0; i < len; i++ )
99d1b93d
VZ
552 {
553 wxChar ch = m_dir[i];
554 switch ( ch )
555 {
9a83f860 556 case wxT('/'):
99d1b93d 557 // convert to backslash
9a83f860 558 ch = wxT('\\');
99d1b93d
VZ
559
560 // fall through
0bc9b25e 561
9a83f860 562 case wxT('\\'):
99d1b93d
VZ
563 while ( i < len - 1 )
564 {
565 wxChar chNext = m_dir[i + 1];
9a83f860 566 if ( chNext != wxT('\\') && chNext != wxT('/') )
99d1b93d
VZ
567 break;
568
04d93c3a
CE
569 // ignore the next one, unless it is at the start of a UNC path
570 if (i > 0)
571 i++;
572 else
0b11099d 573 break;
99d1b93d
VZ
574 }
575 // fall through
576
577 default:
578 // normal char
579 dir += ch;
580 }
581 }
582
583 of.lpstrInitialDir = dir.c_str();
2bda0e17 584
e15e548b 585 of.Flags = msw_flags;
0b11099d 586 of.lpfnHook = wxFileDialogHookFunction;
0a7b0229 587 of.lCustData = (LPARAM)this;
2bda0e17 588
daf32463 589 wxArrayString wildDescriptions, wildFilters;
2bda0e17 590
daf32463 591 size_t items = wxParseCommonDialogsFilter(m_wildCard, wildDescriptions, wildFilters);
2bda0e17 592
9a83f860 593 wxASSERT_MSG( items > 0 , wxT("empty wildcard list") );
2bda0e17 594
1f2f0331 595 wxString filterBuffer;
2bda0e17 596
daf32463
WS
597 for (i = 0; i < items ; i++)
598 {
599 filterBuffer += wildDescriptions[i];
600 filterBuffer += wxT("|");
601 filterBuffer += wildFilters[i];
602 filterBuffer += wxT("|");
574c0bbf
JS
603 }
604
574c0bbf 605 // Replace | with \0
e031f1df 606 for (i = 0; i < filterBuffer.length(); i++ ) {
223d09f6
KB
607 if ( filterBuffer.GetChar(i) == wxT('|') ) {
608 filterBuffer[i] = wxT('\0');
e15e548b
VZ
609 }
610 }
2bda0e17 611
017dc06b 612 of.lpstrFilter = filterBuffer.t_str();
cc42eb7a 613 of.nFilterIndex = m_filterIndex + 1;
2bda0e17
KB
614
615 //=== Setting defaultFileName >>=========================================
616
64accea5 617 wxStrlcpy(fileNameBuffer, m_fileName.c_str(), WXSIZEOF(fileNameBuffer));
2bda0e17 618
e15e548b 619 of.lpstrFile = fileNameBuffer; // holds returned filename
f6bcfd97 620 of.nMaxFile = wxMAXPATH;
2bda0e17 621
90bddb85 622 // we must set the default extension because otherwise Windows would check
e031f1df 623 // for the existing of a wrong file with wxFD_OVERWRITE_PROMPT (i.e. if the
90bddb85
VZ
624 // user types "foo" and the default extension is ".bar" we should force it
625 // to check for "foo.bar" existence and not "foo")
626 wxString defextBuffer; // we need it to be alive until GetSaveFileName()!
b014db05 627 if (HasFdFlag(wxFD_SAVE))
90bddb85 628 {
017dc06b 629 const wxChar* extension = filterBuffer.t_str();
90bddb85
VZ
630 int maxFilter = (int)(of.nFilterIndex*2L) - 1;
631
632 for( int i = 0; i < maxFilter; i++ ) // get extension
633 extension = extension + wxStrlen( extension ) + 1;
634
635 // use dummy name a to avoid assert in AppendExtension
636 defextBuffer = AppendExtension(wxT("a"), extension);
637 if (defextBuffer.StartsWith(wxT("a.")))
638 {
026ff75b 639 defextBuffer = defextBuffer.Mid(2); // remove "a."
90bddb85
VZ
640 of.lpstrDefExt = defextBuffer.c_str();
641 }
642 }
0b11099d 643
af1f0a76
VZ
644 // store off before the standard windows dialog can possibly change it
645 const wxString cwdOrig = wxGetCwd();
646
2bda0e17
KB
647 //== Execute FileDialog >>=================================================
648
fe048d77
VZ
649 if ( !ShowCommFileDialog(&of, m_windowStyle) )
650 return wxID_CANCEL;
2bda0e17 651
fe048d77
VZ
652 // GetOpenFileName will always change the current working directory on
653 // (according to MSDN) "Windows NT 4.0/2000/XP" because the flag
654 // OFN_NOCHANGEDIR has no effect. If the user did not specify
655 // wxFD_CHANGE_DIR let's restore the current working directory to what it
656 // was before the dialog was shown.
657 if ( msw_flags & OFN_NOCHANGEDIR )
f6bcfd97 658 {
fe048d77 659 wxSetWorkingDirectory(cwdOrig);
f6bcfd97 660 }
c46c1fb8 661
fe048d77 662 m_fileNames.Empty();
c61f4f6d 663
fe048d77 664 if ( ( HasFdFlag(wxFD_MULTIPLE) ) &&
c61f4f6d 665#if defined(OFN_EXPLORER)
fe048d77 666 ( fileNameBuffer[of.nFileOffset-1] == wxT('\0') )
c61f4f6d 667#else
fe048d77 668 ( fileNameBuffer[of.nFileOffset-1] == wxT(' ') )
c61f4f6d 669#endif // OFN_EXPLORER
fe048d77
VZ
670 )
671 {
c61f4f6d 672#if defined(OFN_EXPLORER)
fe048d77
VZ
673 m_dir = fileNameBuffer;
674 i = of.nFileOffset;
675 m_fileName = &fileNameBuffer[i];
676 m_fileNames.Add(m_fileName);
677 i += m_fileName.length() + 1;
c61f4f6d 678
fe048d77
VZ
679 while (fileNameBuffer[i] != wxT('\0'))
680 {
681 m_fileNames.Add(&fileNameBuffer[i]);
682 i += wxStrlen(&fileNameBuffer[i]) + 1;
683 }
c61f4f6d 684#else
9a83f860 685 wxStringTokenizer toke(fileNameBuffer, wxT(" \t\r\n"));
fe048d77
VZ
686 m_dir = toke.GetNextToken();
687 m_fileName = toke.GetNextToken();
688 m_fileNames.Add(m_fileName);
c61f4f6d 689
fe048d77
VZ
690 while (toke.HasMoreTokens())
691 m_fileNames.Add(toke.GetNextToken());
c61f4f6d
VZ
692#endif // OFN_EXPLORER
693
fe048d77 694 wxString dir(m_dir);
9a83f860
VZ
695 if ( m_dir.Last() != wxT('\\') )
696 dir += wxT('\\');
2bda0e17 697
fe048d77
VZ
698 m_path = dir + m_fileName;
699 m_filterIndex = (int)of.nFilterIndex - 1;
700 }
701 else
702 {
703 //=== Adding the correct extension >>=================================
2bda0e17 704
fe048d77 705 m_filterIndex = (int)of.nFilterIndex - 1;
2bda0e17 706
fe048d77
VZ
707 if ( !of.nFileExtension ||
708 (of.nFileExtension && fileNameBuffer[of.nFileExtension] == wxT('\0')) )
709 {
710 // User has typed a filename without an extension:
017dc06b 711 const wxChar* extension = filterBuffer.t_str();
fe048d77 712 int maxFilter = (int)(of.nFilterIndex*2L) - 1;
a039ccbf 713
fe048d77
VZ
714 for( int i = 0; i < maxFilter; i++ ) // get extension
715 extension = extension + wxStrlen( extension ) + 1;
2bda0e17 716
fe048d77 717 m_fileName = AppendExtension(fileNameBuffer, extension);
e408bf52 718 wxStrlcpy(fileNameBuffer, m_fileName.c_str(), WXSIZEOF(fileNameBuffer));
c61f4f6d 719 }
fe048d77
VZ
720
721 m_path = fileNameBuffer;
722 m_fileName = wxFileNameFromPath(fileNameBuffer);
723 m_fileNames.Add(m_fileName);
724 m_dir = wxPathOnly(fileNameBuffer);
7cc98b3e 725 }
2bda0e17 726
fe048d77 727 return wxID_OK;
2bda0e17
KB
728
729}
730
3180bc0e 731#endif // wxUSE_FILEDLG && !(__SMARTPHONE__ && __WXWINCE__)