]> git.saurik.com Git - wxWidgets.git/blob - src/generic/filectrlg.cpp
Fix wrong return value in the changes of r73365.
[wxWidgets.git] / src / generic / filectrlg.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/generic/filectrlg.cpp
3 // Purpose:     wxGenericFileCtrl Implementation
4 // Author:      Diaa M. Sami
5 // Created:     2007-07-07
6 // RCS-ID:      $Id$
7 // Copyright:   (c) Diaa M. Sami
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 #include "wx/wxprec.h"
12
13 #ifdef __BORLANDC__
14 #pragma hdrstop
15 #endif
16
17 #if wxUSE_FILECTRL
18
19 #include "wx/generic/filectrlg.h"
20
21 #ifndef WX_PRECOMP
22     #include "wx/settings.h"
23     #include "wx/sizer.h"
24     #include "wx/stattext.h"
25     #include "wx/checkbox.h"
26     #include "wx/msgdlg.h"
27     #include "wx/log.h"
28     #include "wx/filedlg.h"
29 #endif
30
31 #include "wx/clntdata.h"
32 #include "wx/file.h"        // for wxS_IXXX constants only
33 #include "wx/generic/dirctrlg.h" // for wxFileIconsTable
34 #include "wx/dir.h"
35 #include "wx/tokenzr.h"
36 #include "wx/imaglist.h"
37
38 #ifdef __WINDOWS__
39     #include "wx/msw/wrapwin.h"
40 #endif
41
42 #if defined(__WXWINCE__)
43 #define IsTopMostDir(dir) (dir == wxT("\\") || dir == wxT("/"))
44 #elif (defined(__DOS__) || defined(__WINDOWS__) || defined (__OS2__))
45 #define IsTopMostDir(dir)   (dir.empty())
46 #else
47 #define IsTopMostDir(dir)   (dir == wxT("/"))
48 #endif
49
50
51 // ----------------------------------------------------------------------------
52 // private functions
53 // ----------------------------------------------------------------------------
54
55 static
56 int wxCALLBACK wxFileDataNameCompare( wxIntPtr data1, wxIntPtr data2, wxIntPtr sortOrder)
57 {
58      wxFileData *fd1 = (wxFileData *)wxUIntToPtr(data1);
59      wxFileData *fd2 = (wxFileData *)wxUIntToPtr(data2);
60
61      if (fd1->GetFileName() == wxT(".."))
62          return -sortOrder;
63      if (fd2->GetFileName() == wxT(".."))
64          return sortOrder;
65      if (fd1->IsDir() && !fd2->IsDir())
66          return -sortOrder;
67      if (fd2->IsDir() && !fd1->IsDir())
68          return sortOrder;
69
70      return sortOrder*wxStrcmp( fd1->GetFileName(), fd2->GetFileName() );
71 }
72
73 static
74 int wxCALLBACK wxFileDataSizeCompare(wxIntPtr data1, wxIntPtr data2, wxIntPtr sortOrder)
75 {
76      wxFileData *fd1 = (wxFileData *)wxUIntToPtr(data1);
77      wxFileData *fd2 = (wxFileData *)wxUIntToPtr(data2);
78
79      if (fd1->GetFileName() == wxT(".."))
80          return -sortOrder;
81      if (fd2->GetFileName() == wxT(".."))
82          return sortOrder;
83      if (fd1->IsDir() && !fd2->IsDir())
84          return -sortOrder;
85      if (fd2->IsDir() && !fd1->IsDir())
86          return sortOrder;
87      if (fd1->IsLink() && !fd2->IsLink())
88          return -sortOrder;
89      if (fd2->IsLink() && !fd1->IsLink())
90          return sortOrder;
91
92      return fd1->GetSize() > fd2->GetSize() ? sortOrder : -sortOrder;
93 }
94
95 static
96 int wxCALLBACK wxFileDataTypeCompare(wxIntPtr data1, wxIntPtr data2, wxIntPtr sortOrder)
97 {
98      wxFileData *fd1 = (wxFileData *)wxUIntToPtr(data1);
99      wxFileData *fd2 = (wxFileData *)wxUIntToPtr(data2);
100
101      if (fd1->GetFileName() == wxT(".."))
102          return -sortOrder;
103      if (fd2->GetFileName() == wxT(".."))
104          return sortOrder;
105      if (fd1->IsDir() && !fd2->IsDir())
106          return -sortOrder;
107      if (fd2->IsDir() && !fd1->IsDir())
108          return sortOrder;
109      if (fd1->IsLink() && !fd2->IsLink())
110          return -sortOrder;
111      if (fd2->IsLink() && !fd1->IsLink())
112          return sortOrder;
113
114      return sortOrder*wxStrcmp( fd1->GetFileType(), fd2->GetFileType() );
115 }
116
117 static
118 int wxCALLBACK wxFileDataTimeCompare(wxIntPtr data1, wxIntPtr data2, wxIntPtr sortOrder)
119 {
120      wxFileData *fd1 = (wxFileData *)wxUIntToPtr(data1);
121      wxFileData *fd2 = (wxFileData *)wxUIntToPtr(data2);
122
123      if (fd1->GetFileName() == wxT(".."))
124          return -sortOrder;
125      if (fd2->GetFileName() == wxT(".."))
126          return sortOrder;
127      if (fd1->IsDir() && !fd2->IsDir())
128          return -sortOrder;
129      if (fd2->IsDir() && !fd1->IsDir())
130          return sortOrder;
131
132      return fd1->GetDateTime().IsLaterThan(fd2->GetDateTime()) ? sortOrder : -sortOrder;
133 }
134
135 // defined in src/generic/dirctrlg.cpp
136 extern size_t wxGetAvailableDrives(wxArrayString &paths, wxArrayString &names, wxArrayInt &icon_ids);
137
138 //-----------------------------------------------------------------------------
139 //  wxFileData
140 //-----------------------------------------------------------------------------
141
142 wxFileData::wxFileData( const wxString &filePath, const wxString &fileName, fileType type, int image_id )
143 {
144     Init();
145     m_fileName = fileName;
146     m_filePath = filePath;
147     m_type = type;
148     m_image = image_id;
149
150     ReadData();
151 }
152
153 void wxFileData::Init()
154 {
155     m_size = 0;
156     m_type = wxFileData::is_file;
157     m_image = wxFileIconsTable::file;
158 }
159
160 void wxFileData::Copy( const wxFileData& fileData )
161 {
162     m_fileName = fileData.GetFileName();
163     m_filePath = fileData.GetFilePath();
164     m_size = fileData.GetSize();
165     m_dateTime = fileData.GetDateTime();
166     m_permissions = fileData.GetPermissions();
167     m_type = fileData.GetType();
168     m_image = fileData.GetImageId();
169 }
170
171 void wxFileData::ReadData()
172 {
173     if (IsDrive())
174     {
175         m_size = 0;
176         return;
177     }
178
179 #if defined(__DOS__) || (defined(__WINDOWS__) && !defined(__WXWINCE__)) || defined(__OS2__)
180     // c:\.. is a drive don't stat it
181     if ((m_fileName == wxT("..")) && (m_filePath.length() <= 5))
182     {
183         m_type = is_drive;
184         m_size = 0;
185         return;
186     }
187 #endif // __DOS__ || __WINDOWS__
188
189 #ifdef __WXWINCE__
190
191     // WinCE
192
193     DWORD fileAttribs = GetFileAttributes(m_filePath.fn_str());
194     m_type |= (fileAttribs & FILE_ATTRIBUTE_DIRECTORY) != 0 ? is_dir : 0;
195
196     wxString p, f, ext;
197     wxFileName::SplitPath(m_filePath, & p, & f, & ext);
198     if (wxStricmp(ext, wxT("exe")) == 0)
199         m_type |= is_exe;
200
201     // Find out size
202     m_size = 0;
203     HANDLE fileHandle = CreateFile(m_filePath.fn_str(),
204             GENERIC_READ,
205             FILE_SHARE_READ,
206             NULL,
207             OPEN_EXISTING,
208             FILE_ATTRIBUTE_NORMAL,
209             NULL);
210
211     if (fileHandle != INVALID_HANDLE_VALUE)
212     {
213         m_size = GetFileSize(fileHandle, 0);
214         CloseHandle(fileHandle);
215     }
216
217     m_dateTime = wxFileModificationTime(m_filePath);
218
219 #else
220
221     // OTHER PLATFORMS
222
223     wxStructStat buff;
224
225 #if defined(__UNIX__) && (!defined( __OS2__ ) && !defined(__VMS))
226     const bool hasStat = lstat( m_filePath.fn_str(), &buff ) == 0;
227     if ( hasStat )
228         m_type |= S_ISLNK(buff.st_mode) ? is_link : 0;
229 #else // no lstat()
230     const bool hasStat = wxStat( m_filePath, &buff ) == 0;
231 #endif
232
233     if ( hasStat )
234     {
235         m_type |= (buff.st_mode & S_IFDIR) != 0 ? is_dir : 0;
236         m_type |= (buff.st_mode & wxS_IXUSR) != 0 ? is_exe : 0;
237
238         m_size = buff.st_size;
239
240         m_dateTime = buff.st_mtime;
241     }
242 #endif
243     // __WXWINCE__
244
245 #if defined(__UNIX__)
246     if ( hasStat )
247     {
248         m_permissions.Printf(wxT("%c%c%c%c%c%c%c%c%c"),
249                              buff.st_mode & wxS_IRUSR ? wxT('r') : wxT('-'),
250                              buff.st_mode & wxS_IWUSR ? wxT('w') : wxT('-'),
251                              buff.st_mode & wxS_IXUSR ? wxT('x') : wxT('-'),
252                              buff.st_mode & wxS_IRGRP ? wxT('r') : wxT('-'),
253                              buff.st_mode & wxS_IWGRP ? wxT('w') : wxT('-'),
254                              buff.st_mode & wxS_IXGRP ? wxT('x') : wxT('-'),
255                              buff.st_mode & wxS_IROTH ? wxT('r') : wxT('-'),
256                              buff.st_mode & wxS_IWOTH ? wxT('w') : wxT('-'),
257                              buff.st_mode & wxS_IXOTH ? wxT('x') : wxT('-'));
258     }
259 #elif defined(__WIN32__)
260     DWORD attribs = ::GetFileAttributes(m_filePath.c_str());
261     if (attribs != (DWORD)-1)
262     {
263         m_permissions.Printf(wxT("%c%c%c%c"),
264                              attribs & FILE_ATTRIBUTE_ARCHIVE  ? wxT('A') : wxT(' '),
265                              attribs & FILE_ATTRIBUTE_READONLY ? wxT('R') : wxT(' '),
266                              attribs & FILE_ATTRIBUTE_HIDDEN   ? wxT('H') : wxT(' '),
267                              attribs & FILE_ATTRIBUTE_SYSTEM   ? wxT('S') : wxT(' '));
268     }
269 #endif
270
271     // try to get a better icon
272     if (m_image == wxFileIconsTable::file)
273     {
274         if (m_fileName.Find(wxT('.'), true) != wxNOT_FOUND)
275         {
276             m_image = wxTheFileIconsTable->GetIconID( m_fileName.AfterLast(wxT('.')));
277         } else if (IsExe())
278         {
279             m_image = wxFileIconsTable::executable;
280         }
281     }
282 }
283
284 wxString wxFileData::GetFileType() const
285 {
286     if (IsDir())
287         return _("<DIR>");
288     else if (IsLink())
289         return _("<LINK>");
290     else if (IsDrive())
291         return _("<DRIVE>");
292     else if (m_fileName.Find(wxT('.'), true) != wxNOT_FOUND)
293         return m_fileName.AfterLast(wxT('.'));
294
295     return wxEmptyString;
296 }
297
298 wxString wxFileData::GetModificationTime() const
299 {
300     // want time as 01:02 so they line up nicely, no %r in WIN32
301     return m_dateTime.FormatDate() + wxT(" ") + m_dateTime.Format(wxT("%I:%M:%S %p"));
302 }
303
304 wxString wxFileData::GetHint() const
305 {
306     wxString s = m_filePath;
307     s += wxT("  ");
308
309     if (IsDir())
310         s += _("<DIR>");
311     else if (IsLink())
312         s += _("<LINK>");
313     else if (IsDrive())
314         s += _("<DRIVE>");
315     else // plain file
316         s += wxString::Format(wxPLURAL("%ld byte", "%ld bytes", m_size),
317                               wxLongLong(m_size).ToString().c_str());
318
319     s += wxT(' ');
320
321     if ( !IsDrive() )
322     {
323         s << GetModificationTime()
324           << wxT("  ")
325           << m_permissions;
326     }
327
328     return s;
329 }
330
331 wxString wxFileData::GetEntry( fileListFieldType num ) const
332 {
333     wxString s;
334     switch ( num )
335     {
336         case FileList_Name:
337             s = m_fileName;
338             break;
339
340         case FileList_Size:
341             if (!IsDir() && !IsLink() && !IsDrive())
342                 s = wxLongLong(m_size).ToString();
343             break;
344
345         case FileList_Type:
346             s = GetFileType();
347             break;
348
349         case FileList_Time:
350             if (!IsDrive())
351                 s = GetModificationTime();
352             break;
353
354 #if defined(__UNIX__) || defined(__WIN32__)
355         case FileList_Perm:
356             s = m_permissions;
357             break;
358 #endif // defined(__UNIX__) || defined(__WIN32__)
359
360         default:
361             wxFAIL_MSG( wxT("unexpected field in wxFileData::GetEntry()") );
362     }
363
364     return s;
365 }
366
367 void wxFileData::SetNewName( const wxString &filePath, const wxString &fileName )
368 {
369     m_fileName = fileName;
370     m_filePath = filePath;
371 }
372
373 void wxFileData::MakeItem( wxListItem &item )
374 {
375     item.m_text = m_fileName;
376     item.ClearAttributes();
377     if (IsExe())
378         item.SetTextColour(*wxRED);
379     if (IsDir())
380         item.SetTextColour(*wxBLUE);
381
382     item.m_image = m_image;
383
384     if (IsLink())
385     {
386         wxColour dg = wxTheColourDatabase->Find( wxT("MEDIUM GREY") );
387         if ( dg.IsOk() )
388             item.SetTextColour(dg);
389     }
390     item.m_data = wxPtrToUInt(this);
391 }
392
393 //-----------------------------------------------------------------------------
394 //  wxFileListCtrl
395 //-----------------------------------------------------------------------------
396
397 IMPLEMENT_DYNAMIC_CLASS(wxFileListCtrl,wxListCtrl)
398
399 BEGIN_EVENT_TABLE(wxFileListCtrl,wxListCtrl)
400     EVT_LIST_DELETE_ITEM(wxID_ANY, wxFileListCtrl::OnListDeleteItem)
401     EVT_LIST_DELETE_ALL_ITEMS(wxID_ANY, wxFileListCtrl::OnListDeleteAllItems)
402     EVT_LIST_END_LABEL_EDIT(wxID_ANY, wxFileListCtrl::OnListEndLabelEdit)
403     EVT_LIST_COL_CLICK(wxID_ANY, wxFileListCtrl::OnListColClick)
404 END_EVENT_TABLE()
405
406
407 wxFileListCtrl::wxFileListCtrl()
408 {
409     m_showHidden = false;
410     m_sort_forward = true;
411     m_sort_field = wxFileData::FileList_Name;
412 }
413
414 wxFileListCtrl::wxFileListCtrl(wxWindow *win,
415                        wxWindowID id,
416                        const wxString& wild,
417                        bool showHidden,
418                        const wxPoint& pos,
419                        const wxSize& size,
420                        long style,
421                        const wxValidator &validator,
422                        const wxString &name)
423           : wxListCtrl(win, id, pos, size, style, validator, name),
424             m_wild(wild)
425 {
426     wxImageList *imageList = wxTheFileIconsTable->GetSmallImageList();
427
428     SetImageList( imageList, wxIMAGE_LIST_SMALL );
429
430     m_showHidden = showHidden;
431
432     m_sort_forward = true;
433     m_sort_field = wxFileData::FileList_Name;
434
435     m_dirName = wxT("*");
436
437     if (style & wxLC_REPORT)
438         ChangeToReportMode();
439 }
440
441 void wxFileListCtrl::ChangeToListMode()
442 {
443     ClearAll();
444     SetSingleStyle( wxLC_LIST );
445     UpdateFiles();
446 }
447
448 void wxFileListCtrl::ChangeToReportMode()
449 {
450     ClearAll();
451     SetSingleStyle( wxLC_REPORT );
452
453     // do this since WIN32 does mm/dd/yy UNIX does mm/dd/yyyy
454     // don't hardcode since mm/dd is dd/mm elsewhere
455     int w, h;
456     wxDateTime dt(22, wxDateTime::Dec, 2002, 22, 22, 22);
457     wxString txt = dt.FormatDate() + wxT("22") + dt.Format(wxT("%I:%M:%S %p"));
458     GetTextExtent(txt, &w, &h);
459
460     InsertColumn( 0, _("Name"), wxLIST_FORMAT_LEFT, w );
461     InsertColumn( 1, _("Size"), wxLIST_FORMAT_LEFT, w/2 );
462     InsertColumn( 2, _("Type"), wxLIST_FORMAT_LEFT, w/2 );
463     InsertColumn( 3, _("Modified"), wxLIST_FORMAT_LEFT, w );
464 #if defined(__UNIX__)
465     GetTextExtent(wxT("Permissions 2"), &w, &h);
466     InsertColumn( 4, _("Permissions"), wxLIST_FORMAT_LEFT, w );
467 #elif defined(__WIN32__)
468     GetTextExtent(wxT("Attributes 2"), &w, &h);
469     InsertColumn( 4, _("Attributes"), wxLIST_FORMAT_LEFT, w );
470 #endif
471
472     UpdateFiles();
473 }
474
475 void wxFileListCtrl::ChangeToSmallIconMode()
476 {
477     ClearAll();
478     SetSingleStyle( wxLC_SMALL_ICON );
479     UpdateFiles();
480 }
481
482 void wxFileListCtrl::ShowHidden( bool show )
483 {
484     m_showHidden = show;
485     UpdateFiles();
486 }
487
488 long wxFileListCtrl::Add( wxFileData *fd, wxListItem &item )
489 {
490     long ret = -1;
491     item.m_mask = wxLIST_MASK_TEXT + wxLIST_MASK_DATA + wxLIST_MASK_IMAGE;
492     fd->MakeItem( item );
493     long my_style = GetWindowStyleFlag();
494     if (my_style & wxLC_REPORT)
495     {
496         ret = InsertItem( item );
497         for (int i = 1; i < wxFileData::FileList_Max; i++)
498             SetItem( item.m_itemId, i, fd->GetEntry((wxFileData::fileListFieldType)i) );
499     }
500     else if ((my_style & wxLC_LIST) || (my_style & wxLC_SMALL_ICON))
501     {
502         ret = InsertItem( item );
503     }
504     return ret;
505 }
506
507 void wxFileListCtrl::UpdateItem(const wxListItem &item)
508 {
509     wxFileData *fd = (wxFileData*)GetItemData(item);
510     wxCHECK_RET(fd, wxT("invalid filedata"));
511
512     fd->ReadData();
513
514     SetItemText(item, fd->GetFileName());
515     SetItemImage(item, fd->GetImageId());
516
517     if (GetWindowStyleFlag() & wxLC_REPORT)
518     {
519         for (int i = 1; i < wxFileData::FileList_Max; i++)
520             SetItem( item.m_itemId, i, fd->GetEntry((wxFileData::fileListFieldType)i) );
521     }
522 }
523
524 void wxFileListCtrl::UpdateFiles()
525 {
526     // don't do anything before ShowModal() call which sets m_dirName
527     if ( m_dirName == wxT("*") )
528         return;
529
530     wxBusyCursor bcur; // this may take a while...
531
532     DeleteAllItems();
533
534     wxListItem item;
535     item.m_itemId = 0;
536     item.m_col = 0;
537
538 #if (defined(__WINDOWS__) || defined(__DOS__) || defined(__WXMAC__) || defined(__OS2__)) && !defined(__WXWINCE__)
539     if ( IsTopMostDir(m_dirName) )
540     {
541         wxArrayString names, paths;
542         wxArrayInt icons;
543         const size_t count = wxGetAvailableDrives(paths, names, icons);
544
545         for ( size_t n = 0; n < count; n++ )
546         {
547             // use paths[n] as the drive name too as our HandleAction() can't
548             // deal with the drive names (of the form "System (C:)") currently
549             // as it mistakenly treats them as file names
550             //
551             // it would be preferable to show names, and not paths, in the
552             // dialog just as the native dialog does but for this we must:
553             //  a) store the item type as item data and modify HandleAction()
554             //     to use it instead of wxDirExists() to check whether the item
555             //     is a directory
556             //  b) store the drives by their drive letters and not their
557             //     descriptions as otherwise it's pretty confusing to the user
558             wxFileData *fd = new wxFileData(paths[n], paths[n],
559                                             wxFileData::is_drive, icons[n]);
560             if (Add(fd, item) != -1)
561                 item.m_itemId++;
562             else
563                 delete fd;
564         }
565     }
566     else
567 #endif // defined(__DOS__) || defined(__WINDOWS__)
568     {
569         // Real directory...
570         if ( !IsTopMostDir(m_dirName) && !m_dirName.empty() )
571         {
572             wxString p(wxPathOnly(m_dirName));
573 #if (defined(__UNIX__) || defined(__WXWINCE__)) && !defined(__OS2__)
574             if (p.empty()) p = wxT("/");
575 #endif // __UNIX__
576             wxFileData *fd = new wxFileData(p, wxT(".."), wxFileData::is_dir, wxFileIconsTable::folder);
577             if (Add(fd, item) != -1)
578                 item.m_itemId++;
579             else
580                 delete fd;
581         }
582
583         wxString dirname(m_dirName);
584 #if defined(__DOS__) || defined(__WINDOWS__) || defined(__OS2__)
585         if (dirname.length() == 2 && dirname[1u] == wxT(':'))
586             dirname << wxT('\\');
587 #endif // defined(__DOS__) || defined(__WINDOWS__) || defined(__OS2__)
588
589         if (dirname.empty())
590             dirname = wxFILE_SEP_PATH;
591
592         wxLogNull logNull;
593         wxDir dir(dirname);
594
595         if ( dir.IsOpened() )
596         {
597             wxString dirPrefix(dirname);
598             if (dirPrefix.Last() != wxFILE_SEP_PATH)
599                 dirPrefix += wxFILE_SEP_PATH;
600
601             int hiddenFlag = m_showHidden ? wxDIR_HIDDEN : 0;
602
603             bool cont;
604             wxString f;
605
606             // Get the directories first (not matched against wildcards):
607             cont = dir.GetFirst(&f, wxEmptyString, wxDIR_DIRS | hiddenFlag);
608             while (cont)
609             {
610                 wxFileData *fd = new wxFileData(dirPrefix + f, f, wxFileData::is_dir, wxFileIconsTable::folder);
611                 if (Add(fd, item) != -1)
612                     item.m_itemId++;
613                 else
614                     delete fd;
615
616                 cont = dir.GetNext(&f);
617             }
618
619             // Tokenize the wildcard string, so we can handle more than 1
620             // search pattern in a wildcard.
621             wxStringTokenizer tokenWild(m_wild, wxT(";"));
622             while ( tokenWild.HasMoreTokens() )
623             {
624                 cont = dir.GetFirst(&f, tokenWild.GetNextToken(),
625                                         wxDIR_FILES | hiddenFlag);
626                 while (cont)
627                 {
628                     wxFileData *fd = new wxFileData(dirPrefix + f, f, wxFileData::is_file, wxFileIconsTable::file);
629                     if (Add(fd, item) != -1)
630                         item.m_itemId++;
631                     else
632                         delete fd;
633
634                     cont = dir.GetNext(&f);
635                 }
636             }
637         }
638     }
639
640     SortItems(m_sort_field, m_sort_forward);
641 }
642
643 void wxFileListCtrl::SetWild( const wxString &wild )
644 {
645     if (wild.Find(wxT('|')) != wxNOT_FOUND)
646         return;
647
648     m_wild = wild;
649     UpdateFiles();
650 }
651
652 void wxFileListCtrl::MakeDir()
653 {
654     wxString new_name( _("NewName") );
655     wxString path( m_dirName );
656     path += wxFILE_SEP_PATH;
657     path += new_name;
658     if (wxFileExists(path))
659     {
660         // try NewName0, NewName1 etc.
661         int i = 0;
662         do {
663             new_name = _("NewName");
664             wxString num;
665             num.Printf( wxT("%d"), i );
666             new_name += num;
667
668             path = m_dirName;
669             path += wxFILE_SEP_PATH;
670             path += new_name;
671             i++;
672         } while (wxFileExists(path));
673     }
674
675     wxLogNull log;
676     if (!wxMkdir(path))
677     {
678         wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
679         dialog.ShowModal();
680         return;
681     }
682
683     wxFileData *fd = new wxFileData( path, new_name, wxFileData::is_dir, wxFileIconsTable::folder );
684     wxListItem item;
685     item.m_itemId = 0;
686     item.m_col = 0;
687     long itemid = Add( fd, item );
688
689     if (itemid != -1)
690     {
691         SortItems(m_sort_field, m_sort_forward);
692         itemid = FindItem( 0, wxPtrToUInt(fd) );
693         EnsureVisible( itemid );
694         EditLabel( itemid );
695     }
696     else
697         delete fd;
698 }
699
700 void wxFileListCtrl::GoToParentDir()
701 {
702     if (!IsTopMostDir(m_dirName))
703     {
704         size_t len = m_dirName.length();
705         if (wxEndsWithPathSeparator(m_dirName))
706             m_dirName.Remove( len-1, 1 );
707         wxString fname( wxFileNameFromPath(m_dirName) );
708         m_dirName = wxPathOnly( m_dirName );
709 #if defined(__DOS__) || defined(__WINDOWS__) || defined(__OS2__)
710         if (!m_dirName.empty())
711         {
712             if (m_dirName.Last() == wxT('.'))
713                 m_dirName = wxEmptyString;
714         }
715 #elif defined(__UNIX__)
716         if (m_dirName.empty())
717             m_dirName = wxT("/");
718 #endif
719         UpdateFiles();
720         long id = FindItem( 0, fname );
721         if (id != wxNOT_FOUND)
722         {
723             SetItemState( id, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
724             EnsureVisible( id );
725         }
726     }
727 }
728
729 void wxFileListCtrl::GoToHomeDir()
730 {
731     wxString s = wxGetUserHome( wxString() );
732     GoToDir(s);
733 }
734
735 void wxFileListCtrl::GoToDir( const wxString &dir )
736 {
737     if (!wxDirExists(dir)) return;
738
739     m_dirName = dir;
740     UpdateFiles();
741
742     SetItemState( 0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
743
744     EnsureVisible( 0 );
745 }
746
747 void wxFileListCtrl::FreeItemData(wxListItem& item)
748 {
749     if ( item.m_data )
750     {
751         wxFileData *fd = (wxFileData*)item.m_data;
752         delete fd;
753
754         item.m_data = 0;
755     }
756 }
757
758 void wxFileListCtrl::OnListDeleteItem( wxListEvent &event )
759 {
760     FreeItemData(event.m_item);
761 }
762
763 void wxFileListCtrl::OnListDeleteAllItems( wxListEvent & WXUNUSED(event) )
764 {
765     FreeAllItemsData();
766 }
767
768 void wxFileListCtrl::FreeAllItemsData()
769 {
770     wxListItem item;
771     item.m_mask = wxLIST_MASK_DATA;
772
773     item.m_itemId = GetNextItem( -1, wxLIST_NEXT_ALL );
774     while ( item.m_itemId != -1 )
775     {
776         GetItem( item );
777         FreeItemData(item);
778         item.m_itemId = GetNextItem( item.m_itemId, wxLIST_NEXT_ALL );
779     }
780 }
781
782 void wxFileListCtrl::OnListEndLabelEdit( wxListEvent &event )
783 {
784     wxFileData *fd = (wxFileData*)event.m_item.m_data;
785     wxASSERT( fd );
786
787     if ((event.GetLabel().empty()) ||
788         (event.GetLabel() == wxT(".")) ||
789         (event.GetLabel() == wxT("..")) ||
790         (event.GetLabel().First( wxFILE_SEP_PATH ) != wxNOT_FOUND))
791     {
792         wxMessageDialog dialog(this, _("Illegal directory name."), _("Error"), wxOK | wxICON_ERROR );
793         dialog.ShowModal();
794         event.Veto();
795         return;
796     }
797
798     wxString new_name( wxPathOnly( fd->GetFilePath() ) );
799     new_name += wxFILE_SEP_PATH;
800     new_name += event.GetLabel();
801
802     wxLogNull log;
803
804     if (wxFileExists(new_name))
805     {
806         wxMessageDialog dialog(this, _("File name exists already."), _("Error"), wxOK | wxICON_ERROR );
807         dialog.ShowModal();
808         event.Veto();
809     }
810
811     if (wxRenameFile(fd->GetFilePath(),new_name))
812     {
813         fd->SetNewName( new_name, event.GetLabel() );
814
815         SetItemState( event.GetItem(), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
816
817         UpdateItem( event.GetItem() );
818         EnsureVisible( event.GetItem() );
819     }
820     else
821     {
822         wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
823         dialog.ShowModal();
824         event.Veto();
825     }
826 }
827
828 void wxFileListCtrl::OnListColClick( wxListEvent &event )
829 {
830     int col = event.GetColumn();
831
832     switch (col)
833     {
834         case wxFileData::FileList_Name :
835         case wxFileData::FileList_Size :
836         case wxFileData::FileList_Type :
837         case wxFileData::FileList_Time : break;
838         default : return;
839     }
840
841     if ((wxFileData::fileListFieldType)col == m_sort_field)
842         m_sort_forward = !m_sort_forward;
843     else
844         m_sort_field = (wxFileData::fileListFieldType)col;
845
846     SortItems(m_sort_field, m_sort_forward);
847 }
848
849 void wxFileListCtrl::SortItems(wxFileData::fileListFieldType field, bool forward)
850 {
851     m_sort_field = field;
852     m_sort_forward = forward;
853     const long sort_dir = forward ? 1 : -1;
854
855     switch (m_sort_field)
856     {
857         case wxFileData::FileList_Size :
858             wxListCtrl::SortItems(wxFileDataSizeCompare, sort_dir);
859             break;
860
861         case wxFileData::FileList_Type :
862             wxListCtrl::SortItems(wxFileDataTypeCompare, sort_dir);
863             break;
864
865         case wxFileData::FileList_Time :
866             wxListCtrl::SortItems(wxFileDataTimeCompare, sort_dir);
867             break;
868
869         case wxFileData::FileList_Name :
870         default :
871             wxListCtrl::SortItems(wxFileDataNameCompare, sort_dir);
872             break;
873     }
874 }
875
876 wxFileListCtrl::~wxFileListCtrl()
877 {
878     // Normally the data are freed via an EVT_LIST_DELETE_ALL_ITEMS event and
879     // wxFileListCtrl::OnListDeleteAllItems. But if the event is generated after
880     // the destruction of the wxFileListCtrl we need to free any data here:
881     FreeAllItemsData();
882 }
883
884 #define  ID_CHOICE        (wxID_FILECTRL + 1)
885 #define  ID_TEXT          (wxID_FILECTRL + 2)
886 #define  ID_FILELIST_CTRL (wxID_FILECTRL + 3)
887 #define  ID_CHECK         (wxID_FILECTRL + 4)
888
889 ///////////////////////////////////////////////////////////////////////////////
890 // wxGenericFileCtrl implementation
891 ///////////////////////////////////////////////////////////////////////////////
892
893 IMPLEMENT_DYNAMIC_CLASS( wxGenericFileCtrl, wxNavigationEnabled<wxControl> )
894
895 BEGIN_EVENT_TABLE( wxGenericFileCtrl, wxNavigationEnabled<wxControl> )
896     EVT_LIST_ITEM_SELECTED( ID_FILELIST_CTRL, wxGenericFileCtrl::OnSelected )
897     EVT_LIST_ITEM_ACTIVATED( ID_FILELIST_CTRL, wxGenericFileCtrl::OnActivated )
898     EVT_CHOICE( ID_CHOICE, wxGenericFileCtrl::OnChoiceFilter )
899     EVT_TEXT_ENTER( ID_TEXT, wxGenericFileCtrl::OnTextEnter )
900     EVT_TEXT( ID_TEXT, wxGenericFileCtrl::OnTextChange )
901     EVT_CHECKBOX( ID_CHECK, wxGenericFileCtrl::OnCheck )
902 END_EVENT_TABLE()
903
904 bool wxGenericFileCtrl::Create( wxWindow *parent,
905                                 wxWindowID id,
906                                 const wxString& defaultDirectory,
907                                 const wxString& defaultFileName,
908                                 const wxString& wildCard,
909                                 long style,
910                                 const wxPoint& pos,
911                                 const wxSize& size,
912                                 const wxString& name )
913 {
914     this->m_style = style;
915     m_inSelected = false;
916     m_noSelChgEvent = false;
917     m_check = NULL;
918
919     // check that the styles are not contradictory
920     wxASSERT_MSG( !( ( m_style & wxFC_SAVE ) && ( m_style & wxFC_OPEN ) ),
921                   wxT( "can't specify both wxFC_SAVE and wxFC_OPEN at once" ) );
922
923     wxASSERT_MSG( !( ( m_style & wxFC_SAVE ) && ( m_style & wxFC_MULTIPLE ) ),
924                   wxT( "wxFC_MULTIPLE can't be used with wxFC_SAVE" ) );
925
926     wxNavigationEnabled<wxControl>::Create( parent, id,
927                                             pos, size,
928                                             wxTAB_TRAVERSAL,
929                                             wxDefaultValidator,
930                                             name );
931
932     m_dir = defaultDirectory;
933
934     m_ignoreChanges = true;
935
936     if ( ( m_dir.empty() ) || ( m_dir == wxT( "." ) ) )
937     {
938         m_dir = wxGetCwd();
939         if ( m_dir.empty() )
940             m_dir = wxFILE_SEP_PATH;
941     }
942
943     const size_t len = m_dir.length();
944     if ( ( len > 1 ) && ( wxEndsWithPathSeparator( m_dir ) ) )
945         m_dir.Remove( len - 1, 1 );
946
947     m_filterExtension = wxEmptyString;
948
949     // layout
950
951     const bool is_pda = ( wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA );
952
953     wxBoxSizer *mainsizer = new wxBoxSizer( wxVERTICAL );
954
955     wxBoxSizer *staticsizer = new wxBoxSizer( wxHORIZONTAL );
956     if ( is_pda )
957         staticsizer->Add( new wxStaticText( this, wxID_ANY, _( "Current directory:" ) ),
958                           wxSizerFlags().DoubleBorder(wxRIGHT) );
959     m_static = new wxStaticText( this, wxID_ANY, m_dir );
960     staticsizer->Add( m_static, 1 );
961     mainsizer->Add( staticsizer, wxSizerFlags().Expand().Border());
962
963     long style2 = wxLC_LIST;
964     if ( !( m_style & wxFC_MULTIPLE ) )
965         style2 |= wxLC_SINGLE_SEL;
966
967 #ifdef __WXWINCE__
968     style2 |= wxSIMPLE_BORDER;
969 #else
970     style2 |= wxSUNKEN_BORDER;
971 #endif
972
973     m_list = new wxFileListCtrl( this, ID_FILELIST_CTRL,
974                                  wxEmptyString, false,
975                                  wxDefaultPosition, wxSize( 400, 140 ),
976                                  style2 );
977
978     m_text = new wxTextCtrl( this, ID_TEXT, wxEmptyString,
979                              wxDefaultPosition, wxDefaultSize,
980                              wxTE_PROCESS_ENTER );
981     m_choice = new wxChoice( this, ID_CHOICE );
982
983     if ( is_pda )
984     {
985         // PDAs have a different screen layout
986         mainsizer->Add( m_list, wxSizerFlags( 1 ).Expand().HorzBorder() );
987
988         wxBoxSizer *textsizer = new wxBoxSizer( wxHORIZONTAL );
989         textsizer->Add( m_text, wxSizerFlags( 1 ).Centre().Border() );
990         textsizer->Add( m_choice, wxSizerFlags( 1 ).Centre().Border() );
991         mainsizer->Add( textsizer, wxSizerFlags().Expand() );
992
993     }
994     else // !is_pda
995     {
996         mainsizer->Add( m_list, wxSizerFlags( 1 ).Expand().Border() );
997         mainsizer->Add( m_text, wxSizerFlags().Expand().Border() );
998
999         wxBoxSizer *choicesizer = new wxBoxSizer( wxHORIZONTAL );
1000         choicesizer->Add( m_choice, wxSizerFlags( 1 ).Centre() );
1001
1002         if ( !( m_style & wxFC_NOSHOWHIDDEN ) )
1003         {
1004             m_check = new wxCheckBox( this, ID_CHECK, _( "Show &hidden files" ) );
1005             choicesizer->Add( m_check, wxSizerFlags().Centre().DoubleBorder(wxLEFT) );
1006         }
1007
1008         mainsizer->Add( choicesizer, wxSizerFlags().Expand().Border() );
1009     }
1010
1011     SetWildcard( wildCard );
1012
1013     SetAutoLayout( true );
1014     SetSizer( mainsizer );
1015
1016     if ( !is_pda )
1017     {
1018         mainsizer->Fit( this );
1019     }
1020
1021     m_list->GoToDir( m_dir );
1022     UpdateControls();
1023     m_text->SetValue( m_fileName );
1024
1025     m_ignoreChanges = false;
1026
1027     // must be after m_ignoreChanges = false
1028     SetFilename( defaultFileName );
1029
1030     return true;
1031 }
1032
1033 // NB: there is an unfortunate mismatch between wxFileName and wxFileDialog
1034 //     method names but our GetDirectory() does correspond to wxFileName::
1035 //     GetPath() while our GetPath() is wxFileName::GetFullPath()
1036 wxString wxGenericFileCtrl::GetPath() const
1037 {
1038     wxASSERT_MSG ( !(m_style & wxFC_MULTIPLE), "use GetPaths() instead" );
1039
1040     return DoGetFileName().GetFullPath();
1041 }
1042
1043 wxString wxGenericFileCtrl::GetFilename() const
1044 {
1045     wxASSERT_MSG ( !(m_style & wxFC_MULTIPLE), "use GetFilenames() instead" );
1046
1047     return DoGetFileName().GetFullName();
1048 }
1049
1050 wxString wxGenericFileCtrl::GetDirectory() const
1051 {
1052     // don't check for wxFC_MULTIPLE here, this one is probably safe to call in
1053     // any case as it can be always taken to mean "current directory"
1054     return DoGetFileName().GetPath();
1055 }
1056
1057 wxFileName wxGenericFileCtrl::DoGetFileName() const
1058 {
1059     wxFileName fn;
1060
1061     wxString value = m_text->GetValue();
1062     if ( value.empty() )
1063     {
1064         // nothing in the text control, get the selected file from the list
1065         wxListItem item;
1066         item.m_itemId = m_list->GetNextItem(-1, wxLIST_NEXT_ALL,
1067                                             wxLIST_STATE_SELECTED);
1068         m_list->GetItem(item);
1069
1070         fn.Assign(m_list->GetDir(), item.m_text);
1071     }
1072     else // user entered the value
1073     {
1074         // the path can be either absolute or relative
1075         fn.Assign(value);
1076         if ( fn.IsRelative() )
1077             fn.MakeAbsolute(m_list->GetDir());
1078     }
1079
1080     return fn;
1081 }
1082
1083 // helper used in DoGetFilenames() and needed because Borland can't compile
1084 // operator?: inline
1085 static inline wxString GetFileNameOrPath(const wxFileName& fn, bool fullPath)
1086 {
1087     return fullPath ? fn.GetFullPath() : fn.GetFullName();
1088 }
1089
1090 void
1091 wxGenericFileCtrl::DoGetFilenames(wxArrayString& filenames, bool fullPath) const
1092 {
1093     filenames.clear();
1094
1095     const wxString dir = m_list->GetDir();
1096
1097     const wxString value = m_text->GetValue();
1098     if ( !value.empty() )
1099     {
1100         wxFileName fn(value);
1101         if ( fn.IsRelative() )
1102             fn.MakeAbsolute(dir);
1103
1104         filenames.push_back(GetFileNameOrPath(fn, fullPath));
1105         return;
1106     }
1107
1108     const int numSel = m_list->GetSelectedItemCount();
1109     if ( !numSel )
1110         return;
1111
1112     filenames.reserve(numSel);
1113
1114     wxListItem item;
1115     item.m_mask = wxLIST_MASK_TEXT;
1116     item.m_itemId = -1;
1117     for ( ;; )
1118     {
1119         item.m_itemId = m_list->GetNextItem(item.m_itemId, wxLIST_NEXT_ALL,
1120                                             wxLIST_STATE_SELECTED);
1121
1122         if ( item.m_itemId == -1 )
1123             break;
1124
1125         m_list->GetItem(item);
1126
1127         const wxFileName fn(dir, item.m_text);
1128         filenames.push_back(GetFileNameOrPath(fn, fullPath));
1129     }
1130 }
1131
1132 bool wxGenericFileCtrl::SetDirectory( const wxString& dir )
1133 {
1134     m_ignoreChanges = true;
1135     m_list->GoToDir( dir );
1136     UpdateControls();
1137     m_ignoreChanges = false;
1138
1139     return wxFileName( dir ).SameAs( m_list->GetDir() );
1140 }
1141
1142 bool wxGenericFileCtrl::SetFilename( const wxString& name )
1143 {
1144     const long item = m_list->FindItem( -1, name );
1145
1146     if ( item == -1 ) // file not found either because it doesn't exist or the
1147         // current filter doesn't show it.
1148         return false;
1149
1150     m_noSelChgEvent = true;
1151
1152     // Deselect selected items
1153     {
1154         const int numSelectedItems = m_list->GetSelectedItemCount();
1155
1156         if ( numSelectedItems > 0 )
1157         {
1158             long itemIndex = -1;
1159
1160             for ( ;; )
1161             {
1162                 itemIndex = m_list->GetNextItem( itemIndex, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
1163                 if ( itemIndex == -1 )
1164                     break;
1165
1166                 m_list->SetItemState( itemIndex, 0, wxLIST_STATE_SELECTED );
1167             }
1168         }
1169     }
1170
1171     m_list->SetItemState( item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
1172     m_list->EnsureVisible( item );
1173
1174     m_noSelChgEvent = false;
1175
1176     return true;
1177 }
1178
1179 void wxGenericFileCtrl::DoSetFilterIndex( int filterindex )
1180 {
1181     wxClientData *pcd = m_choice->GetClientObject( filterindex );
1182     if ( !pcd )
1183         return;
1184
1185     const wxString& str = ((static_cast<wxStringClientData *>(pcd))->GetData());
1186     m_list->SetWild( str );
1187     m_filterIndex = filterindex;
1188     if ( str.Left( 2 ) == wxT( "*." ) )
1189     {
1190         m_filterExtension = str.Mid( 1 );
1191         if ( m_filterExtension == wxT( ".*" ) )
1192             m_filterExtension.clear();
1193     }
1194     else
1195     {
1196         m_filterExtension.clear();
1197     }
1198
1199     GenerateFilterChangedEvent( this, this );
1200 }
1201
1202 void wxGenericFileCtrl::SetWildcard( const wxString& wildCard )
1203 {
1204     if ( wildCard.empty() || wildCard == wxFileSelectorDefaultWildcardStr )
1205     {
1206         m_wildCard = wxString::Format( _( "All files (%s)|%s" ),
1207                                        wxFileSelectorDefaultWildcardStr,
1208                                        wxFileSelectorDefaultWildcardStr );
1209     }
1210     else
1211         m_wildCard = wildCard;
1212
1213     wxArrayString wildDescriptions, wildFilters;
1214     const size_t count = wxParseCommonDialogsFilter( m_wildCard,
1215                          wildDescriptions,
1216                          wildFilters );
1217     wxCHECK_RET( count, wxT( "wxFileDialog: bad wildcard string" ) );
1218
1219     m_choice->Clear();
1220
1221     for ( size_t n = 0; n < count; n++ )
1222     {
1223         m_choice->Append(wildDescriptions[n], new wxStringClientData(wildFilters[n]));
1224     }
1225
1226     SetFilterIndex( 0 );
1227 }
1228
1229 void wxGenericFileCtrl::SetFilterIndex( int filterindex )
1230 {
1231     m_choice->SetSelection( filterindex );
1232
1233     DoSetFilterIndex( filterindex );
1234 }
1235
1236 void wxGenericFileCtrl::OnChoiceFilter( wxCommandEvent &event )
1237 {
1238     DoSetFilterIndex( ( int )event.GetInt() );
1239 }
1240
1241 void wxGenericFileCtrl::OnCheck( wxCommandEvent &event )
1242 {
1243     m_list->ShowHidden( event.GetInt() != 0 );
1244 }
1245
1246 void wxGenericFileCtrl::OnActivated( wxListEvent &event )
1247 {
1248     HandleAction( event.m_item.m_text );
1249 }
1250
1251 void wxGenericFileCtrl::OnTextEnter( wxCommandEvent &WXUNUSED( event ) )
1252 {
1253     HandleAction( m_text->GetValue() );
1254 }
1255
1256 void wxGenericFileCtrl::OnTextChange( wxCommandEvent &WXUNUSED( event ) )
1257 {
1258     if ( !m_ignoreChanges )
1259     {
1260         // Clear selections.  Otherwise when the user types in a value they may
1261         // not get the file whose name they typed.
1262         if ( m_list->GetSelectedItemCount() > 0 )
1263         {
1264             long item = m_list->GetNextItem( -1, wxLIST_NEXT_ALL,
1265                                              wxLIST_STATE_SELECTED );
1266             while ( item != -1 )
1267             {
1268                 m_list->SetItemState( item, 0, wxLIST_STATE_SELECTED );
1269                 item = m_list->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
1270             }
1271         }
1272     }
1273 }
1274
1275 void wxGenericFileCtrl::OnSelected( wxListEvent &event )
1276 {
1277     if ( m_ignoreChanges )
1278         return;
1279
1280     if ( m_inSelected )
1281         return;
1282
1283     m_inSelected = true;
1284     const wxString filename( event.m_item.m_text );
1285
1286 #ifdef __WXWINCE__
1287     // No double-click on most WinCE devices, so do action immediately.
1288     HandleAction( filename );
1289 #else
1290     if ( filename == wxT( ".." ) )
1291     {
1292         m_inSelected = false;
1293         return;
1294     }
1295
1296     wxString dir = m_list->GetDir();
1297     if ( !IsTopMostDir( dir ) )
1298         dir += wxFILE_SEP_PATH;
1299     dir += filename;
1300     if ( wxDirExists( dir ) )
1301     {
1302         m_inSelected = false;
1303
1304         return;
1305     }
1306
1307
1308     m_ignoreChanges = true;
1309     m_text->SetValue( filename );
1310
1311     if ( m_list->GetSelectedItemCount() > 1 )
1312     {
1313         m_text->Clear();
1314     }
1315
1316     if ( !m_noSelChgEvent )
1317         GenerateSelectionChangedEvent( this, this );
1318
1319     m_ignoreChanges = false;
1320 #endif
1321     m_inSelected = false;
1322 }
1323
1324 void wxGenericFileCtrl::HandleAction( const wxString &fn )
1325 {
1326     if ( m_ignoreChanges )
1327         return;
1328
1329     wxString filename( fn );
1330     if ( filename.empty() )
1331     {
1332         return;
1333     }
1334     if ( filename == wxT( "." ) ) return;
1335
1336     wxString dir = m_list->GetDir();
1337
1338     // "some/place/" means they want to chdir not try to load "place"
1339     const bool want_dir = filename.Last() == wxFILE_SEP_PATH;
1340     if ( want_dir )
1341         filename = filename.RemoveLast();
1342
1343     if ( filename == wxT( ".." ) )
1344     {
1345         m_ignoreChanges = true;
1346         m_list->GoToParentDir();
1347
1348         GenerateFolderChangedEvent( this, this );
1349
1350         UpdateControls();
1351         m_ignoreChanges = false;
1352         return;
1353     }
1354
1355 #ifdef __UNIX__
1356     if ( filename == wxT( "~" ) )
1357     {
1358         m_ignoreChanges = true;
1359         m_list->GoToHomeDir();
1360
1361         GenerateFolderChangedEvent( this, this );
1362
1363         UpdateControls();
1364         m_ignoreChanges = false;
1365         return;
1366     }
1367
1368     if ( filename.BeforeFirst( wxT( '/' ) ) == wxT( "~" ) )
1369     {
1370         filename = wxString( wxGetUserHome() ) + filename.Remove( 0, 1 );
1371     }
1372 #endif // __UNIX__
1373
1374     if ( !( m_style & wxFC_SAVE ) )
1375     {
1376         if ( ( filename.Find( wxT( '*' ) ) != wxNOT_FOUND ) ||
1377                 ( filename.Find( wxT( '?' ) ) != wxNOT_FOUND ) )
1378         {
1379             if ( filename.Find( wxFILE_SEP_PATH ) != wxNOT_FOUND )
1380             {
1381                 wxMessageBox( _( "Illegal file specification." ),
1382                               _( "Error" ), wxOK | wxICON_ERROR, this );
1383                 return;
1384             }
1385             m_list->SetWild( filename );
1386             return;
1387         }
1388     }
1389
1390     if ( !IsTopMostDir( dir ) )
1391         dir += wxFILE_SEP_PATH;
1392     if ( !wxIsAbsolutePath( filename ) )
1393     {
1394         dir += filename;
1395         filename = dir;
1396     }
1397
1398     if ( wxDirExists( filename ) )
1399     {
1400         m_ignoreChanges = true;
1401         m_list->GoToDir( filename );
1402         UpdateControls();
1403
1404         GenerateFolderChangedEvent( this, this );
1405
1406         m_ignoreChanges = false;
1407         return;
1408     }
1409
1410     // they really wanted a dir, but it doesn't exist
1411     if ( want_dir )
1412     {
1413         wxMessageBox( _( "Directory doesn't exist." ), _( "Error" ),
1414                       wxOK | wxICON_ERROR, this );
1415         return;
1416     }
1417
1418     // append the default extension to the filename if it doesn't have any
1419     //
1420     // VZ: the logic of testing for !wxFileExists() only for the open file
1421     //     dialog is not entirely clear to me, why don't we allow saving to a
1422     //     file without extension as well?
1423     if ( !( m_style & wxFC_OPEN ) || !wxFileExists( filename ) )
1424     {
1425         filename = wxFileDialogBase::AppendExtension( filename, m_filterExtension );
1426         GenerateFileActivatedEvent( this, this, wxFileName( filename ).GetFullName() );
1427         return;
1428     }
1429
1430     GenerateFileActivatedEvent( this, this );
1431 }
1432
1433 bool wxGenericFileCtrl::SetPath( const wxString& path )
1434 {
1435     if ( !wxFileName::FileExists( ( path ) ) )
1436         return false;
1437
1438     wxString ext;
1439     wxFileName::SplitPath( path, &m_dir, &m_fileName, &ext );
1440     if ( !ext.empty() )
1441     {
1442         m_fileName += wxT( "." );
1443         m_fileName += ext;
1444     }
1445
1446     SetDirectory( m_dir );
1447     SetFilename( m_fileName );
1448
1449     return true;
1450 }
1451
1452 void wxGenericFileCtrl::GetPaths( wxArrayString& paths ) const
1453 {
1454     DoGetFilenames( paths, true );
1455 }
1456
1457 void wxGenericFileCtrl::GetFilenames( wxArrayString& files ) const
1458 {
1459     DoGetFilenames( files, false );
1460 }
1461
1462 void wxGenericFileCtrl::UpdateControls()
1463 {
1464     const wxString dir = m_list->GetDir();
1465     m_static->SetLabel( dir );
1466 }
1467
1468 void wxGenericFileCtrl::GoToParentDir()
1469 {
1470     m_list->GoToParentDir();
1471     UpdateControls();
1472 }
1473
1474 void wxGenericFileCtrl::GoToHomeDir()
1475 {
1476     m_list->GoToHomeDir();
1477     UpdateControls();
1478 }
1479
1480 #endif // wxUSE_FILECTRL