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__)
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__)
53 #include "wx/filename.h"
54 #include "wx/tokenzr.h"
57 #define OFN_EXPLORER 0x00080000
60 // ----------------------------------------------------------------------------
62 // ----------------------------------------------------------------------------
65 # define wxMAXPATH 65534
67 # define wxMAXPATH 1024
70 # define wxMAXFILE 1024
74 // ----------------------------------------------------------------------------
76 // ----------------------------------------------------------------------------
78 // standard dialog size
79 static wxRect
gs_rectDialog(0, 0, 428, 266);
81 // ============================================================================
83 // ============================================================================
85 IMPLEMENT_CLASS(wxFileDialog
, wxFileDialogBase
)
87 // ----------------------------------------------------------------------------
88 // hook function for moving the dialog
89 // ----------------------------------------------------------------------------
92 wxFileDialogHookFunction(HWND hDlg
,
94 WPARAM
WXUNUSED(wParam
),
98 hwndDialog
= ::GetParent( hDlg
);
104 GetWindowRect( hwndDialog
, & dlgRect
);
105 gs_rectDialog
.x
= dlgRect
.left
;
106 gs_rectDialog
.y
= dlgRect
.top
;
107 gs_rectDialog
.width
= dlgRect
.right
- dlgRect
.left
;
108 gs_rectDialog
.height
= dlgRect
.bottom
- dlgRect
.top
;
114 OFNOTIFY
* pNotifyCode
;
115 pNotifyCode
= (LPOFNOTIFY
) lParam
;
116 if (CDN_INITDONE
== (pNotifyCode
->hdr
).code
)
118 SetWindowPos( hwndDialog
, HWND_TOP
,
122 gs_rectDialog
.height
,
123 SWP_NOZORDER
|SWP_NOSIZE
);
129 // do the default processing
133 // ----------------------------------------------------------------------------
135 // ----------------------------------------------------------------------------
137 wxFileDialog::wxFileDialog(wxWindow
*parent
,
138 const wxString
& message
,
139 const wxString
& defaultDir
,
140 const wxString
& defaultFileName
,
141 const wxString
& wildCard
,
144 : wxFileDialogBase(parent
, message
, defaultDir
, defaultFileName
,
145 wildCard
, style
, pos
)
148 if ( ( m_dialogStyle
& wxMULTIPLE
) && ( m_dialogStyle
& wxSAVE
) )
149 m_dialogStyle
&= ~wxMULTIPLE
;
151 m_bMovedWindow
= false;
153 // Must set to zero, otherwise the wx routines won't size the window
154 // the second time you call the file dialog, because it thinks it is
155 // already at the requested size.. (when centering)
160 void wxFileDialog::GetPaths(wxArrayString
& paths
) const
165 if ( m_dir
.Last() != _T('\\') )
168 size_t count
= m_fileNames
.GetCount();
169 for ( size_t n
= 0; n
< count
; n
++ )
171 if (wxFileName(m_fileNames
[n
]).IsAbsolute())
172 paths
.Add(m_fileNames
[n
]);
174 paths
.Add(dir
+ m_fileNames
[n
]);
178 void wxFileDialog::GetFilenames(wxArrayString
& files
) const
183 void wxFileDialog::SetPath(const wxString
& path
)
186 wxSplitPath(path
, &m_dir
, &m_fileName
, &ext
);
188 m_fileName
<< _T('.') << ext
;
191 void wxFileDialog::DoGetPosition( int *x
, int *y
) const
193 *x
= gs_rectDialog
.x
;
194 *y
= gs_rectDialog
.y
;
198 void wxFileDialog::DoGetSize(int *width
, int *height
) const
200 *width
= gs_rectDialog
.width
;
201 *height
= gs_rectDialog
.height
;
204 void wxFileDialog::DoMoveWindow(int x
, int y
, int WXUNUSED(width
), int WXUNUSED(height
))
206 m_bMovedWindow
= true;
212 The width and height can not be set by the programmer
213 its just not possible. But the program can get the
214 size of the Dlg after it has been shown, in case they need
219 int wxFileDialog::ShowModal()
222 if (m_parent
) hWnd
= (HWND
) m_parent
->GetHWND();
223 if (!hWnd
&& wxTheApp
->GetTopWindow())
224 hWnd
= (HWND
) wxTheApp
->GetTopWindow()->GetHWND();
226 static wxChar fileNameBuffer
[ wxMAXPATH
]; // the file-name
227 wxChar titleBuffer
[ wxMAXFILE
+1+wxMAXEXT
]; // the file-name, without path
229 *fileNameBuffer
= wxT('\0');
230 *titleBuffer
= wxT('\0');
232 #if WXWIN_COMPATIBILITY_2_4
234 if ( (m_dialogStyle
& wxHIDE_READONLY
) || (m_dialogStyle
& wxSAVE
) )
235 msw_flags
|= OFN_HIDEREADONLY
;
237 long msw_flags
= OFN_HIDEREADONLY
;
240 if ( m_dialogStyle
& wxFILE_MUST_EXIST
)
241 msw_flags
|= OFN_PATHMUSTEXIST
| OFN_FILEMUSTEXIST
;
243 If the window has been moved the programmer is probably
244 trying to center or position it. Thus we set the callback
245 or hook function so that we can actually adjust the position.
246 Without moving or centering the dlg, it will just stay
247 in the upper left of the frame, it does not center
248 automatically.. One additional note, when the hook is
249 enabled, the PLACES BAR in the dlg (shown on later versions
250 of windows (2000 and XP) will automatically be turned off
251 according to the MSDN docs. This is normal. If the
252 programmer needs the PLACES BAR (left side of dlg) they
253 just shouldn't move or center the dlg.
255 if (m_bMovedWindow
) // we need the these flags.
256 msw_flags
|= OFN_EXPLORER
|OFN_ENABLEHOOK
|OFN_ENABLESIZING
;
258 if (m_dialogStyle
& wxMULTIPLE
)
260 // OFN_EXPLORER must always be specified with OFN_ALLOWMULTISELECT
261 msw_flags
|= OFN_EXPLORER
| OFN_ALLOWMULTISELECT
;
264 // if wxCHANGE_DIR flag is not given we shouldn't change the CWD which the
265 // standard dialog does by default
266 if ( !(m_dialogStyle
& wxCHANGE_DIR
) )
268 msw_flags
|= OFN_NOCHANGEDIR
;
271 if ( m_dialogStyle
& wxOVERWRITE_PROMPT
)
273 msw_flags
|= OFN_OVERWRITEPROMPT
;
279 // the OPENFILENAME struct has been extended in newer version of
280 // comcdlg32.dll, but as we don't use the extended fields anyhow, set
281 // the struct size to the old value - otherwise, the programs compiled
282 // with new headers will not work with the old libraries
283 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
284 of
.lStructSize
= sizeof(OPENFILENAME
) -
285 (sizeof(void *) + 2*sizeof(DWORD
));
287 of
.lStructSize
= sizeof(OPENFILENAME
);
291 of
.lpstrTitle
= WXSTRINGCAST m_message
;
292 of
.lpstrFileTitle
= titleBuffer
;
293 of
.nMaxFileTitle
= wxMAXFILE
+ 1 + wxMAXEXT
; // Windows 3.0 and 3.1
295 // Convert forward slashes to backslashes (file selector doesn't like
296 // forward slashes) and also squeeze multiple consecutive slashes into one
297 // as it doesn't like two backslashes in a row neither
300 size_t i
, len
= m_dir
.length();
302 for ( i
= 0; i
< len
; i
++ )
304 wxChar ch
= m_dir
[i
];
308 // convert to backslash
314 while ( i
< len
- 1 )
316 wxChar chNext
= m_dir
[i
+ 1];
317 if ( chNext
!= _T('\\') && chNext
!= _T('/') )
320 // ignore the next one, unless it is at the start of a UNC path
334 of
.lpstrInitialDir
= dir
.c_str();
336 of
.Flags
= msw_flags
;
337 of
.lpfnHook
= wxFileDialogHookFunction
;
339 wxArrayString wildDescriptions
, wildFilters
;
341 size_t items
= wxParseCommonDialogsFilter(m_wildCard
, wildDescriptions
, wildFilters
);
343 wxASSERT_MSG( items
> 0 , _T("empty wildcard list") );
345 wxString filterBuffer
;
347 for (i
= 0; i
< items
; i
++)
349 filterBuffer
+= wildDescriptions
[i
];
350 filterBuffer
+= wxT("|");
351 filterBuffer
+= wildFilters
[i
];
352 filterBuffer
+= wxT("|");
356 for (i
= 0; i
< filterBuffer
.Len(); i
++ ) {
357 if ( filterBuffer
.GetChar(i
) == wxT('|') ) {
358 filterBuffer
[i
] = wxT('\0');
362 of
.lpstrFilter
= (LPTSTR
)filterBuffer
.c_str();
363 of
.nFilterIndex
= m_filterIndex
+ 1;
365 //=== Setting defaultFileName >>=========================================
367 wxStrncpy( fileNameBuffer
, (const wxChar
*)m_fileName
, wxMAXPATH
-1 );
368 fileNameBuffer
[ wxMAXPATH
-1 ] = wxT('\0');
370 of
.lpstrFile
= fileNameBuffer
; // holds returned filename
371 of
.nMaxFile
= wxMAXPATH
;
373 // we must set the default extension because otherwise Windows would check
374 // for the existing of a wrong file with wxOVERWRITE_PROMPT (i.e. if the
375 // user types "foo" and the default extension is ".bar" we should force it
376 // to check for "foo.bar" existence and not "foo")
377 wxString defextBuffer
; // we need it to be alive until GetSaveFileName()!
378 if (m_dialogStyle
& wxSAVE
)
380 const wxChar
* extension
= filterBuffer
;
381 int maxFilter
= (int)(of
.nFilterIndex
*2L) - 1;
383 for( int i
= 0; i
< maxFilter
; i
++ ) // get extension
384 extension
= extension
+ wxStrlen( extension
) + 1;
386 // use dummy name a to avoid assert in AppendExtension
387 defextBuffer
= AppendExtension(wxT("a"), extension
);
388 if (defextBuffer
.StartsWith(wxT("a.")))
391 of
.lpstrDefExt
= defextBuffer
.c_str();
395 //== Execute FileDialog >>=================================================
397 //== Execute FileDialog >>=================================================
399 bool success
= (m_dialogStyle
& wxSAVE
? GetSaveFileName(&of
)
400 : GetOpenFileName(&of
)) != 0;
402 DWORD errCode
= CommDlgExtendedError();
405 if (!success
&& (errCode
== CDERR_STRUCTSIZE
))
407 // The struct size has changed so try a smaller or bigger size
409 int oldStructSize
= of
.lStructSize
;
410 of
.lStructSize
= oldStructSize
- (sizeof(void *) + 2*sizeof(DWORD
));
411 success
= (m_dialogStyle
& wxSAVE
) ? (GetSaveFileName(&of
) != 0)
412 : (GetOpenFileName(&of
) != 0);
413 errCode
= CommDlgExtendedError();
415 if (!success
&& (errCode
== CDERR_STRUCTSIZE
))
417 of
.lStructSize
= oldStructSize
+ (sizeof(void *) + 2*sizeof(DWORD
));
418 success
= (m_dialogStyle
& wxSAVE
) ? (GetSaveFileName(&of
) != 0)
419 : (GetOpenFileName(&of
) != 0);
428 if ( ( m_dialogStyle
& wxMULTIPLE
) &&
429 #if defined(OFN_EXPLORER)
430 ( fileNameBuffer
[of
.nFileOffset
-1] == wxT('\0') )
432 ( fileNameBuffer
[of
.nFileOffset
-1] == wxT(' ') )
433 #endif // OFN_EXPLORER
436 #if defined(OFN_EXPLORER)
437 m_dir
= fileNameBuffer
;
439 m_fileName
= &fileNameBuffer
[i
];
440 m_fileNames
.Add(m_fileName
);
441 i
+= m_fileName
.Len() + 1;
443 while (fileNameBuffer
[i
] != wxT('\0'))
445 m_fileNames
.Add(&fileNameBuffer
[i
]);
446 i
+= wxStrlen(&fileNameBuffer
[i
]) + 1;
449 wxStringTokenizer
toke(fileNameBuffer
, _T(" \t\r\n"));
450 m_dir
= toke
.GetNextToken();
451 m_fileName
= toke
.GetNextToken();
452 m_fileNames
.Add(m_fileName
);
454 while (toke
.HasMoreTokens())
455 m_fileNames
.Add(toke
.GetNextToken());
456 #endif // OFN_EXPLORER
459 if ( m_dir
.Last() != _T('\\') )
462 m_path
= dir
+ m_fileName
;
463 m_filterIndex
= (int)of
.nFilterIndex
- 1;
467 //=== Adding the correct extension >>=================================
469 m_filterIndex
= (int)of
.nFilterIndex
- 1;
471 if ( !of
.nFileExtension
||
472 (of
.nFileExtension
&& fileNameBuffer
[of
.nFileExtension
] == wxT('\0')) )
474 // User has typed a filename without an extension:
475 const wxChar
* extension
= filterBuffer
;
476 int maxFilter
= (int)(of
.nFilterIndex
*2L) - 1;
478 for( int i
= 0; i
< maxFilter
; i
++ ) // get extension
479 extension
= extension
+ wxStrlen( extension
) + 1;
481 m_fileName
= AppendExtension(fileNameBuffer
, extension
);
482 wxStrncpy(fileNameBuffer
, m_fileName
.c_str(), wxMin(m_fileName
.Len(), wxMAXPATH
-1));
483 fileNameBuffer
[wxMin(m_fileName
.Len(), wxMAXPATH
-1)] = wxT('\0');
486 m_path
= fileNameBuffer
;
487 m_fileName
= wxFileNameFromPath(fileNameBuffer
);
488 m_fileNames
.Add(m_fileName
);
489 m_dir
= wxPathOnly(fileNameBuffer
);
494 // common dialog failed - why?
496 DWORD dwErr
= CommDlgExtendedError();
499 // this msg is only for developers
500 wxLogError(wxT("Common dialog failed with error code %0lx."),
503 //else: it was just cancelled
507 return success
? wxID_OK
: wxID_CANCEL
;
511 #endif // wxUSE_FILEDLG