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__)
53 #include "wx/filename.h"
54 #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 //== Execute FileDialog >>=================================================
402 bool success
= (m_dialogStyle
& wxSAVE
? GetSaveFileName(&of
)
403 : GetOpenFileName(&of
)) != 0;
405 DWORD errCode
= CommDlgExtendedError();
408 if (!success
&& (errCode
== CDERR_STRUCTSIZE
))
410 // The struct size has changed so try a smaller or bigger size
412 int oldStructSize
= of
.lStructSize
;
413 of
.lStructSize
= oldStructSize
- (sizeof(void *) + 2*sizeof(DWORD
));
414 success
= (m_dialogStyle
& wxSAVE
) ? (GetSaveFileName(&of
) != 0)
415 : (GetOpenFileName(&of
) != 0);
416 errCode
= CommDlgExtendedError();
418 if (!success
&& (errCode
== CDERR_STRUCTSIZE
))
420 of
.lStructSize
= oldStructSize
+ (sizeof(void *) + 2*sizeof(DWORD
));
421 success
= (m_dialogStyle
& wxSAVE
) ? (GetSaveFileName(&of
) != 0)
422 : (GetOpenFileName(&of
) != 0);
431 if ( ( m_dialogStyle
& wxMULTIPLE
) &&
432 #if defined(OFN_EXPLORER)
433 ( fileNameBuffer
[of
.nFileOffset
-1] == wxT('\0') )
435 ( fileNameBuffer
[of
.nFileOffset
-1] == wxT(' ') )
436 #endif // OFN_EXPLORER
439 #if defined(OFN_EXPLORER)
440 m_dir
= fileNameBuffer
;
442 m_fileName
= &fileNameBuffer
[i
];
443 m_fileNames
.Add(m_fileName
);
444 i
+= m_fileName
.Len() + 1;
446 while (fileNameBuffer
[i
] != wxT('\0'))
448 m_fileNames
.Add(&fileNameBuffer
[i
]);
449 i
+= wxStrlen(&fileNameBuffer
[i
]) + 1;
452 wxStringTokenizer
toke(fileNameBuffer
, _T(" \t\r\n"));
453 m_dir
= toke
.GetNextToken();
454 m_fileName
= toke
.GetNextToken();
455 m_fileNames
.Add(m_fileName
);
457 while (toke
.HasMoreTokens())
458 m_fileNames
.Add(toke
.GetNextToken());
459 #endif // OFN_EXPLORER
462 if ( m_dir
.Last() != _T('\\') )
465 m_path
= dir
+ m_fileName
;
466 m_filterIndex
= (int)of
.nFilterIndex
- 1;
470 //=== Adding the correct extension >>=================================
472 m_filterIndex
= (int)of
.nFilterIndex
- 1;
474 if ( !of
.nFileExtension
||
475 (of
.nFileExtension
&& fileNameBuffer
[of
.nFileExtension
] == wxT('\0')) )
477 // User has typed a filename without an extension:
478 const wxChar
* extension
= filterBuffer
;
479 int maxFilter
= (int)(of
.nFilterIndex
*2L) - 1;
481 for( int i
= 0; i
< maxFilter
; i
++ ) // get extension
482 extension
= extension
+ wxStrlen( extension
) + 1;
484 m_fileName
= AppendExtension(fileNameBuffer
, extension
);
485 wxStrncpy(fileNameBuffer
, m_fileName
.c_str(), wxMin(m_fileName
.Len(), wxMAXPATH
-1));
486 fileNameBuffer
[wxMin(m_fileName
.Len(), wxMAXPATH
-1)] = wxT('\0');
489 m_path
= fileNameBuffer
;
490 m_fileName
= wxFileNameFromPath(fileNameBuffer
);
491 m_fileNames
.Add(m_fileName
);
492 m_dir
= wxPathOnly(fileNameBuffer
);
497 // common dialog failed - why?
499 DWORD dwErr
= CommDlgExtendedError();
502 // this msg is only for developers
503 wxLogError(wxT("Common dialog failed with error code %0lx."),
506 //else: it was just cancelled
510 return success
? wxID_OK
: wxID_CANCEL
;
514 #endif // wxUSE_FILEDLG && !(__SMARTPHONE__ && __WXWINCE__)