]> git.saurik.com Git - wxWidgets.git/blame - src/msw/filedlg.cpp
Implemented PocketPC menubar/toolbar as wxToolMenuBar derived
[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
65571936 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
3180bc0e 31#if wxUSE_FILEDLG && !(defined(__SMARTPHONE__) && defined(__WXWINCE__))
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 <stdlib.h>
50#include <string.h>
51
8ad9ca97 52#include "wx/filename.h"
8f177c8e 53#include "wx/tokenzr.h"
b713f891 54#include "wx/math.h"
8f177c8e 55
41b8fe99 56#include "wx/msw/missing.h"
6e8aa701 57
f6bcfd97
BP
58// ----------------------------------------------------------------------------
59// constants
60// ----------------------------------------------------------------------------
61
62#ifdef __WIN32__
2b5f62a0 63# define wxMAXPATH 65534
f6bcfd97
BP
64#else
65# define wxMAXPATH 1024
66#endif
67
68# define wxMAXFILE 1024
69
70# define wxMAXEXT 5
71
0b11099d
VZ
72// ----------------------------------------------------------------------------
73// globals
74// ----------------------------------------------------------------------------
75
76// standard dialog size
77static wxRect gs_rectDialog(0, 0, 428, 266);
78
f6bcfd97
BP
79// ============================================================================
80// implementation
81// ============================================================================
82
f74172ab 83IMPLEMENT_CLASS(wxFileDialog, wxFileDialogBase)
2bda0e17 84
0b11099d
VZ
85// ----------------------------------------------------------------------------
86// hook function for moving the dialog
87// ----------------------------------------------------------------------------
88
89UINT APIENTRY
90wxFileDialogHookFunction(HWND hDlg,
91 UINT iMsg,
92 WPARAM WXUNUSED(wParam),
93 LPARAM lParam)
94{
95 HWND hwndDialog;
96 hwndDialog = ::GetParent( hDlg );
97 switch (iMsg)
98 {
99 case WM_DESTROY:
100 {
101 RECT dlgRect;
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;
107 }
108 break;
109
110 case WM_NOTIFY:
111 {
112 OFNOTIFY * pNotifyCode;
113 pNotifyCode = (LPOFNOTIFY) lParam;
114 if (CDN_INITDONE == (pNotifyCode->hdr).code)
115 {
116 SetWindowPos( hwndDialog, HWND_TOP,
117 gs_rectDialog.x,
118 gs_rectDialog.y,
119 gs_rectDialog.width,
120 gs_rectDialog.height,
121 SWP_NOZORDER|SWP_NOSIZE);
122 }
123 }
124 break;
125 }
126
127 // do the default processing
128 return 0;
129}
130
f6bcfd97 131// ----------------------------------------------------------------------------
b600ed13 132// wxFileDialog
f6bcfd97
BP
133// ----------------------------------------------------------------------------
134
2b5f62a0
VZ
135wxFileDialog::wxFileDialog(wxWindow *parent,
136 const wxString& message,
137 const wxString& defaultDir,
138 const wxString& defaultFileName,
139 const wxString& wildCard,
140 long style,
f74172ab 141 const wxPoint& pos)
0b11099d
VZ
142 : wxFileDialogBase(parent, message, defaultDir, defaultFileName,
143 wildCard, style, pos)
f74172ab 144
2bda0e17 145{
c61f4f6d
VZ
146 if ( ( m_dialogStyle & wxMULTIPLE ) && ( m_dialogStyle & wxSAVE ) )
147 m_dialogStyle &= ~wxMULTIPLE;
2bda0e17 148
0b11099d
VZ
149 m_bMovedWindow = false;
150
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)
154 gs_rectDialog.x =
155 gs_rectDialog.y = 0;
156
157}
c61f4f6d
VZ
158void wxFileDialog::GetPaths(wxArrayString& paths) const
159{
160 paths.Empty();
161
162 wxString dir(m_dir);
163 if ( m_dir.Last() != _T('\\') )
164 dir += _T('\\');
165
166 size_t count = m_fileNames.GetCount();
167 for ( size_t n = 0; n < count; n++ )
168 {
8ad9ca97
JS
169 if (wxFileName(m_fileNames[n]).IsAbsolute())
170 paths.Add(m_fileNames[n]);
171 else
172 paths.Add(dir + m_fileNames[n]);
c61f4f6d
VZ
173 }
174}
175
89654c9a
VZ
176void wxFileDialog::GetFilenames(wxArrayString& files) const
177{
178 files = m_fileNames;
179}
180
2b5f62a0
VZ
181void wxFileDialog::SetPath(const wxString& path)
182{
183 wxString ext;
184 wxSplitPath(path, &m_dir, &m_fileName, &ext);
185 if ( !ext.empty() )
186 m_fileName << _T('.') << ext;
187}
188
0b11099d
VZ
189void wxFileDialog::DoGetPosition( int *x, int *y ) const
190{
191 *x = gs_rectDialog.x;
192 *y = gs_rectDialog.y;
193}
194
195
196void wxFileDialog::DoGetSize(int *width, int *height) const
197{
198 *width = gs_rectDialog.width;
199 *height = gs_rectDialog.height;
200}
201
202void wxFileDialog::DoMoveWindow(int x, int y, int WXUNUSED(width), int WXUNUSED(height))
203{
204 m_bMovedWindow = true;
205
206 gs_rectDialog.x = x;
207 gs_rectDialog.y = y;
208
209 /*
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
213 that data.
214 */
215}
216
c61f4f6d 217int wxFileDialog::ShowModal()
2bda0e17 218{
1f2f0331
VZ
219 HWND hWnd = 0;
220 if (m_parent) hWnd = (HWND) m_parent->GetHWND();
f6bcfd97
BP
221 if (!hWnd && wxTheApp->GetTopWindow())
222 hWnd = (HWND) wxTheApp->GetTopWindow()->GetHWND();
2bda0e17 223
f6bcfd97
BP
224 static wxChar fileNameBuffer [ wxMAXPATH ]; // the file-name
225 wxChar titleBuffer [ wxMAXFILE+1+wxMAXEXT ]; // the file-name, without path
2bda0e17 226
223d09f6
KB
227 *fileNameBuffer = wxT('\0');
228 *titleBuffer = wxT('\0');
2bda0e17 229
21416306 230#if WXWIN_COMPATIBILITY_2_4
2bda0e17 231 long msw_flags = 0;
e15e548b 232 if ( (m_dialogStyle & wxHIDE_READONLY) || (m_dialogStyle & wxSAVE) )
1f2f0331 233 msw_flags |= OFN_HIDEREADONLY;
21416306
WS
234#else
235 long msw_flags = OFN_HIDEREADONLY;
236#endif
237
e15e548b 238 if ( m_dialogStyle & wxFILE_MUST_EXIST )
1f2f0331 239 msw_flags |= OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
0b11099d
VZ
240 /*
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.
252 */
503528dc
JS
253 if (m_bMovedWindow) // we need these flags.
254 {
255 msw_flags |= OFN_EXPLORER|OFN_ENABLEHOOK;
256#ifndef __WXWINCE__
257 msw_flags |= OFN_ENABLESIZING;
258#endif
259 }
6e8aa701 260
c61f4f6d 261 if (m_dialogStyle & wxMULTIPLE )
6e8aa701
VZ
262 {
263 // OFN_EXPLORER must always be specified with OFN_ALLOWMULTISELECT
264 msw_flags |= OFN_EXPLORER | OFN_ALLOWMULTISELECT;
265 }
266
99d1b93d
VZ
267 // if wxCHANGE_DIR flag is not given we shouldn't change the CWD which the
268 // standard dialog does by default
6e8aa701
VZ
269 if ( !(m_dialogStyle & wxCHANGE_DIR) )
270 {
271 msw_flags |= OFN_NOCHANGEDIR;
272 }
ac95e671 273
99d1b93d
VZ
274 if ( m_dialogStyle & wxOVERWRITE_PROMPT )
275 {
276 msw_flags |= OFN_OVERWRITEPROMPT;
277 }
ac95e671 278
e15e548b 279 OPENFILENAME of;
f6bcfd97
BP
280 wxZeroMemory(of);
281
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));
289#else // old headers
e15e548b 290 of.lStructSize = sizeof(OPENFILENAME);
f6bcfd97
BP
291#endif
292
e15e548b 293 of.hwndOwner = hWnd;
837e5743 294 of.lpstrTitle = WXSTRINGCAST m_message;
e15e548b 295 of.lpstrFileTitle = titleBuffer;
f6bcfd97 296 of.nMaxFileTitle = wxMAXFILE + 1 + wxMAXEXT; // Windows 3.0 and 3.1
2bda0e17 297
0bc9b25e 298 // Convert forward slashes to backslashes (file selector doesn't like
99d1b93d
VZ
299 // forward slashes) and also squeeze multiple consecutive slashes into one
300 // as it doesn't like two backslashes in a row neither
0627d091 301
cbe874bd
WS
302 wxString dir;
303 size_t i, len = m_dir.length();
99d1b93d 304 dir.reserve(len);
0627d091 305 for ( i = 0; i < len; i++ )
99d1b93d
VZ
306 {
307 wxChar ch = m_dir[i];
308 switch ( ch )
309 {
310 case _T('/'):
311 // convert to backslash
312 ch = _T('\\');
313
314 // fall through
0bc9b25e 315
99d1b93d
VZ
316 case _T('\\'):
317 while ( i < len - 1 )
318 {
319 wxChar chNext = m_dir[i + 1];
320 if ( chNext != _T('\\') && chNext != _T('/') )
321 break;
322
04d93c3a
CE
323 // ignore the next one, unless it is at the start of a UNC path
324 if (i > 0)
325 i++;
326 else
0b11099d 327 break;
99d1b93d
VZ
328 }
329 // fall through
330
331 default:
332 // normal char
333 dir += ch;
334 }
335 }
336
337 of.lpstrInitialDir = dir.c_str();
2bda0e17 338
e15e548b 339 of.Flags = msw_flags;
0b11099d 340 of.lpfnHook = wxFileDialogHookFunction;
2bda0e17 341
daf32463 342 wxArrayString wildDescriptions, wildFilters;
2bda0e17 343
daf32463 344 size_t items = wxParseCommonDialogsFilter(m_wildCard, wildDescriptions, wildFilters);
2bda0e17 345
daf32463 346 wxASSERT_MSG( items > 0 , _T("empty wildcard list") );
2bda0e17 347
1f2f0331 348 wxString filterBuffer;
2bda0e17 349
daf32463
WS
350 for (i = 0; i < items ; i++)
351 {
352 filterBuffer += wildDescriptions[i];
353 filterBuffer += wxT("|");
354 filterBuffer += wildFilters[i];
355 filterBuffer += wxT("|");
574c0bbf
JS
356 }
357
574c0bbf 358 // Replace | with \0
0bc9b25e 359 for (i = 0; i < filterBuffer.Len(); i++ ) {
223d09f6
KB
360 if ( filterBuffer.GetChar(i) == wxT('|') ) {
361 filterBuffer[i] = wxT('\0');
e15e548b
VZ
362 }
363 }
2bda0e17 364
daf32463 365 of.lpstrFilter = (LPTSTR)filterBuffer.c_str();
cc42eb7a 366 of.nFilterIndex = m_filterIndex + 1;
2bda0e17
KB
367
368 //=== Setting defaultFileName >>=========================================
369
f6bcfd97
BP
370 wxStrncpy( fileNameBuffer, (const wxChar *)m_fileName, wxMAXPATH-1 );
371 fileNameBuffer[ wxMAXPATH-1 ] = wxT('\0');
2bda0e17 372
e15e548b 373 of.lpstrFile = fileNameBuffer; // holds returned filename
f6bcfd97 374 of.nMaxFile = wxMAXPATH;
2bda0e17 375
90bddb85
VZ
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)
382 {
383 const wxChar* extension = filterBuffer;
384 int maxFilter = (int)(of.nFilterIndex*2L) - 1;
385
386 for( int i = 0; i < maxFilter; i++ ) // get extension
387 extension = extension + wxStrlen( extension ) + 1;
388
389 // use dummy name a to avoid assert in AppendExtension
390 defextBuffer = AppendExtension(wxT("a"), extension);
391 if (defextBuffer.StartsWith(wxT("a.")))
392 {
393 defextBuffer.Mid(2);
394 of.lpstrDefExt = defextBuffer.c_str();
395 }
396 }
0b11099d 397
2bda0e17
KB
398 //== Execute FileDialog >>=================================================
399
3f6638b8
VZ
400 bool success = (m_dialogStyle & wxSAVE ? GetSaveFileName(&of)
401 : GetOpenFileName(&of)) != 0;
2bda0e17 402
f6bcfd97
BP
403 DWORD errCode = CommDlgExtendedError();
404
405#ifdef __WIN32__
406 if (!success && (errCode == CDERR_STRUCTSIZE))
407 {
408 // The struct size has changed so try a smaller or bigger size
409
410 int oldStructSize = of.lStructSize;
411 of.lStructSize = oldStructSize - (sizeof(void *) + 2*sizeof(DWORD));
412 success = (m_dialogStyle & wxSAVE) ? (GetSaveFileName(&of) != 0)
413 : (GetOpenFileName(&of) != 0);
414 errCode = CommDlgExtendedError();
415
416 if (!success && (errCode == CDERR_STRUCTSIZE))
417 {
418 of.lStructSize = oldStructSize + (sizeof(void *) + 2*sizeof(DWORD));
419 success = (m_dialogStyle & wxSAVE) ? (GetSaveFileName(&of) != 0)
420 : (GetOpenFileName(&of) != 0);
421 }
422 }
c6603ac2 423#endif // __WIN32__
f6bcfd97 424
2bda0e17
KB
425 if ( success )
426 {
c61f4f6d
VZ
427 m_fileNames.Empty();
428
429 if ( ( m_dialogStyle & wxMULTIPLE ) &&
430#if defined(OFN_EXPLORER)
c39e82f0 431 ( fileNameBuffer[of.nFileOffset-1] == wxT('\0') )
c61f4f6d 432#else
c39e82f0 433 ( fileNameBuffer[of.nFileOffset-1] == wxT(' ') )
c61f4f6d 434#endif // OFN_EXPLORER
c39e82f0 435 )
c61f4f6d
VZ
436 {
437#if defined(OFN_EXPLORER)
438 m_dir = fileNameBuffer;
439 i = of.nFileOffset;
440 m_fileName = &fileNameBuffer[i];
441 m_fileNames.Add(m_fileName);
442 i += m_fileName.Len() + 1;
443
444 while (fileNameBuffer[i] != wxT('\0'))
445 {
446 m_fileNames.Add(&fileNameBuffer[i]);
447 i += wxStrlen(&fileNameBuffer[i]) + 1;
448 }
449#else
c6603ac2 450 wxStringTokenizer toke(fileNameBuffer, _T(" \t\r\n"));
c61f4f6d
VZ
451 m_dir = toke.GetNextToken();
452 m_fileName = toke.GetNextToken();
453 m_fileNames.Add(m_fileName);
454
455 while (toke.HasMoreTokens())
456 m_fileNames.Add(toke.GetNextToken());
457#endif // OFN_EXPLORER
458
459 wxString dir(m_dir);
460 if ( m_dir.Last() != _T('\\') )
461 dir += _T('\\');
462
c61f4f6d 463 m_path = dir + m_fileName;
f0f43012 464 m_filterIndex = (int)of.nFilterIndex - 1;
c61f4f6d
VZ
465 }
466 else
467 {
c61f4f6d 468 //=== Adding the correct extension >>=================================
2bda0e17 469
cc42eb7a 470 m_filterIndex = (int)of.nFilterIndex - 1;
2bda0e17 471
0b11099d 472 if ( !of.nFileExtension ||
c6603ac2
VS
473 (of.nFileExtension && fileNameBuffer[of.nFileExtension] == wxT('\0')) )
474 {
475 // User has typed a filename without an extension:
f74172ab
VZ
476 const wxChar* extension = filterBuffer;
477 int maxFilter = (int)(of.nFilterIndex*2L) - 1;
2bda0e17 478
f74172ab
VZ
479 for( int i = 0; i < maxFilter; i++ ) // get extension
480 extension = extension + wxStrlen( extension ) + 1;
a039ccbf 481
f74172ab
VZ
482 m_fileName = AppendExtension(fileNameBuffer, extension);
483 wxStrncpy(fileNameBuffer, m_fileName.c_str(), wxMin(m_fileName.Len(), wxMAXPATH-1));
484 fileNameBuffer[wxMin(m_fileName.Len(), wxMAXPATH-1)] = wxT('\0');
2bda0e17 485 }
2bda0e17 486
c61f4f6d
VZ
487 m_path = fileNameBuffer;
488 m_fileName = wxFileNameFromPath(fileNameBuffer);
489 m_fileNames.Add(m_fileName);
490 m_dir = wxPathOnly(fileNameBuffer);
491 }
7cc98b3e
VZ
492 }
493 else
494 {
495 // common dialog failed - why?
496#ifdef __WXDEBUG__
497 DWORD dwErr = CommDlgExtendedError();
498 if ( dwErr != 0 )
499 {
500 // this msg is only for developers
223d09f6 501 wxLogError(wxT("Common dialog failed with error code %0lx."),
7cc98b3e
VZ
502 dwErr);
503 }
504 //else: it was just cancelled
505#endif
506 }
2bda0e17 507
7cc98b3e 508 return success ? wxID_OK : wxID_CANCEL;
2bda0e17
KB
509
510}
511
3180bc0e 512#endif // wxUSE_FILEDLG && !(__SMARTPHONE__ && __WXWINCE__)
c61f4f6d 513