]> git.saurik.com Git - wxWidgets.git/blob - src/generic/filectrlg.cpp
Applied colspan corrections, #15274 and #15275 (dghart)
[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