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 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #if wxUSE_FILEDLG && !(defined(__SMARTPHONE__) && defined(__WXWINCE__))
31 #include "wx/msgdlg.h"
32 #include "wx/filedlg.h"
33 #include "wx/filefn.h"
39 #include "wx/msw/wrapcdlg.h"
44 #include "wx/filename.h"
45 #include "wx/tokenzr.h"
48 #include "wx/msw/missing.h"
50 // ----------------------------------------------------------------------------
52 // ----------------------------------------------------------------------------
55 # define wxMAXPATH 65534
57 # define wxMAXPATH 1024
60 # define wxMAXFILE 1024
64 // ----------------------------------------------------------------------------
66 // ----------------------------------------------------------------------------
68 // standard dialog size
69 static wxRect
gs_rectDialog(0, 0, 428, 266);
71 // ============================================================================
73 // ============================================================================
75 IMPLEMENT_CLASS(wxFileDialog
, wxFileDialogBase
)
77 // ----------------------------------------------------------------------------
78 // hook function for moving the dialog
79 // ----------------------------------------------------------------------------
82 wxFileDialogHookFunction(HWND hDlg
,
84 WPARAM
WXUNUSED(wParam
),
88 hwndDialog
= ::GetParent( hDlg
);
94 GetWindowRect( hwndDialog
, & dlgRect
);
95 gs_rectDialog
.x
= dlgRect
.left
;
96 gs_rectDialog
.y
= dlgRect
.top
;
97 gs_rectDialog
.width
= dlgRect
.right
- dlgRect
.left
;
98 gs_rectDialog
.height
= dlgRect
.bottom
- dlgRect
.top
;
104 OFNOTIFY
* pNotifyCode
;
105 pNotifyCode
= (LPOFNOTIFY
) lParam
;
106 if (CDN_INITDONE
== (pNotifyCode
->hdr
).code
)
108 SetWindowPos( hwndDialog
, HWND_TOP
,
112 gs_rectDialog
.height
,
113 SWP_NOZORDER
|SWP_NOSIZE
);
119 // do the default processing
123 // ----------------------------------------------------------------------------
125 // ----------------------------------------------------------------------------
127 wxFileDialog::wxFileDialog(wxWindow
*parent
,
128 const wxString
& message
,
129 const wxString
& defaultDir
,
130 const wxString
& defaultFileName
,
131 const wxString
& wildCard
,
134 : wxFileDialogBase(parent
, message
, defaultDir
, defaultFileName
,
135 wildCard
, style
, pos
)
138 if ( ( m_dialogStyle
& wxMULTIPLE
) && ( m_dialogStyle
& wxSAVE
) )
139 m_dialogStyle
&= ~wxMULTIPLE
;
141 m_bMovedWindow
= false;
143 // Must set to zero, otherwise the wx routines won't size the window
144 // the second time you call the file dialog, because it thinks it is
145 // already at the requested size.. (when centering)
150 void wxFileDialog::GetPaths(wxArrayString
& paths
) const
155 if ( m_dir
.Last() != _T('\\') )
158 size_t count
= m_fileNames
.GetCount();
159 for ( size_t n
= 0; n
< count
; n
++ )
161 if (wxFileName(m_fileNames
[n
]).IsAbsolute())
162 paths
.Add(m_fileNames
[n
]);
164 paths
.Add(dir
+ m_fileNames
[n
]);
168 void wxFileDialog::GetFilenames(wxArrayString
& files
) const
173 void wxFileDialog::SetPath(const wxString
& path
)
176 wxSplitPath(path
, &m_dir
, &m_fileName
, &ext
);
178 m_fileName
<< _T('.') << ext
;
181 void wxFileDialog::DoGetPosition( int *x
, int *y
) const
183 *x
= gs_rectDialog
.x
;
184 *y
= gs_rectDialog
.y
;
188 void wxFileDialog::DoGetSize(int *width
, int *height
) const
190 *width
= gs_rectDialog
.width
;
191 *height
= gs_rectDialog
.height
;
194 void wxFileDialog::DoMoveWindow(int x
, int y
, int WXUNUSED(width
), int WXUNUSED(height
))
196 m_bMovedWindow
= true;
202 The width and height can not be set by the programmer
203 its just not possible. But the program can get the
204 size of the Dlg after it has been shown, in case they need
209 int wxFileDialog::ShowModal()
212 if (m_parent
) hWnd
= (HWND
) m_parent
->GetHWND();
213 if (!hWnd
&& wxTheApp
->GetTopWindow())
214 hWnd
= (HWND
) wxTheApp
->GetTopWindow()->GetHWND();
216 static wxChar fileNameBuffer
[ wxMAXPATH
]; // the file-name
217 wxChar titleBuffer
[ wxMAXFILE
+1+wxMAXEXT
]; // the file-name, without path
219 *fileNameBuffer
= wxT('\0');
220 *titleBuffer
= wxT('\0');
222 #if WXWIN_COMPATIBILITY_2_4
224 if ( (m_dialogStyle
& wxHIDE_READONLY
) || (m_dialogStyle
& wxSAVE
) )
225 msw_flags
|= OFN_HIDEREADONLY
;
227 long msw_flags
= OFN_HIDEREADONLY
;
230 if ( m_dialogStyle
& wxFILE_MUST_EXIST
)
231 msw_flags
|= OFN_PATHMUSTEXIST
| OFN_FILEMUSTEXIST
;
233 If the window has been moved the programmer is probably
234 trying to center or position it. Thus we set the callback
235 or hook function so that we can actually adjust the position.
236 Without moving or centering the dlg, it will just stay
237 in the upper left of the frame, it does not center
238 automatically.. One additional note, when the hook is
239 enabled, the PLACES BAR in the dlg (shown on later versions
240 of windows (2000 and XP) will automatically be turned off
241 according to the MSDN docs. This is normal. If the
242 programmer needs the PLACES BAR (left side of dlg) they
243 just shouldn't move or center the dlg.
245 if (m_bMovedWindow
) // we need these flags.
247 msw_flags
|= OFN_EXPLORER
|OFN_ENABLEHOOK
;
249 msw_flags
|= OFN_ENABLESIZING
;
253 if (m_dialogStyle
& wxMULTIPLE
)
255 // OFN_EXPLORER must always be specified with OFN_ALLOWMULTISELECT
256 msw_flags
|= OFN_EXPLORER
| OFN_ALLOWMULTISELECT
;
259 // if wxCHANGE_DIR flag is not given we shouldn't change the CWD which the
260 // standard dialog does by default
261 if ( !(m_dialogStyle
& wxCHANGE_DIR
) )
263 msw_flags
|= OFN_NOCHANGEDIR
;
266 if ( m_dialogStyle
& wxOVERWRITE_PROMPT
)
268 msw_flags
|= OFN_OVERWRITEPROMPT
;
274 // the OPENFILENAME struct has been extended in newer version of
275 // comcdlg32.dll, but as we don't use the extended fields anyhow, set
276 // the struct size to the old value - otherwise, the programs compiled
277 // with new headers will not work with the old libraries
278 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
279 of
.lStructSize
= sizeof(OPENFILENAME
) -
280 (sizeof(void *) + 2*sizeof(DWORD
));
282 of
.lStructSize
= sizeof(OPENFILENAME
);
286 of
.lpstrTitle
= WXSTRINGCAST m_message
;
287 of
.lpstrFileTitle
= titleBuffer
;
288 of
.nMaxFileTitle
= wxMAXFILE
+ 1 + wxMAXEXT
; // Windows 3.0 and 3.1
290 // Convert forward slashes to backslashes (file selector doesn't like
291 // forward slashes) and also squeeze multiple consecutive slashes into one
292 // as it doesn't like two backslashes in a row neither
295 size_t i
, len
= m_dir
.length();
297 for ( i
= 0; i
< len
; i
++ )
299 wxChar ch
= m_dir
[i
];
303 // convert to backslash
309 while ( i
< len
- 1 )
311 wxChar chNext
= m_dir
[i
+ 1];
312 if ( chNext
!= _T('\\') && chNext
!= _T('/') )
315 // ignore the next one, unless it is at the start of a UNC path
329 of
.lpstrInitialDir
= dir
.c_str();
331 of
.Flags
= msw_flags
;
332 of
.lpfnHook
= wxFileDialogHookFunction
;
334 wxArrayString wildDescriptions
, wildFilters
;
336 size_t items
= wxParseCommonDialogsFilter(m_wildCard
, wildDescriptions
, wildFilters
);
338 wxASSERT_MSG( items
> 0 , _T("empty wildcard list") );
340 wxString filterBuffer
;
342 for (i
= 0; i
< items
; i
++)
344 filterBuffer
+= wildDescriptions
[i
];
345 filterBuffer
+= wxT("|");
346 filterBuffer
+= wildFilters
[i
];
347 filterBuffer
+= wxT("|");
351 for (i
= 0; i
< filterBuffer
.Len(); i
++ ) {
352 if ( filterBuffer
.GetChar(i
) == wxT('|') ) {
353 filterBuffer
[i
] = wxT('\0');
357 of
.lpstrFilter
= (LPTSTR
)filterBuffer
.c_str();
358 of
.nFilterIndex
= m_filterIndex
+ 1;
360 //=== Setting defaultFileName >>=========================================
362 wxStrncpy( fileNameBuffer
, (const wxChar
*)m_fileName
, wxMAXPATH
-1 );
363 fileNameBuffer
[ wxMAXPATH
-1 ] = wxT('\0');
365 of
.lpstrFile
= fileNameBuffer
; // holds returned filename
366 of
.nMaxFile
= wxMAXPATH
;
368 // we must set the default extension because otherwise Windows would check
369 // for the existing of a wrong file with wxOVERWRITE_PROMPT (i.e. if the
370 // user types "foo" and the default extension is ".bar" we should force it
371 // to check for "foo.bar" existence and not "foo")
372 wxString defextBuffer
; // we need it to be alive until GetSaveFileName()!
373 if (m_dialogStyle
& wxSAVE
)
375 const wxChar
* extension
= filterBuffer
;
376 int maxFilter
= (int)(of
.nFilterIndex
*2L) - 1;
378 for( int i
= 0; i
< maxFilter
; i
++ ) // get extension
379 extension
= extension
+ wxStrlen( extension
) + 1;
381 // use dummy name a to avoid assert in AppendExtension
382 defextBuffer
= AppendExtension(wxT("a"), extension
);
383 if (defextBuffer
.StartsWith(wxT("a.")))
386 of
.lpstrDefExt
= defextBuffer
.c_str();
390 //== Execute FileDialog >>=================================================
392 bool success
= (m_dialogStyle
& wxSAVE
? GetSaveFileName(&of
)
393 : GetOpenFileName(&of
)) != 0;
395 DWORD errCode
= CommDlgExtendedError();
398 if (!success
&& (errCode
== CDERR_STRUCTSIZE
))
400 // The struct size has changed so try a smaller or bigger size
402 int oldStructSize
= of
.lStructSize
;
403 of
.lStructSize
= oldStructSize
- (sizeof(void *) + 2*sizeof(DWORD
));
404 success
= (m_dialogStyle
& wxSAVE
) ? (GetSaveFileName(&of
) != 0)
405 : (GetOpenFileName(&of
) != 0);
406 errCode
= CommDlgExtendedError();
408 if (!success
&& (errCode
== CDERR_STRUCTSIZE
))
410 of
.lStructSize
= oldStructSize
+ (sizeof(void *) + 2*sizeof(DWORD
));
411 success
= (m_dialogStyle
& wxSAVE
) ? (GetSaveFileName(&of
) != 0)
412 : (GetOpenFileName(&of
) != 0);
421 if ( ( m_dialogStyle
& wxMULTIPLE
) &&
422 #if defined(OFN_EXPLORER)
423 ( fileNameBuffer
[of
.nFileOffset
-1] == wxT('\0') )
425 ( fileNameBuffer
[of
.nFileOffset
-1] == wxT(' ') )
426 #endif // OFN_EXPLORER
429 #if defined(OFN_EXPLORER)
430 m_dir
= fileNameBuffer
;
432 m_fileName
= &fileNameBuffer
[i
];
433 m_fileNames
.Add(m_fileName
);
434 i
+= m_fileName
.Len() + 1;
436 while (fileNameBuffer
[i
] != wxT('\0'))
438 m_fileNames
.Add(&fileNameBuffer
[i
]);
439 i
+= wxStrlen(&fileNameBuffer
[i
]) + 1;
442 wxStringTokenizer
toke(fileNameBuffer
, _T(" \t\r\n"));
443 m_dir
= toke
.GetNextToken();
444 m_fileName
= toke
.GetNextToken();
445 m_fileNames
.Add(m_fileName
);
447 while (toke
.HasMoreTokens())
448 m_fileNames
.Add(toke
.GetNextToken());
449 #endif // OFN_EXPLORER
452 if ( m_dir
.Last() != _T('\\') )
455 m_path
= dir
+ m_fileName
;
456 m_filterIndex
= (int)of
.nFilterIndex
- 1;
460 //=== Adding the correct extension >>=================================
462 m_filterIndex
= (int)of
.nFilterIndex
- 1;
464 if ( !of
.nFileExtension
||
465 (of
.nFileExtension
&& fileNameBuffer
[of
.nFileExtension
] == wxT('\0')) )
467 // User has typed a filename without an extension:
468 const wxChar
* extension
= filterBuffer
;
469 int maxFilter
= (int)(of
.nFilterIndex
*2L) - 1;
471 for( int i
= 0; i
< maxFilter
; i
++ ) // get extension
472 extension
= extension
+ wxStrlen( extension
) + 1;
474 m_fileName
= AppendExtension(fileNameBuffer
, extension
);
475 wxStrncpy(fileNameBuffer
, m_fileName
.c_str(), wxMin(m_fileName
.Len(), wxMAXPATH
-1));
476 fileNameBuffer
[wxMin(m_fileName
.Len(), wxMAXPATH
-1)] = wxT('\0');
479 m_path
= fileNameBuffer
;
480 m_fileName
= wxFileNameFromPath(fileNameBuffer
);
481 m_fileNames
.Add(m_fileName
);
482 m_dir
= wxPathOnly(fileNameBuffer
);
487 // common dialog failed - why?
489 DWORD dwErr
= CommDlgExtendedError();
492 // this msg is only for developers
493 wxLogError(wxT("Common dialog failed with error code %0lx."),
496 //else: it was just cancelled
500 return success
? wxID_OK
: wxID_CANCEL
;
504 #endif // wxUSE_FILEDLG && !(__SMARTPHONE__ && __WXWINCE__)