1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/filedlg.cpp
3 // Purpose: wxFileDialog
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "filedlg.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
31 #if wxUSE_FILEDLG && !(defined(__SMARTPHONE__) && defined(__WXWINCE__))
35 #include "wx/msgdlg.h"
36 #include "wx/filedlg.h"
37 #include "wx/filefn.h"
43 #include "wx/msw/private.h"
45 #if !defined(__WIN32__) || defined(__WXWINCE__)
52 #include "wx/filename.h"
53 #include "wx/tokenzr.h"
56 #include "wx/msw/missing.h"
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
63 # define wxMAXPATH 65534
65 # define wxMAXPATH 1024
68 # define wxMAXFILE 1024
72 // ----------------------------------------------------------------------------
74 // ----------------------------------------------------------------------------
76 // standard dialog size
77 static wxRect
gs_rectDialog(0, 0, 428, 266);
79 // ============================================================================
81 // ============================================================================
83 IMPLEMENT_CLASS(wxFileDialog
, wxFileDialogBase
)
85 // ----------------------------------------------------------------------------
86 // hook function for moving the dialog
87 // ----------------------------------------------------------------------------
90 wxFileDialogHookFunction(HWND hDlg
,
92 WPARAM
WXUNUSED(wParam
),
96 hwndDialog
= ::GetParent( hDlg
);
102 GetWindowRect( hwndDialog
, & dlgRect
);
103 gs_rectDialog
.x
= dlgRect
.left
;
104 gs_rectDialog
.y
= dlgRect
.top
;
105 gs_rectDialog
.width
= dlgRect
.right
- dlgRect
.left
;
106 gs_rectDialog
.height
= dlgRect
.bottom
- dlgRect
.top
;
112 OFNOTIFY
* pNotifyCode
;
113 pNotifyCode
= (LPOFNOTIFY
) lParam
;
114 if (CDN_INITDONE
== (pNotifyCode
->hdr
).code
)
116 SetWindowPos( hwndDialog
, HWND_TOP
,
120 gs_rectDialog
.height
,
121 SWP_NOZORDER
|SWP_NOSIZE
);
127 // do the default processing
131 // ----------------------------------------------------------------------------
133 // ----------------------------------------------------------------------------
135 wxFileDialog::wxFileDialog(wxWindow
*parent
,
136 const wxString
& message
,
137 const wxString
& defaultDir
,
138 const wxString
& defaultFileName
,
139 const wxString
& wildCard
,
142 : wxFileDialogBase(parent
, message
, defaultDir
, defaultFileName
,
143 wildCard
, style
, pos
)
146 if ( ( m_dialogStyle
& wxMULTIPLE
) && ( m_dialogStyle
& wxSAVE
) )
147 m_dialogStyle
&= ~wxMULTIPLE
;
149 m_bMovedWindow
= false;
151 // Must set to zero, otherwise the wx routines won't size the window
152 // the second time you call the file dialog, because it thinks it is
153 // already at the requested size.. (when centering)
158 void wxFileDialog::GetPaths(wxArrayString
& paths
) const
163 if ( m_dir
.Last() != _T('\\') )
166 size_t count
= m_fileNames
.GetCount();
167 for ( size_t n
= 0; n
< count
; n
++ )
169 if (wxFileName(m_fileNames
[n
]).IsAbsolute())
170 paths
.Add(m_fileNames
[n
]);
172 paths
.Add(dir
+ m_fileNames
[n
]);
176 void wxFileDialog::GetFilenames(wxArrayString
& files
) const
181 void wxFileDialog::SetPath(const wxString
& path
)
184 wxSplitPath(path
, &m_dir
, &m_fileName
, &ext
);
186 m_fileName
<< _T('.') << ext
;
189 void wxFileDialog::DoGetPosition( int *x
, int *y
) const
191 *x
= gs_rectDialog
.x
;
192 *y
= gs_rectDialog
.y
;
196 void wxFileDialog::DoGetSize(int *width
, int *height
) const
198 *width
= gs_rectDialog
.width
;
199 *height
= gs_rectDialog
.height
;
202 void wxFileDialog::DoMoveWindow(int x
, int y
, int WXUNUSED(width
), int WXUNUSED(height
))
204 m_bMovedWindow
= true;
210 The width and height can not be set by the programmer
211 its just not possible. But the program can get the
212 size of the Dlg after it has been shown, in case they need
217 int wxFileDialog::ShowModal()
220 if (m_parent
) hWnd
= (HWND
) m_parent
->GetHWND();
221 if (!hWnd
&& wxTheApp
->GetTopWindow())
222 hWnd
= (HWND
) wxTheApp
->GetTopWindow()->GetHWND();
224 static wxChar fileNameBuffer
[ wxMAXPATH
]; // the file-name
225 wxChar titleBuffer
[ wxMAXFILE
+1+wxMAXEXT
]; // the file-name, without path
227 *fileNameBuffer
= wxT('\0');
228 *titleBuffer
= wxT('\0');
230 #if WXWIN_COMPATIBILITY_2_4
232 if ( (m_dialogStyle
& wxHIDE_READONLY
) || (m_dialogStyle
& wxSAVE
) )
233 msw_flags
|= OFN_HIDEREADONLY
;
235 long msw_flags
= OFN_HIDEREADONLY
;
238 if ( m_dialogStyle
& wxFILE_MUST_EXIST
)
239 msw_flags
|= OFN_PATHMUSTEXIST
| OFN_FILEMUSTEXIST
;
241 If the window has been moved the programmer is probably
242 trying to center or position it. Thus we set the callback
243 or hook function so that we can actually adjust the position.
244 Without moving or centering the dlg, it will just stay
245 in the upper left of the frame, it does not center
246 automatically.. One additional note, when the hook is
247 enabled, the PLACES BAR in the dlg (shown on later versions
248 of windows (2000 and XP) will automatically be turned off
249 according to the MSDN docs. This is normal. If the
250 programmer needs the PLACES BAR (left side of dlg) they
251 just shouldn't move or center the dlg.
253 if (m_bMovedWindow
) // we need these flags.
255 msw_flags
|= OFN_EXPLORER
|OFN_ENABLEHOOK
;
257 msw_flags
|= OFN_ENABLESIZING
;
261 if (m_dialogStyle
& wxMULTIPLE
)
263 // OFN_EXPLORER must always be specified with OFN_ALLOWMULTISELECT
264 msw_flags
|= OFN_EXPLORER
| OFN_ALLOWMULTISELECT
;
267 // if wxCHANGE_DIR flag is not given we shouldn't change the CWD which the
268 // standard dialog does by default
269 if ( !(m_dialogStyle
& wxCHANGE_DIR
) )
271 msw_flags
|= OFN_NOCHANGEDIR
;
274 if ( m_dialogStyle
& wxOVERWRITE_PROMPT
)
276 msw_flags
|= OFN_OVERWRITEPROMPT
;
282 // the OPENFILENAME struct has been extended in newer version of
283 // comcdlg32.dll, but as we don't use the extended fields anyhow, set
284 // the struct size to the old value - otherwise, the programs compiled
285 // with new headers will not work with the old libraries
286 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
287 of
.lStructSize
= sizeof(OPENFILENAME
) -
288 (sizeof(void *) + 2*sizeof(DWORD
));
290 of
.lStructSize
= sizeof(OPENFILENAME
);
294 of
.lpstrTitle
= WXSTRINGCAST m_message
;
295 of
.lpstrFileTitle
= titleBuffer
;
296 of
.nMaxFileTitle
= wxMAXFILE
+ 1 + wxMAXEXT
; // Windows 3.0 and 3.1
298 // Convert forward slashes to backslashes (file selector doesn't like
299 // forward slashes) and also squeeze multiple consecutive slashes into one
300 // as it doesn't like two backslashes in a row neither
303 size_t i
, len
= m_dir
.length();
305 for ( i
= 0; i
< len
; i
++ )
307 wxChar ch
= m_dir
[i
];
311 // convert to backslash
317 while ( i
< len
- 1 )
319 wxChar chNext
= m_dir
[i
+ 1];
320 if ( chNext
!= _T('\\') && chNext
!= _T('/') )
323 // ignore the next one, unless it is at the start of a UNC path
337 of
.lpstrInitialDir
= dir
.c_str();
339 of
.Flags
= msw_flags
;
340 of
.lpfnHook
= wxFileDialogHookFunction
;
342 wxArrayString wildDescriptions
, wildFilters
;
344 size_t items
= wxParseCommonDialogsFilter(m_wildCard
, wildDescriptions
, wildFilters
);
346 wxASSERT_MSG( items
> 0 , _T("empty wildcard list") );
348 wxString filterBuffer
;
350 for (i
= 0; i
< items
; i
++)
352 filterBuffer
+= wildDescriptions
[i
];
353 filterBuffer
+= wxT("|");
354 filterBuffer
+= wildFilters
[i
];
355 filterBuffer
+= wxT("|");
359 for (i
= 0; i
< filterBuffer
.Len(); i
++ ) {
360 if ( filterBuffer
.GetChar(i
) == wxT('|') ) {
361 filterBuffer
[i
] = wxT('\0');
365 of
.lpstrFilter
= (LPTSTR
)filterBuffer
.c_str();
366 of
.nFilterIndex
= m_filterIndex
+ 1;
368 //=== Setting defaultFileName >>=========================================
370 wxStrncpy( fileNameBuffer
, (const wxChar
*)m_fileName
, wxMAXPATH
-1 );
371 fileNameBuffer
[ wxMAXPATH
-1 ] = wxT('\0');
373 of
.lpstrFile
= fileNameBuffer
; // holds returned filename
374 of
.nMaxFile
= wxMAXPATH
;
376 // we must set the default extension because otherwise Windows would check
377 // for the existing of a wrong file with wxOVERWRITE_PROMPT (i.e. if the
378 // user types "foo" and the default extension is ".bar" we should force it
379 // to check for "foo.bar" existence and not "foo")
380 wxString defextBuffer
; // we need it to be alive until GetSaveFileName()!
381 if (m_dialogStyle
& wxSAVE
)
383 const wxChar
* extension
= filterBuffer
;
384 int maxFilter
= (int)(of
.nFilterIndex
*2L) - 1;
386 for( int i
= 0; i
< maxFilter
; i
++ ) // get extension
387 extension
= extension
+ wxStrlen( extension
) + 1;
389 // use dummy name a to avoid assert in AppendExtension
390 defextBuffer
= AppendExtension(wxT("a"), extension
);
391 if (defextBuffer
.StartsWith(wxT("a.")))
394 of
.lpstrDefExt
= defextBuffer
.c_str();
398 //== Execute FileDialog >>=================================================
400 bool success
= (m_dialogStyle
& wxSAVE
? GetSaveFileName(&of
)
401 : GetOpenFileName(&of
)) != 0;
403 DWORD errCode
= CommDlgExtendedError();
406 if (!success
&& (errCode
== CDERR_STRUCTSIZE
))
408 // The struct size has changed so try a smaller or bigger size
410 int oldStructSize
= of
.lStructSize
;
411 of
.lStructSize
= oldStructSize
- (sizeof(void *) + 2*sizeof(DWORD
));
412 success
= (m_dialogStyle
& wxSAVE
) ? (GetSaveFileName(&of
) != 0)
413 : (GetOpenFileName(&of
) != 0);
414 errCode
= CommDlgExtendedError();
416 if (!success
&& (errCode
== CDERR_STRUCTSIZE
))
418 of
.lStructSize
= oldStructSize
+ (sizeof(void *) + 2*sizeof(DWORD
));
419 success
= (m_dialogStyle
& wxSAVE
) ? (GetSaveFileName(&of
) != 0)
420 : (GetOpenFileName(&of
) != 0);
429 if ( ( m_dialogStyle
& wxMULTIPLE
) &&
430 #if defined(OFN_EXPLORER)
431 ( fileNameBuffer
[of
.nFileOffset
-1] == wxT('\0') )
433 ( fileNameBuffer
[of
.nFileOffset
-1] == wxT(' ') )
434 #endif // OFN_EXPLORER
437 #if defined(OFN_EXPLORER)
438 m_dir
= fileNameBuffer
;
440 m_fileName
= &fileNameBuffer
[i
];
441 m_fileNames
.Add(m_fileName
);
442 i
+= m_fileName
.Len() + 1;
444 while (fileNameBuffer
[i
] != wxT('\0'))
446 m_fileNames
.Add(&fileNameBuffer
[i
]);
447 i
+= wxStrlen(&fileNameBuffer
[i
]) + 1;
450 wxStringTokenizer
toke(fileNameBuffer
, _T(" \t\r\n"));
451 m_dir
= toke
.GetNextToken();
452 m_fileName
= toke
.GetNextToken();
453 m_fileNames
.Add(m_fileName
);
455 while (toke
.HasMoreTokens())
456 m_fileNames
.Add(toke
.GetNextToken());
457 #endif // OFN_EXPLORER
460 if ( m_dir
.Last() != _T('\\') )
463 m_path
= dir
+ m_fileName
;
464 m_filterIndex
= (int)of
.nFilterIndex
- 1;
468 //=== Adding the correct extension >>=================================
470 m_filterIndex
= (int)of
.nFilterIndex
- 1;
472 if ( !of
.nFileExtension
||
473 (of
.nFileExtension
&& fileNameBuffer
[of
.nFileExtension
] == wxT('\0')) )
475 // User has typed a filename without an extension:
476 const wxChar
* extension
= filterBuffer
;
477 int maxFilter
= (int)(of
.nFilterIndex
*2L) - 1;
479 for( int i
= 0; i
< maxFilter
; i
++ ) // get extension
480 extension
= extension
+ wxStrlen( extension
) + 1;
482 m_fileName
= AppendExtension(fileNameBuffer
, extension
);
483 wxStrncpy(fileNameBuffer
, m_fileName
.c_str(), wxMin(m_fileName
.Len(), wxMAXPATH
-1));
484 fileNameBuffer
[wxMin(m_fileName
.Len(), wxMAXPATH
-1)] = wxT('\0');
487 m_path
= fileNameBuffer
;
488 m_fileName
= wxFileNameFromPath(fileNameBuffer
);
489 m_fileNames
.Add(m_fileName
);
490 m_dir
= wxPathOnly(fileNameBuffer
);
495 // common dialog failed - why?
497 DWORD dwErr
= CommDlgExtendedError();
500 // this msg is only for developers
501 wxLogError(wxT("Common dialog failed with error code %0lx."),
504 //else: it was just cancelled
508 return success
? wxID_OK
: wxID_CANCEL
;
512 #endif // wxUSE_FILEDLG && !(__SMARTPHONE__ && __WXWINCE__)