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/wrapcdlg.h"
48 #include "wx/filename.h"
49 #include "wx/tokenzr.h"
52 #include "wx/msw/missing.h"
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
59 # define wxMAXPATH 65534
61 # define wxMAXPATH 1024
64 # define wxMAXFILE 1024
68 // ----------------------------------------------------------------------------
70 // ----------------------------------------------------------------------------
72 // standard dialog size
73 static wxRect
gs_rectDialog(0, 0, 428, 266);
75 // ============================================================================
77 // ============================================================================
79 IMPLEMENT_CLASS(wxFileDialog
, wxFileDialogBase
)
81 // ----------------------------------------------------------------------------
82 // hook function for moving the dialog
83 // ----------------------------------------------------------------------------
86 wxFileDialogHookFunction(HWND hDlg
,
88 WPARAM
WXUNUSED(wParam
),
92 hwndDialog
= ::GetParent( hDlg
);
98 GetWindowRect( hwndDialog
, & dlgRect
);
99 gs_rectDialog
.x
= dlgRect
.left
;
100 gs_rectDialog
.y
= dlgRect
.top
;
101 gs_rectDialog
.width
= dlgRect
.right
- dlgRect
.left
;
102 gs_rectDialog
.height
= dlgRect
.bottom
- dlgRect
.top
;
108 OFNOTIFY
* pNotifyCode
;
109 pNotifyCode
= (LPOFNOTIFY
) lParam
;
110 if (CDN_INITDONE
== (pNotifyCode
->hdr
).code
)
112 SetWindowPos( hwndDialog
, HWND_TOP
,
116 gs_rectDialog
.height
,
117 SWP_NOZORDER
|SWP_NOSIZE
);
123 // do the default processing
127 // ----------------------------------------------------------------------------
129 // ----------------------------------------------------------------------------
131 wxFileDialog::wxFileDialog(wxWindow
*parent
,
132 const wxString
& message
,
133 const wxString
& defaultDir
,
134 const wxString
& defaultFileName
,
135 const wxString
& wildCard
,
138 : wxFileDialogBase(parent
, message
, defaultDir
, defaultFileName
,
139 wildCard
, style
, pos
)
142 if ( ( m_dialogStyle
& wxMULTIPLE
) && ( m_dialogStyle
& wxSAVE
) )
143 m_dialogStyle
&= ~wxMULTIPLE
;
145 m_bMovedWindow
= false;
147 // Must set to zero, otherwise the wx routines won't size the window
148 // the second time you call the file dialog, because it thinks it is
149 // already at the requested size.. (when centering)
154 void wxFileDialog::GetPaths(wxArrayString
& paths
) const
159 if ( m_dir
.Last() != _T('\\') )
162 size_t count
= m_fileNames
.GetCount();
163 for ( size_t n
= 0; n
< count
; n
++ )
165 if (wxFileName(m_fileNames
[n
]).IsAbsolute())
166 paths
.Add(m_fileNames
[n
]);
168 paths
.Add(dir
+ m_fileNames
[n
]);
172 void wxFileDialog::GetFilenames(wxArrayString
& files
) const
177 void wxFileDialog::SetPath(const wxString
& path
)
180 wxSplitPath(path
, &m_dir
, &m_fileName
, &ext
);
182 m_fileName
<< _T('.') << ext
;
185 void wxFileDialog::DoGetPosition( int *x
, int *y
) const
187 *x
= gs_rectDialog
.x
;
188 *y
= gs_rectDialog
.y
;
192 void wxFileDialog::DoGetSize(int *width
, int *height
) const
194 *width
= gs_rectDialog
.width
;
195 *height
= gs_rectDialog
.height
;
198 void wxFileDialog::DoMoveWindow(int x
, int y
, int WXUNUSED(width
), int WXUNUSED(height
))
200 m_bMovedWindow
= true;
206 The width and height can not be set by the programmer
207 its just not possible. But the program can get the
208 size of the Dlg after it has been shown, in case they need
213 int wxFileDialog::ShowModal()
216 if (m_parent
) hWnd
= (HWND
) m_parent
->GetHWND();
217 if (!hWnd
&& wxTheApp
->GetTopWindow())
218 hWnd
= (HWND
) wxTheApp
->GetTopWindow()->GetHWND();
220 static wxChar fileNameBuffer
[ wxMAXPATH
]; // the file-name
221 wxChar titleBuffer
[ wxMAXFILE
+1+wxMAXEXT
]; // the file-name, without path
223 *fileNameBuffer
= wxT('\0');
224 *titleBuffer
= wxT('\0');
226 #if WXWIN_COMPATIBILITY_2_4
228 if ( (m_dialogStyle
& wxHIDE_READONLY
) || (m_dialogStyle
& wxSAVE
) )
229 msw_flags
|= OFN_HIDEREADONLY
;
231 long msw_flags
= OFN_HIDEREADONLY
;
234 if ( m_dialogStyle
& wxFILE_MUST_EXIST
)
235 msw_flags
|= OFN_PATHMUSTEXIST
| OFN_FILEMUSTEXIST
;
237 If the window has been moved the programmer is probably
238 trying to center or position it. Thus we set the callback
239 or hook function so that we can actually adjust the position.
240 Without moving or centering the dlg, it will just stay
241 in the upper left of the frame, it does not center
242 automatically.. One additional note, when the hook is
243 enabled, the PLACES BAR in the dlg (shown on later versions
244 of windows (2000 and XP) will automatically be turned off
245 according to the MSDN docs. This is normal. If the
246 programmer needs the PLACES BAR (left side of dlg) they
247 just shouldn't move or center the dlg.
249 if (m_bMovedWindow
) // we need these flags.
251 msw_flags
|= OFN_EXPLORER
|OFN_ENABLEHOOK
;
253 msw_flags
|= OFN_ENABLESIZING
;
257 if (m_dialogStyle
& wxMULTIPLE
)
259 // OFN_EXPLORER must always be specified with OFN_ALLOWMULTISELECT
260 msw_flags
|= OFN_EXPLORER
| OFN_ALLOWMULTISELECT
;
263 // if wxCHANGE_DIR flag is not given we shouldn't change the CWD which the
264 // standard dialog does by default
265 if ( !(m_dialogStyle
& wxCHANGE_DIR
) )
267 msw_flags
|= OFN_NOCHANGEDIR
;
270 if ( m_dialogStyle
& wxOVERWRITE_PROMPT
)
272 msw_flags
|= OFN_OVERWRITEPROMPT
;
278 // the OPENFILENAME struct has been extended in newer version of
279 // comcdlg32.dll, but as we don't use the extended fields anyhow, set
280 // the struct size to the old value - otherwise, the programs compiled
281 // with new headers will not work with the old libraries
282 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
283 of
.lStructSize
= sizeof(OPENFILENAME
) -
284 (sizeof(void *) + 2*sizeof(DWORD
));
286 of
.lStructSize
= sizeof(OPENFILENAME
);
290 of
.lpstrTitle
= WXSTRINGCAST m_message
;
291 of
.lpstrFileTitle
= titleBuffer
;
292 of
.nMaxFileTitle
= wxMAXFILE
+ 1 + wxMAXEXT
; // Windows 3.0 and 3.1
294 // Convert forward slashes to backslashes (file selector doesn't like
295 // forward slashes) and also squeeze multiple consecutive slashes into one
296 // as it doesn't like two backslashes in a row neither
299 size_t i
, len
= m_dir
.length();
301 for ( i
= 0; i
< len
; i
++ )
303 wxChar ch
= m_dir
[i
];
307 // convert to backslash
313 while ( i
< len
- 1 )
315 wxChar chNext
= m_dir
[i
+ 1];
316 if ( chNext
!= _T('\\') && chNext
!= _T('/') )
319 // ignore the next one, unless it is at the start of a UNC path
333 of
.lpstrInitialDir
= dir
.c_str();
335 of
.Flags
= msw_flags
;
336 of
.lpfnHook
= wxFileDialogHookFunction
;
338 wxArrayString wildDescriptions
, wildFilters
;
340 size_t items
= wxParseCommonDialogsFilter(m_wildCard
, wildDescriptions
, wildFilters
);
342 wxASSERT_MSG( items
> 0 , _T("empty wildcard list") );
344 wxString filterBuffer
;
346 for (i
= 0; i
< items
; i
++)
348 filterBuffer
+= wildDescriptions
[i
];
349 filterBuffer
+= wxT("|");
350 filterBuffer
+= wildFilters
[i
];
351 filterBuffer
+= wxT("|");
355 for (i
= 0; i
< filterBuffer
.Len(); i
++ ) {
356 if ( filterBuffer
.GetChar(i
) == wxT('|') ) {
357 filterBuffer
[i
] = wxT('\0');
361 of
.lpstrFilter
= (LPTSTR
)filterBuffer
.c_str();
362 of
.nFilterIndex
= m_filterIndex
+ 1;
364 //=== Setting defaultFileName >>=========================================
366 wxStrncpy( fileNameBuffer
, (const wxChar
*)m_fileName
, wxMAXPATH
-1 );
367 fileNameBuffer
[ wxMAXPATH
-1 ] = wxT('\0');
369 of
.lpstrFile
= fileNameBuffer
; // holds returned filename
370 of
.nMaxFile
= wxMAXPATH
;
372 // we must set the default extension because otherwise Windows would check
373 // for the existing of a wrong file with wxOVERWRITE_PROMPT (i.e. if the
374 // user types "foo" and the default extension is ".bar" we should force it
375 // to check for "foo.bar" existence and not "foo")
376 wxString defextBuffer
; // we need it to be alive until GetSaveFileName()!
377 if (m_dialogStyle
& wxSAVE
)
379 const wxChar
* extension
= filterBuffer
;
380 int maxFilter
= (int)(of
.nFilterIndex
*2L) - 1;
382 for( int i
= 0; i
< maxFilter
; i
++ ) // get extension
383 extension
= extension
+ wxStrlen( extension
) + 1;
385 // use dummy name a to avoid assert in AppendExtension
386 defextBuffer
= AppendExtension(wxT("a"), extension
);
387 if (defextBuffer
.StartsWith(wxT("a.")))
390 of
.lpstrDefExt
= defextBuffer
.c_str();
394 //== Execute FileDialog >>=================================================
396 bool success
= (m_dialogStyle
& wxSAVE
? GetSaveFileName(&of
)
397 : GetOpenFileName(&of
)) != 0;
399 DWORD errCode
= CommDlgExtendedError();
402 if (!success
&& (errCode
== CDERR_STRUCTSIZE
))
404 // The struct size has changed so try a smaller or bigger size
406 int oldStructSize
= of
.lStructSize
;
407 of
.lStructSize
= oldStructSize
- (sizeof(void *) + 2*sizeof(DWORD
));
408 success
= (m_dialogStyle
& wxSAVE
) ? (GetSaveFileName(&of
) != 0)
409 : (GetOpenFileName(&of
) != 0);
410 errCode
= CommDlgExtendedError();
412 if (!success
&& (errCode
== CDERR_STRUCTSIZE
))
414 of
.lStructSize
= oldStructSize
+ (sizeof(void *) + 2*sizeof(DWORD
));
415 success
= (m_dialogStyle
& wxSAVE
) ? (GetSaveFileName(&of
) != 0)
416 : (GetOpenFileName(&of
) != 0);
425 if ( ( m_dialogStyle
& wxMULTIPLE
) &&
426 #if defined(OFN_EXPLORER)
427 ( fileNameBuffer
[of
.nFileOffset
-1] == wxT('\0') )
429 ( fileNameBuffer
[of
.nFileOffset
-1] == wxT(' ') )
430 #endif // OFN_EXPLORER
433 #if defined(OFN_EXPLORER)
434 m_dir
= fileNameBuffer
;
436 m_fileName
= &fileNameBuffer
[i
];
437 m_fileNames
.Add(m_fileName
);
438 i
+= m_fileName
.Len() + 1;
440 while (fileNameBuffer
[i
] != wxT('\0'))
442 m_fileNames
.Add(&fileNameBuffer
[i
]);
443 i
+= wxStrlen(&fileNameBuffer
[i
]) + 1;
446 wxStringTokenizer
toke(fileNameBuffer
, _T(" \t\r\n"));
447 m_dir
= toke
.GetNextToken();
448 m_fileName
= toke
.GetNextToken();
449 m_fileNames
.Add(m_fileName
);
451 while (toke
.HasMoreTokens())
452 m_fileNames
.Add(toke
.GetNextToken());
453 #endif // OFN_EXPLORER
456 if ( m_dir
.Last() != _T('\\') )
459 m_path
= dir
+ m_fileName
;
460 m_filterIndex
= (int)of
.nFilterIndex
- 1;
464 //=== Adding the correct extension >>=================================
466 m_filterIndex
= (int)of
.nFilterIndex
- 1;
468 if ( !of
.nFileExtension
||
469 (of
.nFileExtension
&& fileNameBuffer
[of
.nFileExtension
] == wxT('\0')) )
471 // User has typed a filename without an extension:
472 const wxChar
* extension
= filterBuffer
;
473 int maxFilter
= (int)(of
.nFilterIndex
*2L) - 1;
475 for( int i
= 0; i
< maxFilter
; i
++ ) // get extension
476 extension
= extension
+ wxStrlen( extension
) + 1;
478 m_fileName
= AppendExtension(fileNameBuffer
, extension
);
479 wxStrncpy(fileNameBuffer
, m_fileName
.c_str(), wxMin(m_fileName
.Len(), wxMAXPATH
-1));
480 fileNameBuffer
[wxMin(m_fileName
.Len(), wxMAXPATH
-1)] = wxT('\0');
483 m_path
= fileNameBuffer
;
484 m_fileName
= wxFileNameFromPath(fileNameBuffer
);
485 m_fileNames
.Add(m_fileName
);
486 m_dir
= wxPathOnly(fileNameBuffer
);
491 // common dialog failed - why?
493 DWORD dwErr
= CommDlgExtendedError();
496 // this msg is only for developers
497 wxLogError(wxT("Common dialog failed with error code %0lx."),
500 //else: it was just cancelled
504 return success
? wxID_OK
: wxID_CANCEL
;
508 #endif // wxUSE_FILEDLG && !(__SMARTPHONE__ && __WXWINCE__)