]> git.saurik.com Git - wxWidgets.git/blame - src/msw/filedlg.cpp
Unicode compilation fix (bug 809707)
[wxWidgets.git] / src / msw / filedlg.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
f6bcfd97 2// Name: src/msw/filedlg.cpp
2bda0e17
KB
3// Purpose: wxFileDialog
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
e15e548b 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
f6bcfd97
BP
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
ba681060 21 #pragma implementation "filedlg.h"
2bda0e17
KB
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
ba681060 28 #pragma hdrstop
2bda0e17
KB
29#endif
30
449110cd 31#if wxUSE_FILEDLG && !wxUSE_SMARTPHONE
1e6feb95 32
2bda0e17 33#ifndef WX_PRECOMP
ba681060
VZ
34 #include "wx/utils.h"
35 #include "wx/msgdlg.h"
ba681060 36 #include "wx/filedlg.h"
2b5f62a0 37 #include "wx/filefn.h"
ba681060 38 #include "wx/intl.h"
2662e49e 39 #include "wx/log.h"
f6bcfd97 40 #include "wx/app.h"
8f177c8e 41#endif
2bda0e17 42
f6bcfd97
BP
43#include "wx/msw/private.h"
44
4676948b 45#if !defined(__WIN32__) || defined(__WXWINCE__)
ba681060 46 #include <commdlg.h>
2bda0e17
KB
47#endif
48
2bda0e17
KB
49#include <math.h>
50#include <stdlib.h>
51#include <string.h>
52
8ad9ca97 53#include "wx/filename.h"
8f177c8e
VZ
54#include "wx/tokenzr.h"
55
6e8aa701
VZ
56#ifndef OFN_EXPLORER
57 #define OFN_EXPLORER 0x00080000
58#endif
59
f6bcfd97
BP
60// ----------------------------------------------------------------------------
61// constants
62// ----------------------------------------------------------------------------
63
64#ifdef __WIN32__
2b5f62a0 65# define wxMAXPATH 65534
f6bcfd97
BP
66#else
67# define wxMAXPATH 1024
68#endif
69
70# define wxMAXFILE 1024
71
72# define wxMAXEXT 5
73
74// ============================================================================
75// implementation
76// ============================================================================
77
f74172ab 78IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase)
2bda0e17 79
f6bcfd97 80// ----------------------------------------------------------------------------
b600ed13 81// wxFileDialog
f6bcfd97
BP
82// ----------------------------------------------------------------------------
83
2b5f62a0
VZ
84wxFileDialog::wxFileDialog(wxWindow *parent,
85 const wxString& message,
86 const wxString& defaultDir,
87 const wxString& defaultFileName,
88 const wxString& wildCard,
89 long style,
f74172ab
VZ
90 const wxPoint& pos)
91 :wxFileDialogBase(parent, message, defaultDir, defaultFileName, wildCard, style, pos)
92
2bda0e17 93{
c61f4f6d
VZ
94 if ( ( m_dialogStyle & wxMULTIPLE ) && ( m_dialogStyle & wxSAVE ) )
95 m_dialogStyle &= ~wxMULTIPLE;
2bda0e17
KB
96}
97
c61f4f6d
VZ
98void wxFileDialog::GetPaths(wxArrayString& paths) const
99{
100 paths.Empty();
101
102 wxString dir(m_dir);
103 if ( m_dir.Last() != _T('\\') )
104 dir += _T('\\');
105
106 size_t count = m_fileNames.GetCount();
107 for ( size_t n = 0; n < count; n++ )
108 {
8ad9ca97
JS
109 if (wxFileName(m_fileNames[n]).IsAbsolute())
110 paths.Add(m_fileNames[n]);
111 else
112 paths.Add(dir + m_fileNames[n]);
c61f4f6d
VZ
113 }
114}
115
2b5f62a0
VZ
116void wxFileDialog::SetPath(const wxString& path)
117{
118 wxString ext;
119 wxSplitPath(path, &m_dir, &m_fileName, &ext);
120 if ( !ext.empty() )
121 m_fileName << _T('.') << ext;
122}
123
c61f4f6d 124int wxFileDialog::ShowModal()
2bda0e17 125{
1f2f0331
VZ
126 HWND hWnd = 0;
127 if (m_parent) hWnd = (HWND) m_parent->GetHWND();
f6bcfd97
BP
128 if (!hWnd && wxTheApp->GetTopWindow())
129 hWnd = (HWND) wxTheApp->GetTopWindow()->GetHWND();
2bda0e17 130
f6bcfd97
BP
131 static wxChar fileNameBuffer [ wxMAXPATH ]; // the file-name
132 wxChar titleBuffer [ wxMAXFILE+1+wxMAXEXT ]; // the file-name, without path
2bda0e17 133
223d09f6
KB
134 *fileNameBuffer = wxT('\0');
135 *titleBuffer = wxT('\0');
2bda0e17 136
2bda0e17 137 long msw_flags = 0;
e15e548b 138 if ( (m_dialogStyle & wxHIDE_READONLY) || (m_dialogStyle & wxSAVE) )
1f2f0331 139 msw_flags |= OFN_HIDEREADONLY;
e15e548b 140 if ( m_dialogStyle & wxFILE_MUST_EXIST )
1f2f0331 141 msw_flags |= OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
6e8aa701 142
c61f4f6d 143 if (m_dialogStyle & wxMULTIPLE )
6e8aa701
VZ
144 {
145 // OFN_EXPLORER must always be specified with OFN_ALLOWMULTISELECT
146 msw_flags |= OFN_EXPLORER | OFN_ALLOWMULTISELECT;
147 }
148
99d1b93d
VZ
149 // if wxCHANGE_DIR flag is not given we shouldn't change the CWD which the
150 // standard dialog does by default
6e8aa701
VZ
151 if ( !(m_dialogStyle & wxCHANGE_DIR) )
152 {
153 msw_flags |= OFN_NOCHANGEDIR;
154 }
012a01fc
JS
155/* chris elliott for some reason this does not work usefully if no extension
156 is given, as it test for junk instead of junk.ext
99d1b93d
VZ
157 if ( m_dialogStyle & wxOVERWRITE_PROMPT )
158 {
159 msw_flags |= OFN_OVERWRITEPROMPT;
160 }
012a01fc 161*/
e15e548b 162 OPENFILENAME of;
f6bcfd97
BP
163 wxZeroMemory(of);
164
165 // the OPENFILENAME struct has been extended in newer version of
166 // comcdlg32.dll, but as we don't use the extended fields anyhow, set
167 // the struct size to the old value - otherwise, the programs compiled
168 // with new headers will not work with the old libraries
169#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
170 of.lStructSize = sizeof(OPENFILENAME) -
171 (sizeof(void *) + 2*sizeof(DWORD));
172#else // old headers
e15e548b 173 of.lStructSize = sizeof(OPENFILENAME);
f6bcfd97
BP
174#endif
175
e15e548b 176 of.hwndOwner = hWnd;
837e5743 177 of.lpstrTitle = WXSTRINGCAST m_message;
e15e548b 178 of.lpstrFileTitle = titleBuffer;
f6bcfd97 179 of.nMaxFileTitle = wxMAXFILE + 1 + wxMAXEXT; // Windows 3.0 and 3.1
2bda0e17 180
0bc9b25e 181 // Convert forward slashes to backslashes (file selector doesn't like
99d1b93d
VZ
182 // forward slashes) and also squeeze multiple consecutive slashes into one
183 // as it doesn't like two backslashes in a row neither
0627d091
RL
184
185 wxString dir;
186 size_t i, len = m_dir.length();
99d1b93d 187 dir.reserve(len);
0627d091 188 for ( i = 0; i < len; i++ )
99d1b93d
VZ
189 {
190 wxChar ch = m_dir[i];
191 switch ( ch )
192 {
193 case _T('/'):
194 // convert to backslash
195 ch = _T('\\');
196
197 // fall through
0bc9b25e 198
99d1b93d
VZ
199 case _T('\\'):
200 while ( i < len - 1 )
201 {
202 wxChar chNext = m_dir[i + 1];
203 if ( chNext != _T('\\') && chNext != _T('/') )
204 break;
205
04d93c3a
CE
206 // ignore the next one, unless it is at the start of a UNC path
207 if (i > 0)
208 i++;
209 else
210 break;
99d1b93d
VZ
211 }
212 // fall through
213
214 default:
215 // normal char
216 dir += ch;
217 }
218 }
219
220 of.lpstrInitialDir = dir.c_str();
2bda0e17 221
e15e548b 222 of.Flags = msw_flags;
2bda0e17
KB
223
224
2bda0e17
KB
225 //=== Like Alejandro Sierra's wildcard modification >>===================
226 /*
1f2f0331
VZ
227 In wxFileSelector you can put, instead of a single wild_card,
228 pairs of strings separated by '|'.
229 The first string is a description, and the
230 second is the wild card. You can put any number of pairs.
2bda0e17 231
1f2f0331 232 eg. "description1 (*.ex1)|*.ex1|description2 (*.ex2)|*.ex2"
2bda0e17 233
1f2f0331
VZ
234 If you put a single wild card, it works as before the modification.
235 */
2bda0e17
KB
236 //=======================================================================
237
4dba84be 238 wxString theFilter;
837e5743 239 if ( wxStrlen(m_wildCard) == 0 )
223d09f6 240 theFilter = wxString(wxT("*.*"));
4dba84be
JS
241 else
242 theFilter = m_wildCard ;
1f2f0331 243 wxString filterBuffer;
2bda0e17 244
223d09f6 245 if ( !wxStrchr( theFilter, wxT('|') ) ) { // only one filter ==> default text
1f2f0331
VZ
246 filterBuffer.Printf(_("Files (%s)|%s"),
247 theFilter.c_str(), theFilter.c_str());
e15e548b 248 }
1f2f0331
VZ
249 else { // more then one filter
250 filterBuffer = theFilter;
2bda0e17 251
574c0bbf
JS
252 }
253
223d09f6 254 filterBuffer += wxT("|");
574c0bbf 255 // Replace | with \0
0bc9b25e 256 for (i = 0; i < filterBuffer.Len(); i++ ) {
223d09f6
KB
257 if ( filterBuffer.GetChar(i) == wxT('|') ) {
258 filterBuffer[i] = wxT('\0');
e15e548b
VZ
259 }
260 }
2bda0e17 261
837e5743 262 of.lpstrFilter = (LPTSTR)(const wxChar *)filterBuffer;
cc42eb7a 263 of.nFilterIndex = m_filterIndex + 1;
2bda0e17
KB
264
265 //=== Setting defaultFileName >>=========================================
266
f6bcfd97
BP
267 wxStrncpy( fileNameBuffer, (const wxChar *)m_fileName, wxMAXPATH-1 );
268 fileNameBuffer[ wxMAXPATH-1 ] = wxT('\0');
2bda0e17 269
e15e548b 270 of.lpstrFile = fileNameBuffer; // holds returned filename
f6bcfd97 271 of.nMaxFile = wxMAXPATH;
2bda0e17
KB
272
273 //== Execute FileDialog >>=================================================
274
3f6638b8
VZ
275 bool success = (m_dialogStyle & wxSAVE ? GetSaveFileName(&of)
276 : GetOpenFileName(&of)) != 0;
2bda0e17 277
f6bcfd97
BP
278 DWORD errCode = CommDlgExtendedError();
279
280#ifdef __WIN32__
281 if (!success && (errCode == CDERR_STRUCTSIZE))
282 {
283 // The struct size has changed so try a smaller or bigger size
284
285 int oldStructSize = of.lStructSize;
286 of.lStructSize = oldStructSize - (sizeof(void *) + 2*sizeof(DWORD));
287 success = (m_dialogStyle & wxSAVE) ? (GetSaveFileName(&of) != 0)
288 : (GetOpenFileName(&of) != 0);
289 errCode = CommDlgExtendedError();
290
291 if (!success && (errCode == CDERR_STRUCTSIZE))
292 {
293 of.lStructSize = oldStructSize + (sizeof(void *) + 2*sizeof(DWORD));
294 success = (m_dialogStyle & wxSAVE) ? (GetSaveFileName(&of) != 0)
295 : (GetOpenFileName(&of) != 0);
296 }
297 }
c6603ac2 298#endif // __WIN32__
f6bcfd97 299
2bda0e17
KB
300 if ( success )
301 {
c61f4f6d
VZ
302 m_fileNames.Empty();
303
304 if ( ( m_dialogStyle & wxMULTIPLE ) &&
305#if defined(OFN_EXPLORER)
c39e82f0 306 ( fileNameBuffer[of.nFileOffset-1] == wxT('\0') )
c61f4f6d 307#else
c39e82f0 308 ( fileNameBuffer[of.nFileOffset-1] == wxT(' ') )
c61f4f6d 309#endif // OFN_EXPLORER
c39e82f0 310 )
c61f4f6d
VZ
311 {
312#if defined(OFN_EXPLORER)
313 m_dir = fileNameBuffer;
314 i = of.nFileOffset;
315 m_fileName = &fileNameBuffer[i];
316 m_fileNames.Add(m_fileName);
317 i += m_fileName.Len() + 1;
318
319 while (fileNameBuffer[i] != wxT('\0'))
320 {
321 m_fileNames.Add(&fileNameBuffer[i]);
322 i += wxStrlen(&fileNameBuffer[i]) + 1;
323 }
324#else
c6603ac2 325 wxStringTokenizer toke(fileNameBuffer, _T(" \t\r\n"));
c61f4f6d
VZ
326 m_dir = toke.GetNextToken();
327 m_fileName = toke.GetNextToken();
328 m_fileNames.Add(m_fileName);
329
330 while (toke.HasMoreTokens())
331 m_fileNames.Add(toke.GetNextToken());
332#endif // OFN_EXPLORER
333
334 wxString dir(m_dir);
335 if ( m_dir.Last() != _T('\\') )
336 dir += _T('\\');
337
c61f4f6d
VZ
338 m_path = dir + m_fileName;
339 }
340 else
341 {
c61f4f6d 342 //=== Adding the correct extension >>=================================
2bda0e17 343
cc42eb7a 344 m_filterIndex = (int)of.nFilterIndex - 1;
2bda0e17 345
c6603ac2
VS
346 if ( !of.nFileExtension ||
347 (of.nFileExtension && fileNameBuffer[of.nFileExtension] == wxT('\0')) )
348 {
349 // User has typed a filename without an extension:
f74172ab
VZ
350 const wxChar* extension = filterBuffer;
351 int maxFilter = (int)(of.nFilterIndex*2L) - 1;
2bda0e17 352
f74172ab
VZ
353 for( int i = 0; i < maxFilter; i++ ) // get extension
354 extension = extension + wxStrlen( extension ) + 1;
a039ccbf 355
f74172ab
VZ
356 m_fileName = AppendExtension(fileNameBuffer, extension);
357 wxStrncpy(fileNameBuffer, m_fileName.c_str(), wxMin(m_fileName.Len(), wxMAXPATH-1));
358 fileNameBuffer[wxMin(m_fileName.Len(), wxMAXPATH-1)] = wxT('\0');
2bda0e17 359 }
2bda0e17 360
c61f4f6d
VZ
361 m_path = fileNameBuffer;
362 m_fileName = wxFileNameFromPath(fileNameBuffer);
363 m_fileNames.Add(m_fileName);
364 m_dir = wxPathOnly(fileNameBuffer);
365 }
012a01fc
JS
366 //=== Simulating the wxOVERWRITE_PROMPT >>============================
367 //should we also test for file save style ??
368 if ( (m_dialogStyle & wxOVERWRITE_PROMPT) &&
369 ::wxFileExists( fileNameBuffer ) )
370 {
371 wxString messageText;
372 messageText.Printf(_("File '%s' already exists.\nDo you want to replace it?"), fileNameBuffer);
6f661de7 373 if ( wxMessageBox(messageText, _("Save File As"), wxYES_NO | wxICON_EXCLAMATION ) != wxYES )
012a01fc
JS
374 {
375 success = FALSE;
376 }
377 }
7cc98b3e
VZ
378 }
379 else
380 {
381 // common dialog failed - why?
382#ifdef __WXDEBUG__
383 DWORD dwErr = CommDlgExtendedError();
384 if ( dwErr != 0 )
385 {
386 // this msg is only for developers
223d09f6 387 wxLogError(wxT("Common dialog failed with error code %0lx."),
7cc98b3e
VZ
388 dwErr);
389 }
390 //else: it was just cancelled
391#endif
392 }
2bda0e17 393
7cc98b3e 394 return success ? wxID_OK : wxID_CANCEL;
2bda0e17
KB
395
396}
397
1e6feb95 398#endif // wxUSE_FILEDLG
c61f4f6d 399