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 these flags.
257 msw_flags
|= OFN_EXPLORER
|OFN_ENABLEHOOK
;
259 msw_flags
|= OFN_ENABLESIZING
;
263 if (m_dialogStyle
& wxMULTIPLE
)
265 // OFN_EXPLORER must always be specified with OFN_ALLOWMULTISELECT
266 msw_flags
|= OFN_EXPLORER
| OFN_ALLOWMULTISELECT
;
269 // if wxCHANGE_DIR flag is not given we shouldn't change the CWD which the
270 // standard dialog does by default
271 if ( !(m_dialogStyle
& wxCHANGE_DIR
) )
273 msw_flags
|= OFN_NOCHANGEDIR
;
276 if ( m_dialogStyle
& wxOVERWRITE_PROMPT
)
278 msw_flags
|= OFN_OVERWRITEPROMPT
;
284 // the OPENFILENAME struct has been extended in newer version of
285 // comcdlg32.dll, but as we don't use the extended fields anyhow, set
286 // the struct size to the old value - otherwise, the programs compiled
287 // with new headers will not work with the old libraries
288 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
289 of
.lStructSize
= sizeof(OPENFILENAME
) -
290 (sizeof(void *) + 2*sizeof(DWORD
));
292 of
.lStructSize
= sizeof(OPENFILENAME
);
296 of
.lpstrTitle
= WXSTRINGCAST m_message
;
297 of
.lpstrFileTitle
= titleBuffer
;
298 of
.nMaxFileTitle
= wxMAXFILE
+ 1 + wxMAXEXT
; // Windows 3.0 and 3.1
300 // Convert forward slashes to backslashes (file selector doesn't like
301 // forward slashes) and also squeeze multiple consecutive slashes into one
302 // as it doesn't like two backslashes in a row neither
305 size_t i
, len
= m_dir
.length();
307 for ( i
= 0; i
< len
; i
++ )
309 wxChar ch
= m_dir
[i
];
313 // convert to backslash
319 while ( i
< len
- 1 )
321 wxChar chNext
= m_dir
[i
+ 1];
322 if ( chNext
!= _T('\\') && chNext
!= _T('/') )
325 // ignore the next one, unless it is at the start of a UNC path
339 of
.lpstrInitialDir
= dir
.c_str();
341 of
.Flags
= msw_flags
;
342 of
.lpfnHook
= wxFileDialogHookFunction
;
344 wxArrayString wildDescriptions
, wildFilters
;
346 size_t items
= wxParseCommonDialogsFilter(m_wildCard
, wildDescriptions
, wildFilters
);
348 wxASSERT_MSG( items
> 0 , _T("empty wildcard list") );
350 wxString filterBuffer
;
352 for (i
= 0; i
< items
; i
++)
354 filterBuffer
+= wildDescriptions
[i
];
355 filterBuffer
+= wxT("|");
356 filterBuffer
+= wildFilters
[i
];
357 filterBuffer
+= wxT("|");
361 for (i
= 0; i
< filterBuffer
.Len(); i
++ ) {
362 if ( filterBuffer
.GetChar(i
) == wxT('|') ) {
363 filterBuffer
[i
] = wxT('\0');
367 of
.lpstrFilter
= (LPTSTR
)filterBuffer
.c_str();
368 of
.nFilterIndex
= m_filterIndex
+ 1;
370 //=== Setting defaultFileName >>=========================================
372 wxStrncpy( fileNameBuffer
, (const wxChar
*)m_fileName
, wxMAXPATH
-1 );
373 fileNameBuffer
[ wxMAXPATH
-1 ] = wxT('\0');
375 of
.lpstrFile
= fileNameBuffer
; // holds returned filename
376 of
.nMaxFile
= wxMAXPATH
;
378 // we must set the default extension because otherwise Windows would check
379 // for the existing of a wrong file with wxOVERWRITE_PROMPT (i.e. if the
380 // user types "foo" and the default extension is ".bar" we should force it
381 // to check for "foo.bar" existence and not "foo")
382 wxString defextBuffer
; // we need it to be alive until GetSaveFileName()!
383 if (m_dialogStyle
& wxSAVE
)
385 const wxChar
* extension
= filterBuffer
;
386 int maxFilter
= (int)(of
.nFilterIndex
*2L) - 1;
388 for( int i
= 0; i
< maxFilter
; i
++ ) // get extension
389 extension
= extension
+ wxStrlen( extension
) + 1;
391 // use dummy name a to avoid assert in AppendExtension
392 defextBuffer
= AppendExtension(wxT("a"), extension
);
393 if (defextBuffer
.StartsWith(wxT("a.")))
396 of
.lpstrDefExt
= defextBuffer
.c_str();
400 //== Execute FileDialog >>=================================================
402 //== Execute FileDialog >>=================================================
404 bool success
= (m_dialogStyle
& wxSAVE
? GetSaveFileName(&of
)
405 : GetOpenFileName(&of
)) != 0;
407 DWORD errCode
= CommDlgExtendedError();
410 if (!success
&& (errCode
== CDERR_STRUCTSIZE
))
412 // The struct size has changed so try a smaller or bigger size
414 int oldStructSize
= of
.lStructSize
;
415 of
.lStructSize
= oldStructSize
- (sizeof(void *) + 2*sizeof(DWORD
));
416 success
= (m_dialogStyle
& wxSAVE
) ? (GetSaveFileName(&of
) != 0)
417 : (GetOpenFileName(&of
) != 0);
418 errCode
= CommDlgExtendedError();
420 if (!success
&& (errCode
== CDERR_STRUCTSIZE
))
422 of
.lStructSize
= oldStructSize
+ (sizeof(void *) + 2*sizeof(DWORD
));
423 success
= (m_dialogStyle
& wxSAVE
) ? (GetSaveFileName(&of
) != 0)
424 : (GetOpenFileName(&of
) != 0);
433 if ( ( m_dialogStyle
& wxMULTIPLE
) &&
434 #if defined(OFN_EXPLORER)
435 ( fileNameBuffer
[of
.nFileOffset
-1] == wxT('\0') )
437 ( fileNameBuffer
[of
.nFileOffset
-1] == wxT(' ') )
438 #endif // OFN_EXPLORER
441 #if defined(OFN_EXPLORER)
442 m_dir
= fileNameBuffer
;
444 m_fileName
= &fileNameBuffer
[i
];
445 m_fileNames
.Add(m_fileName
);
446 i
+= m_fileName
.Len() + 1;
448 while (fileNameBuffer
[i
] != wxT('\0'))
450 m_fileNames
.Add(&fileNameBuffer
[i
]);
451 i
+= wxStrlen(&fileNameBuffer
[i
]) + 1;
454 wxStringTokenizer
toke(fileNameBuffer
, _T(" \t\r\n"));
455 m_dir
= toke
.GetNextToken();
456 m_fileName
= toke
.GetNextToken();
457 m_fileNames
.Add(m_fileName
);
459 while (toke
.HasMoreTokens())
460 m_fileNames
.Add(toke
.GetNextToken());
461 #endif // OFN_EXPLORER
464 if ( m_dir
.Last() != _T('\\') )
467 m_path
= dir
+ m_fileName
;
468 m_filterIndex
= (int)of
.nFilterIndex
- 1;
472 //=== Adding the correct extension >>=================================
474 m_filterIndex
= (int)of
.nFilterIndex
- 1;
476 if ( !of
.nFileExtension
||
477 (of
.nFileExtension
&& fileNameBuffer
[of
.nFileExtension
] == wxT('\0')) )
479 // User has typed a filename without an extension:
480 const wxChar
* extension
= filterBuffer
;
481 int maxFilter
= (int)(of
.nFilterIndex
*2L) - 1;
483 for( int i
= 0; i
< maxFilter
; i
++ ) // get extension
484 extension
= extension
+ wxStrlen( extension
) + 1;
486 m_fileName
= AppendExtension(fileNameBuffer
, extension
);
487 wxStrncpy(fileNameBuffer
, m_fileName
.c_str(), wxMin(m_fileName
.Len(), wxMAXPATH
-1));
488 fileNameBuffer
[wxMin(m_fileName
.Len(), wxMAXPATH
-1)] = wxT('\0');
491 m_path
= fileNameBuffer
;
492 m_fileName
= wxFileNameFromPath(fileNameBuffer
);
493 m_fileNames
.Add(m_fileName
);
494 m_dir
= wxPathOnly(fileNameBuffer
);
499 // common dialog failed - why?
501 DWORD dwErr
= CommDlgExtendedError();
504 // this msg is only for developers
505 wxLogError(wxT("Common dialog failed with error code %0lx."),
508 //else: it was just cancelled
512 return success
? wxID_OK
: wxID_CANCEL
;
516 #endif // wxUSE_FILEDLG