]> git.saurik.com Git - wxWidgets.git/blame - src/generic/filectrlg.cpp
Interpret wxRect passed to wxRichToolTip::ShowFor() as client coords.
[wxWidgets.git] / src / generic / filectrlg.cpp
CommitLineData
0cf3e587
VZ
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
0cf3e587
VZ
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"
690a6489 36#include "wx/imaglist.h"
0cf3e587 37
bb5a9514 38#ifdef __WINDOWS__
0cf3e587
VZ
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
55static
d3ca8487 56int wxCALLBACK wxFileDataNameCompare( wxIntPtr data1, wxIntPtr data2, wxIntPtr sortOrder)
0cf3e587
VZ
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
73static
d3ca8487 74int wxCALLBACK wxFileDataSizeCompare(wxIntPtr data1, wxIntPtr data2, wxIntPtr sortOrder)
0cf3e587
VZ
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
95static
d3ca8487 96int wxCALLBACK wxFileDataTypeCompare(wxIntPtr data1, wxIntPtr data2, wxIntPtr sortOrder)
0cf3e587
VZ
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
117static
d3ca8487 118int wxCALLBACK wxFileDataTimeCompare(wxIntPtr data1, wxIntPtr data2, wxIntPtr sortOrder)
0cf3e587
VZ
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
136extern size_t wxGetAvailableDrives(wxArrayString &paths, wxArrayString &names, wxArrayInt &icon_ids);
137
138//-----------------------------------------------------------------------------
139// wxFileData
140//-----------------------------------------------------------------------------
141
142wxFileData::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
153void wxFileData::Init()
154{
155 m_size = 0;
156 m_type = wxFileData::is_file;
157 m_image = wxFileIconsTable::file;
158}
159
160void 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
171void 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;
bd365871 197 wxFileName::SplitPath(m_filePath, & p, & f, & ext);
0cf3e587
VZ
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))
4d35172f
VZ
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;
0cf3e587 229#else // no lstat()
4d35172f 230 const bool hasStat = wxStat( m_filePath, &buff ) == 0;
0cf3e587
VZ
231#endif
232
4d35172f
VZ
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;
0cf3e587 237
4d35172f 238 m_size = buff.st_size;
0cf3e587 239
4d35172f
VZ
240 m_dateTime = buff.st_mtime;
241 }
0cf3e587
VZ
242#endif
243 // __WXWINCE__
244
245#if defined(__UNIX__)
4d35172f
VZ
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 }
0cf3e587
VZ
259#elif defined(__WIN32__)
260 DWORD attribs = ::GetFileAttributes(m_filePath.c_str());
261 if (attribs != (DWORD)-1)
262 {
9a83f860
VZ
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(' '));
0cf3e587
VZ
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
284wxString 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
298wxString 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
304wxString 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
331wxString 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:
9a83f860 361 wxFAIL_MSG( wxT("unexpected field in wxFileData::GetEntry()") );
0cf3e587
VZ
362 }
363
364 return s;
365}
366
367void wxFileData::SetNewName( const wxString &filePath, const wxString &fileName )
368{
369 m_fileName = fileName;
370 m_filePath = filePath;
371}
372
373void 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 {
9a83f860 386 wxColour dg = wxTheColourDatabase->Find( wxT("MEDIUM GREY") );
a1b806b9 387 if ( dg.IsOk() )
0cf3e587
VZ
388 item.SetTextColour(dg);
389 }
390 item.m_data = wxPtrToUInt(this);
391}
392
393//-----------------------------------------------------------------------------
16a6b53d 394// wxFileListCtrl
0cf3e587
VZ
395//-----------------------------------------------------------------------------
396
16a6b53d 397IMPLEMENT_DYNAMIC_CLASS(wxFileListCtrl,wxListCtrl)
0cf3e587 398
16a6b53d
VZ
399BEGIN_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)
0cf3e587
VZ
404END_EVENT_TABLE()
405
406
16a6b53d 407wxFileListCtrl::wxFileListCtrl()
0cf3e587
VZ
408{
409 m_showHidden = false;
260020e3 410 m_sort_forward = true;
0cf3e587
VZ
411 m_sort_field = wxFileData::FileList_Name;
412}
413
16a6b53d 414wxFileListCtrl::wxFileListCtrl(wxWindow *win,
0cf3e587
VZ
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
260020e3 432 m_sort_forward = true;
0cf3e587
VZ
433 m_sort_field = wxFileData::FileList_Name;
434
435 m_dirName = wxT("*");
436
437 if (style & wxLC_REPORT)
438 ChangeToReportMode();
439}
440
16a6b53d 441void wxFileListCtrl::ChangeToListMode()
0cf3e587
VZ
442{
443 ClearAll();
444 SetSingleStyle( wxLC_LIST );
445 UpdateFiles();
446}
447
16a6b53d 448void wxFileListCtrl::ChangeToReportMode()
0cf3e587
VZ
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
16a6b53d 475void wxFileListCtrl::ChangeToSmallIconMode()
0cf3e587
VZ
476{
477 ClearAll();
478 SetSingleStyle( wxLC_SMALL_ICON );
479 UpdateFiles();
480}
481
16a6b53d 482void wxFileListCtrl::ShowHidden( bool show )
0cf3e587
VZ
483{
484 m_showHidden = show;
485 UpdateFiles();
486}
487
16a6b53d 488long wxFileListCtrl::Add( wxFileData *fd, wxListItem &item )
0cf3e587
VZ
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
16a6b53d 507void wxFileListCtrl::UpdateItem(const wxListItem &item)
0cf3e587
VZ
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
16a6b53d 524void wxFileListCtrl::UpdateFiles()
0cf3e587
VZ
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;
e8548d99 543 const size_t count = wxGetAvailableDrives(paths, names, icons);
0cf3e587 544
e8548d99 545 for ( size_t n = 0; n < count; n++ )
0cf3e587 546 {
e8548d99
VZ
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]);
0cf3e587
VZ
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
260020e3 640 SortItems(m_sort_field, m_sort_forward);
0cf3e587
VZ
641}
642
16a6b53d 643void wxFileListCtrl::SetWild( const wxString &wild )
0cf3e587
VZ
644{
645 if (wild.Find(wxT('|')) != wxNOT_FOUND)
646 return;
647
648 m_wild = wild;
649 UpdateFiles();
650}
651
16a6b53d 652void wxFileListCtrl::MakeDir()
0cf3e587
VZ
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;
6485c8d7 687 long itemid = Add( fd, item );
0cf3e587 688
6485c8d7 689 if (itemid != -1)
0cf3e587 690 {
260020e3 691 SortItems(m_sort_field, m_sort_forward);
6485c8d7
SC
692 itemid = FindItem( 0, wxPtrToUInt(fd) );
693 EnsureVisible( itemid );
694 EditLabel( itemid );
0cf3e587
VZ
695 }
696 else
697 delete fd;
698}
699
16a6b53d 700void wxFileListCtrl::GoToParentDir()
0cf3e587
VZ
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 {
0cf3e587
VZ
723 SetItemState( id, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
724 EnsureVisible( id );
0cf3e587
VZ
725 }
726 }
727}
728
16a6b53d 729void wxFileListCtrl::GoToHomeDir()
0cf3e587
VZ
730{
731 wxString s = wxGetUserHome( wxString() );
732 GoToDir(s);
733}
734
16a6b53d 735void wxFileListCtrl::GoToDir( const wxString &dir )
0cf3e587
VZ
736{
737 if (!wxDirExists(dir)) return;
738
739 m_dirName = dir;
740 UpdateFiles();
741
0cf3e587 742 SetItemState( 0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
0cf3e587
VZ
743
744 EnsureVisible( 0 );
745}
746
16a6b53d 747void wxFileListCtrl::FreeItemData(wxListItem& item)
0cf3e587
VZ
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
16a6b53d 758void wxFileListCtrl::OnListDeleteItem( wxListEvent &event )
0cf3e587
VZ
759{
760 FreeItemData(event.m_item);
761}
762
16a6b53d 763void wxFileListCtrl::OnListDeleteAllItems( wxListEvent & WXUNUSED(event) )
0cf3e587
VZ
764{
765 FreeAllItemsData();
766}
767
16a6b53d 768void wxFileListCtrl::FreeAllItemsData()
0cf3e587
VZ
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
16a6b53d 782void wxFileListCtrl::OnListEndLabelEdit( wxListEvent &event )
0cf3e587
VZ
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
0cf3e587 815 SetItemState( event.GetItem(), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
0cf3e587
VZ
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
16a6b53d 828void wxFileListCtrl::OnListColClick( wxListEvent &event )
0cf3e587
VZ
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)
260020e3 842 m_sort_forward = !m_sort_forward;
0cf3e587
VZ
843 else
844 m_sort_field = (wxFileData::fileListFieldType)col;
845
260020e3 846 SortItems(m_sort_field, m_sort_forward);
0cf3e587
VZ
847}
848
16a6b53d 849void wxFileListCtrl::SortItems(wxFileData::fileListFieldType field, bool forward)
0cf3e587
VZ
850{
851 m_sort_field = field;
260020e3 852 m_sort_forward = forward;
0cf3e587
VZ
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
16a6b53d 876wxFileListCtrl::~wxFileListCtrl()
0cf3e587
VZ
877{
878 // Normally the data are freed via an EVT_LIST_DELETE_ALL_ITEMS event and
16a6b53d
VZ
879 // wxFileListCtrl::OnListDeleteAllItems. But if the event is generated after
880 // the destruction of the wxFileListCtrl we need to free any data here:
0cf3e587
VZ
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
5804d539 893IMPLEMENT_DYNAMIC_CLASS( wxGenericFileCtrl, wxNavigationEnabled<wxControl> )
0cf3e587 894
5804d539 895BEGIN_EVENT_TABLE( wxGenericFileCtrl, wxNavigationEnabled<wxControl> )
0cf3e587
VZ
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 )
902END_EVENT_TABLE()
903
904bool 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;
8ce68f7f 917 m_check = NULL;
0cf3e587
VZ
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
5804d539
VZ
926 wxNavigationEnabled<wxControl>::Create( parent, id,
927 pos, size,
928 wxTAB_TRAVERSAL,
929 wxDefaultValidator,
930 name );
0cf3e587
VZ
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 )
8ce68f7f
VZ
957 staticsizer->Add( new wxStaticText( this, wxID_ANY, _( "Current directory:" ) ),
958 wxSizerFlags().DoubleBorder(wxRIGHT) );
0cf3e587
VZ
959 m_static = new wxStaticText( this, wxID_ANY, m_dir );
960 staticsizer->Add( m_static, 1 );
8ce68f7f 961 mainsizer->Add( staticsizer, wxSizerFlags().Expand().Border());
0cf3e587
VZ
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
16a6b53d
VZ
973 m_list = new wxFileListCtrl( this, ID_FILELIST_CTRL,
974 wxEmptyString, false,
975 wxDefaultPosition, wxSize( 400, 140 ),
976 style2 );
0cf3e587
VZ
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() );
8ce68f7f 990 textsizer->Add( m_choice, wxSizerFlags( 1 ).Centre().Border() );
0cf3e587
VZ
991 mainsizer->Add( textsizer, wxSizerFlags().Expand() );
992
0cf3e587
VZ
993 }
994 else // !is_pda
995 {
8ce68f7f
VZ
996 mainsizer->Add( m_list, wxSizerFlags( 1 ).Expand().Border() );
997 mainsizer->Add( m_text, wxSizerFlags().Expand().Border() );
0cf3e587
VZ
998
999 wxBoxSizer *choicesizer = new wxBoxSizer( wxHORIZONTAL );
8ce68f7f 1000 choicesizer->Add( m_choice, wxSizerFlags( 1 ).Centre() );
0cf3e587
VZ
1001
1002 if ( !( m_style & wxFC_NOSHOWHIDDEN ) )
8ce68f7f 1003 {
0cf3e587 1004 m_check = new wxCheckBox( this, ID_CHECK, _( "Show &hidden files" ) );
8ce68f7f
VZ
1005 choicesizer->Add( m_check, wxSizerFlags().Centre().DoubleBorder(wxLEFT) );
1006 }
0cf3e587 1007
8ce68f7f 1008 mainsizer->Add( choicesizer, wxSizerFlags().Expand().Border() );
0cf3e587
VZ
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
398eebb1
VZ
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()
0cf3e587
VZ
1036wxString wxGenericFileCtrl::GetPath() const
1037{
398eebb1
VZ
1038 wxASSERT_MSG ( !(m_style & wxFC_MULTIPLE), "use GetPaths() instead" );
1039
1040 return DoGetFileName().GetFullPath();
0cf3e587
VZ
1041}
1042
1043wxString wxGenericFileCtrl::GetFilename() const
1044{
398eebb1
VZ
1045 wxASSERT_MSG ( !(m_style & wxFC_MULTIPLE), "use GetFilenames() instead" );
1046
1047 return DoGetFileName().GetFullName();
0cf3e587
VZ
1048}
1049
398eebb1 1050wxString wxGenericFileCtrl::GetDirectory() const
0cf3e587 1051{
398eebb1
VZ
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}
0cf3e587 1056
398eebb1
VZ
1057wxFileName wxGenericFileCtrl::DoGetFileName() const
1058{
1059 wxFileName fn;
0cf3e587 1060
398eebb1
VZ
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;
0cf3e587
VZ
1081}
1082
d42b8535
VZ
1083// helper used in DoGetFilenames() and needed because Borland can't compile
1084// operator?: inline
1085static inline wxString GetFileNameOrPath(const wxFileName& fn, bool fullPath)
1086{
1087 return fullPath ? fn.GetFullPath() : fn.GetFullName();
1088}
1089
1090void
1091wxGenericFileCtrl::DoGetFilenames(wxArrayString& filenames, bool fullPath) const
0cf3e587 1092{
7d42f4d6 1093 filenames.clear();
0cf3e587 1094
398eebb1 1095 const wxString dir = m_list->GetDir();
0cf3e587 1096
7d42f4d6 1097 const wxString value = m_text->GetValue();
0cf3e587
VZ
1098 if ( !value.empty() )
1099 {
7d42f4d6
VZ
1100 wxFileName fn(value);
1101 if ( fn.IsRelative() )
1102 fn.MakeAbsolute(dir);
1103
d42b8535 1104 filenames.push_back(GetFileNameOrPath(fn, fullPath));
0cf3e587
VZ
1105 return;
1106 }
1107
7d42f4d6
VZ
1108 const int numSel = m_list->GetSelectedItemCount();
1109 if ( !numSel )
0cf3e587 1110 return;
0cf3e587 1111
7d42f4d6 1112 filenames.reserve(numSel);
0cf3e587
VZ
1113
1114 wxListItem item;
1115 item.m_mask = wxLIST_MASK_TEXT;
7d42f4d6
VZ
1116 item.m_itemId = -1;
1117 for ( ;; )
0cf3e587 1118 {
7d42f4d6
VZ
1119 item.m_itemId = m_list->GetNextItem(item.m_itemId, wxLIST_NEXT_ALL,
1120 wxLIST_STATE_SELECTED);
0cf3e587 1121
7d42f4d6
VZ
1122 if ( item.m_itemId == -1 )
1123 break;
1124
1125 m_list->GetItem(item);
0cf3e587 1126
7d42f4d6 1127 const wxFileName fn(dir, item.m_text);
d42b8535 1128 filenames.push_back(GetFileNameOrPath(fn, fullPath));
0cf3e587
VZ
1129 }
1130}
1131
1132bool 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
0cf3e587
VZ
1142bool 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
1179void wxGenericFileCtrl::DoSetFilterIndex( int filterindex )
1180{
a85ad1db
VZ
1181 wxClientData *pcd = m_choice->GetClientObject( filterindex );
1182 if ( !pcd )
1183 return;
1184
5c33522f 1185 const wxString& str = ((static_cast<wxStringClientData *>(pcd))->GetData());
0cf3e587
VZ
1186 m_list->SetWild( str );
1187 m_filterIndex = filterindex;
1188 if ( str.Left( 2 ) == wxT( "*." ) )
1189 {
1190 m_filterExtension = str.Mid( 1 );
9a83f860 1191 if ( m_filterExtension == wxT( ".*" ) )
0cf3e587
VZ
1192 m_filterExtension.clear();
1193 }
1194 else
1195 {
1196 m_filterExtension.clear();
1197 }
6305f044
VZ
1198
1199 GenerateFilterChangedEvent( this, this );
0cf3e587
VZ
1200}
1201
1202void 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
1229void wxGenericFileCtrl::SetFilterIndex( int filterindex )
1230{
1231 m_choice->SetSelection( filterindex );
1232
1233 DoSetFilterIndex( filterindex );
1234}
1235
1236void wxGenericFileCtrl::OnChoiceFilter( wxCommandEvent &event )
1237{
1238 DoSetFilterIndex( ( int )event.GetInt() );
1239}
1240
1241void wxGenericFileCtrl::OnCheck( wxCommandEvent &event )
1242{
1243 m_list->ShowHidden( event.GetInt() != 0 );
1244}
1245
1246void wxGenericFileCtrl::OnActivated( wxListEvent &event )
1247{
1248 HandleAction( event.m_item.m_text );
1249}
1250
1251void wxGenericFileCtrl::OnTextEnter( wxCommandEvent &WXUNUSED( event ) )
1252{
1253 HandleAction( m_text->GetValue() );
1254}
1255
1256void 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
1275void 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 }
bd365871 1306
0cf3e587
VZ
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
1324void 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
1433bool wxGenericFileCtrl::SetPath( const wxString& path )
1434{
1435 if ( !wxFileName::FileExists( ( path ) ) )
1436 return false;
1437
1438 wxString ext;
bd365871 1439 wxFileName::SplitPath( path, &m_dir, &m_fileName, &ext );
0cf3e587
VZ
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
1452void wxGenericFileCtrl::GetPaths( wxArrayString& paths ) const
1453{
1454 DoGetFilenames( paths, true );
1455}
1456
1457void wxGenericFileCtrl::GetFilenames( wxArrayString& files ) const
1458{
1459 DoGetFilenames( files, false );
1460}
1461
1462void wxGenericFileCtrl::UpdateControls()
1463{
1464 const wxString dir = m_list->GetDir();
1465 m_static->SetLabel( dir );
1466}
1467
1468void wxGenericFileCtrl::GoToParentDir()
1469{
1470 m_list->GoToParentDir();
1471 UpdateControls();
1472}
1473
1474void wxGenericFileCtrl::GoToHomeDir()
1475{
1476 m_list->GoToHomeDir();
1477 UpdateControls();
1478}
1479
0cf3e587 1480#endif // wxUSE_FILECTRL