APplied patch [ 705301 ] Don't send event for wxSplitter::Unsplit
[wxWidgets.git] / src / generic / filedlgg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: filedlgg.cpp
3 // Purpose: wxGenericFileDialog
4 // Author: Robert Roebling
5 // Modified by:
6 // Created: 12/12/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Robert Roebling
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "filedlgg.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_FILEDLG
32
33 #if !defined(__UNIX__) && !defined(__DOS__) && !defined(__WIN32__)
34 #error wxGenericFileDialog currently only supports Unix, win32 and DOS
35 #endif
36
37 #include "wx/checkbox.h"
38 #include "wx/textctrl.h"
39 #include "wx/choice.h"
40 #include "wx/checkbox.h"
41 #include "wx/stattext.h"
42 #include "wx/debug.h"
43 #include "wx/log.h"
44 #include "wx/intl.h"
45 #include "wx/msgdlg.h"
46 #include "wx/sizer.h"
47 #include "wx/bmpbuttn.h"
48 #include "wx/tokenzr.h"
49 #include "wx/mimetype.h"
50 #include "wx/image.h"
51 #include "wx/module.h"
52 #include "wx/config.h"
53 #include "wx/imaglist.h"
54 #include "wx/dir.h"
55 #include "wx/artprov.h"
56 #include "wx/hash.h"
57 #include "wx/file.h" // for wxS_IXXX constants only
58 #include "wx/filedlg.h" // wxOPEN, wxSAVE...
59 #include "wx/generic/filedlgg.h"
60
61 #if wxUSE_TOOLTIPS
62 #include "wx/tooltip.h"
63 #endif
64
65 #include <sys/types.h>
66 #include <sys/stat.h>
67
68 #ifdef __UNIX__
69 #include <dirent.h>
70 #include <pwd.h>
71 #ifndef __VMS
72 # include <grp.h>
73 #endif
74 #endif
75
76 #ifdef __WATCOMC__
77 #include <direct.h>
78 #endif
79
80 #include <time.h>
81 #if defined(__UNIX__) || defined(__DOS__)
82 #include <unistd.h>
83 #endif
84
85 // ----------------------------------------------------------------------------
86 // private classes - icons list management
87 // ----------------------------------------------------------------------------
88
89 class wxFileIconEntry : public wxObject
90 {
91 public:
92 wxFileIconEntry(int i) { id = i; }
93
94 int id;
95 };
96
97
98 class wxFileIconsTable
99 {
100 public:
101 wxFileIconsTable();
102
103 int GetIconID(const wxString& extension, const wxString& mime = wxEmptyString);
104 wxImageList *GetImageList() { return &m_ImageList; }
105
106 protected:
107 wxImageList m_ImageList;
108 wxHashTable m_HashTable;
109 };
110
111 static wxFileIconsTable *g_IconsTable = NULL;
112
113 #define FI_FOLDER 0
114 #define FI_UNKNOWN 1
115 #define FI_EXECUTABLE 2
116
117 wxFileIconsTable::wxFileIconsTable() :
118 m_ImageList(16, 16),
119 m_HashTable(wxKEY_STRING)
120 {
121 m_HashTable.DeleteContents(TRUE);
122 // FI_FOLDER:
123 m_ImageList.Add(wxArtProvider::GetBitmap(wxART_FOLDER, wxART_CMN_DIALOG));
124 // FI_UNKNOWN:
125 m_ImageList.Add(wxArtProvider::GetBitmap(wxART_NORMAL_FILE, wxART_CMN_DIALOG));
126 // FI_EXECUTABLE:
127 if (GetIconID(wxEmptyString, _T("application/x-executable")) == FI_UNKNOWN)
128 {
129 m_ImageList.Add(wxArtProvider::GetBitmap(wxART_EXECUTABLE_FILE, wxART_CMN_DIALOG));
130 m_HashTable.Delete(_T("exe"));
131 m_HashTable.Put(_T("exe"), new wxFileIconEntry(FI_EXECUTABLE));
132 }
133 /* else put into list by GetIconID
134 (KDE defines application/x-executable for *.exe and has nice icon)
135 */
136 }
137
138
139
140 #if wxUSE_MIMETYPE
141 // VS: we don't need this function w/o wxMimeTypesManager because we'll only have
142 // one icon and we won't resize it
143
144 static wxBitmap CreateAntialiasedBitmap(const wxImage& img)
145 {
146 wxImage smallimg (16, 16);
147 unsigned char *p1, *p2, *ps;
148 unsigned char mr = img.GetMaskRed(),
149 mg = img.GetMaskGreen(),
150 mb = img.GetMaskBlue();
151
152 unsigned x, y;
153 unsigned sr, sg, sb, smask;
154
155 p1 = img.GetData(), p2 = img.GetData() + 3 * 32, ps = smallimg.GetData();
156 smallimg.SetMaskColour(mr, mr, mr);
157
158 for (y = 0; y < 16; y++)
159 {
160 for (x = 0; x < 16; x++)
161 {
162 sr = sg = sb = smask = 0;
163 if (p1[0] != mr || p1[1] != mg || p1[2] != mb)
164 sr += p1[0], sg += p1[1], sb += p1[2];
165 else smask++;
166 p1 += 3;
167 if (p1[0] != mr || p1[1] != mg || p1[2] != mb)
168 sr += p1[0], sg += p1[1], sb += p1[2];
169 else smask++;
170 p1 += 3;
171 if (p2[0] != mr || p2[1] != mg || p2[2] != mb)
172 sr += p2[0], sg += p2[1], sb += p2[2];
173 else smask++;
174 p2 += 3;
175 if (p2[0] != mr || p2[1] != mg || p2[2] != mb)
176 sr += p2[0], sg += p2[1], sb += p2[2];
177 else smask++;
178 p2 += 3;
179
180 if (smask > 2)
181 ps[0] = ps[1] = ps[2] = mr;
182 else
183 ps[0] = sr >> 2, ps[1] = sg >> 2, ps[2] = sb >> 2;
184 ps += 3;
185 }
186 p1 += 32 * 3, p2 += 32 * 3;
187 }
188
189 return wxBitmap(smallimg);
190 }
191
192 // finds empty borders and return non-empty area of image:
193 static wxImage CutEmptyBorders(const wxImage& img)
194 {
195 unsigned char mr = img.GetMaskRed(),
196 mg = img.GetMaskGreen(),
197 mb = img.GetMaskBlue();
198 unsigned char *dt = img.GetData(), *dttmp;
199 unsigned w = img.GetWidth(), h = img.GetHeight();
200
201 unsigned top, bottom, left, right, i;
202 bool empt;
203
204 #define MK_DTTMP(x,y) dttmp = dt + ((x + y * w) * 3)
205 #define NOEMPTY_PIX(empt) if (dttmp[0] != mr || dttmp[1] != mg || dttmp[2] != mb) {empt = FALSE; break;}
206
207 for (empt = TRUE, top = 0; empt && top < h; top++)
208 {
209 MK_DTTMP(0, top);
210 for (i = 0; i < w; i++, dttmp+=3)
211 NOEMPTY_PIX(empt)
212 }
213 for (empt = TRUE, bottom = h-1; empt && bottom > top; bottom--)
214 {
215 MK_DTTMP(0, bottom);
216 for (i = 0; i < w; i++, dttmp+=3)
217 NOEMPTY_PIX(empt)
218 }
219 for (empt = TRUE, left = 0; empt && left < w; left++)
220 {
221 MK_DTTMP(left, 0);
222 for (i = 0; i < h; i++, dttmp+=3*w)
223 NOEMPTY_PIX(empt)
224 }
225 for (empt = TRUE, right = w-1; empt && right > left; right--)
226 {
227 MK_DTTMP(right, 0);
228 for (i = 0; i < h; i++, dttmp+=3*w)
229 NOEMPTY_PIX(empt)
230 }
231 top--, left--, bottom++, right++;
232
233 return img.GetSubImage(wxRect(left, top, right - left + 1, bottom - top + 1));
234 }
235 #endif // wxUSE_MIMETYPE
236
237
238
239 int wxFileIconsTable::GetIconID(const wxString& extension, const wxString& mime)
240 {
241 #if wxUSE_MIMETYPE
242 if (!extension.IsEmpty())
243 {
244 wxFileIconEntry *entry = (wxFileIconEntry*) m_HashTable.Get(extension);
245 if (entry) return (entry -> id);
246 }
247
248 wxFileType *ft = (mime.IsEmpty()) ?
249 wxTheMimeTypesManager -> GetFileTypeFromExtension(extension) :
250 wxTheMimeTypesManager -> GetFileTypeFromMimeType(mime);
251 wxIcon ic;
252 if (ft == NULL || (!ft -> GetIcon(&ic)) || (!ic.Ok()))
253 {
254 int newid = FI_UNKNOWN;
255 m_HashTable.Put(extension, new wxFileIconEntry(newid));
256 return newid;
257 }
258
259 wxBitmap tmpBmp;
260 tmpBmp.CopyFromIcon(ic);
261 wxImage img = tmpBmp.ConvertToImage();
262
263 delete ft;
264
265 int id = m_ImageList.GetImageCount();
266 if (img.GetWidth() == 16 && img.GetHeight() == 16)
267 m_ImageList.Add(wxBitmap(img));
268 else
269 {
270 if (img.GetWidth() != 32 || img.GetHeight() != 32)
271 m_ImageList.Add(CreateAntialiasedBitmap(CutEmptyBorders(img).Rescale(32, 32)));
272 else
273 m_ImageList.Add(CreateAntialiasedBitmap(img));
274 }
275 m_HashTable.Put(extension, new wxFileIconEntry(id));
276 return id;
277
278 #else // !wxUSE_MIMETYPE
279
280 if (extension == wxT("exe"))
281 return FI_EXECUTABLE;
282 else
283 return FI_UNKNOWN;
284 #endif // wxUSE_MIMETYPE/!wxUSE_MIMETYPE
285 }
286
287
288
289 // ----------------------------------------------------------------------------
290 // private functions
291 // ----------------------------------------------------------------------------
292
293 static
294 int wxFileDataNameCompare( long data1, long data2, long data)
295 {
296 wxFileData *fd1 = (wxFileData*)data1;
297 wxFileData *fd2 = (wxFileData*)data2;
298 if (fd1->GetName() == wxT("..")) return -data;
299 if (fd2->GetName() == wxT("..")) return data;
300 if (fd1->IsDir() && !fd2->IsDir()) return -data;
301 if (fd2->IsDir() && !fd1->IsDir()) return data;
302 return data*wxStrcmp( fd1->GetName(), fd2->GetName() );
303 }
304
305 static
306 int wxFileDataTypeCompare( long data1, long data2, long data)
307 {
308 wxFileData *fd1 = (wxFileData*)data1;
309 wxFileData *fd2 = (wxFileData*)data2;
310 if (fd1->GetName() == wxT("..")) return -data;
311 if (fd2->GetName() == wxT("..")) return data;
312 if (fd1->IsDir() && !fd2->IsDir()) return -data;
313 if (fd2->IsDir() && !fd1->IsDir()) return data;
314 if (fd1->IsLink() && !fd2->IsLink()) return -data;
315 if (fd2->IsLink() && !fd1->IsLink()) return data;
316 return data*(fd1->GetSize() - fd2->GetSize());
317 }
318
319 static
320 int wxFileDataTimeCompare( long data1, long data2, long data)
321 {
322 wxFileData *fd1 = (wxFileData*)data1;
323 wxFileData *fd2 = (wxFileData*)data2;
324 if (fd1->GetName() == wxT("..")) return -data;
325 if (fd2->GetName() == wxT("..")) return data;
326 if (fd1->IsDir() && !fd2->IsDir()) return -data;
327 if (fd2->IsDir() && !fd1->IsDir()) return data;
328
329 int val = fd1->GetYear() - fd2->GetYear();
330 if (val) return data*val;
331 val = fd1->GetMonth() - fd2->GetMonth();
332 if (val) return data*val;
333 val = fd1->GetDay() - fd2->GetDay();
334 if (val) return data*val;
335 val = fd1->GetHour() - fd2->GetHour();
336 if (val) return data*val;
337 val = fd1->GetMinute() - fd2->GetMinute();
338 return data*val;
339 }
340
341 #ifdef __UNIX__
342 #define IsTopMostDir(dir) (dir == wxT("/"))
343 #endif
344
345 #if defined(__DOS__) || defined(__WINDOWS__)
346 #define IsTopMostDir(dir) (dir.IsEmpty())
347 #endif
348
349 #if defined(__DOS__) || defined(__WINDOWS__)
350 extern bool wxIsDriveAvailable(const wxString& dirName);
351 #endif
352
353 //-----------------------------------------------------------------------------
354 // wxFileData
355 //-----------------------------------------------------------------------------
356
357 wxFileData::wxFileData( const wxString &name, const wxString &fname, fileType type )
358 {
359 m_name = name;
360 m_fileName = fname;
361 m_type = type;
362
363 #if defined(__DOS__) || defined(__WINDOWS__)
364 // VS: In case the file is root directory of a volume (e.g. "C:"),
365 // we don't want it stat()ed, since the drive may not be in:
366 if (name.length() == 2 && name[1u] == wxT(':'))
367 {
368 m_type = is_drive;
369 m_size = 0;
370 return;
371 }
372
373 // This is a drive, even if MSW thinks c:\.. is a file
374 if ((name == wxT("..")) && (fname.length() <= 5))
375 {
376 m_type = is_drive;
377 m_size = 0;
378 return;
379 }
380 #endif // __DOS__ || __WINDOWS__
381
382 wxStructStat buff;
383
384 #if defined(__UNIX__) && (!defined( __EMX__ ) && !defined(__VMS))
385 lstat( m_fileName.fn_str(), &buff );
386 m_type |= S_ISLNK( buff.st_mode ) != 0 ? is_link : 0;
387 #else // no lstat()
388 wxStat( m_fileName, &buff );
389 #endif
390
391 m_type |= (buff.st_mode & S_IFDIR) != 0 ? is_dir : 0;
392 m_type |= (buff.st_mode & wxS_IXUSR) != 0 ? is_exe : 0;
393
394 m_size = buff.st_size;
395
396 const struct tm * const t = localtime( &buff.st_mtime );
397 m_hour = t->tm_hour;
398 m_minute = t->tm_min;
399 m_month = t->tm_mon+1;
400 m_day = t->tm_mday;
401 m_year = t->tm_year;
402 m_year += 1900;
403
404 m_permissions.Printf(_T("%c%c%c"),
405 buff.st_mode & wxS_IRUSR ? _T('r') : _T('-'),
406 buff.st_mode & wxS_IWUSR ? _T('w') : _T('-'),
407 buff.st_mode & wxS_IXUSR ? _T('x') : _T('-'));
408 }
409
410 wxString wxFileData::GetName() const
411 {
412 return m_name;
413 }
414
415 wxString wxFileData::GetFullName() const
416 {
417 return m_fileName;
418 }
419
420 bool wxFileData::IsDir() const
421 {
422 return (m_type & is_dir) != 0;
423 }
424 bool wxFileData::IsLink() const
425 {
426 return (m_type & is_link) != 0;
427 }
428 bool wxFileData::IsExe() const
429 {
430 return (m_type & is_exe) != 0;
431 }
432 bool wxFileData::IsDrive() const
433 {
434 return (m_type & is_drive) != 0;
435 }
436
437 wxString wxFileData::GetHint() const
438 {
439 wxString s = m_fileName;
440 s += wxT(" ");
441 if (IsDir())
442 s += wxT("<DIR> ");
443 else if (IsLink())
444 s += wxT("<LINK> ");
445 else if (IsDrive())
446 {
447 s += wxT("<DRIVE> ");
448 return s;
449 }
450 else
451 {
452 s += LongToString( m_size );
453 s += wxT(" bytes ");
454 }
455
456 s += IntToString( m_day );
457 s += wxT(".");
458 s += IntToString( m_month );
459 s += wxT(".");
460 s += IntToString( m_year );
461 s += wxT(" ");
462 s += IntToString( m_hour );
463 s += wxT(":");
464 s += IntToString( m_minute );
465 s += wxT(" ");
466 s += m_permissions;
467 return s;
468 };
469
470 wxString wxFileData::GetEntry( fileListFieldType num ) const
471 {
472 wxString s;
473 switch ( num )
474 {
475 case FileList_Name:
476 s = m_name;
477 break;
478
479 case FileList_Type:
480 if (IsDir())
481 s = _("<DIR>");
482 else if (IsLink())
483 s = _("<LINK>");
484 else if (IsDrive())
485 s = _("<DRIVE>");
486 else
487 s.Printf(_T("%ld"), m_size);
488 break;
489
490 case FileList_Date:
491 if (!IsDrive())
492 s.Printf(_T("%02d.%02d.%d"), m_day, m_month, m_year);
493 break;
494
495 case FileList_Time:
496 if (!IsDrive())
497 s.Printf(_T("%02d:%02d"), m_hour, m_minute);
498 break;
499
500 #ifdef __UNIX__
501 case FileList_Perm:
502 s = m_permissions;
503 break;
504 #endif // __UNIX__
505
506 default:
507 wxFAIL_MSG( _T("unexpected field in wxFileData::GetEntry()") );
508 }
509
510 return s;
511 }
512
513 void wxFileData::SetNewName( const wxString &name, const wxString &fname )
514 {
515 m_name = name;
516 m_fileName = fname;
517 }
518
519 void wxFileData::MakeItem( wxListItem &item )
520 {
521 item.m_text = m_name;
522 item.ClearAttributes();
523 if (IsExe())
524 item.SetTextColour(*wxRED);
525 if (IsDir())
526 item.SetTextColour(*wxBLUE);
527
528 if (IsDir())
529 item.m_image = FI_FOLDER;
530 if (IsDrive()) // FIXME - add icons for drives, see wxDirCtrl
531 item.m_image = FI_FOLDER;
532 else if (IsExe())
533 item.m_image = FI_EXECUTABLE;
534 else if (m_name.Find(wxT('.')) != wxNOT_FOUND)
535 item.m_image = g_IconsTable->GetIconID(m_name.AfterLast(wxT('.')));
536 else
537 item.m_image = FI_UNKNOWN;
538
539 if (IsLink())
540 {
541 wxColour *dg = wxTheColourDatabase->FindColour( _T("MEDIUM GREY") );
542 item.SetTextColour(*dg);
543 }
544 item.m_data = (long)this;
545 }
546
547 //-----------------------------------------------------------------------------
548 // wxFileCtrl
549 //-----------------------------------------------------------------------------
550
551 IMPLEMENT_DYNAMIC_CLASS(wxFileCtrl,wxListCtrl)
552
553 BEGIN_EVENT_TABLE(wxFileCtrl,wxListCtrl)
554 EVT_LIST_DELETE_ITEM(-1, wxFileCtrl::OnListDeleteItem)
555 EVT_LIST_END_LABEL_EDIT(-1, wxFileCtrl::OnListEndLabelEdit)
556 EVT_LIST_COL_CLICK(-1, wxFileCtrl::OnListColClick)
557 END_EVENT_TABLE()
558
559
560 wxFileCtrl::wxFileCtrl()
561 {
562 m_showHidden = FALSE;
563 m_goToParentControl = NULL;
564 m_newDirControl = NULL;
565 m_sort_foward = 1;
566 m_sort_field = wxFileData::FileList_Name;
567 }
568
569 wxFileCtrl::wxFileCtrl(wxWindow *win,
570 wxWindowID id,
571 const wxString& wild,
572 bool showHidden,
573 const wxPoint& pos,
574 const wxSize& size,
575 long style,
576 const wxValidator &validator,
577 const wxString &name)
578 : wxListCtrl(win, id, pos, size, style, validator, name),
579 m_wild(wild)
580 {
581 if (! g_IconsTable)
582 g_IconsTable = new wxFileIconsTable;
583 wxImageList *imageList = g_IconsTable->GetImageList();
584
585 SetImageList( imageList, wxIMAGE_LIST_SMALL );
586
587 m_goToParentControl =
588 m_newDirControl = NULL;
589
590 m_showHidden = showHidden;
591
592 m_sort_foward = 1;
593 m_sort_field = wxFileData::FileList_Name;
594
595 m_dirName = wxT("*");
596
597 if (style & wxLC_REPORT)
598 ChangeToReportMode();
599 }
600
601 void wxFileCtrl::ChangeToListMode()
602 {
603 ClearAll();
604 SetSingleStyle( wxLC_LIST );
605 UpdateFiles();
606 }
607
608 void wxFileCtrl::ChangeToReportMode()
609 {
610 ClearAll();
611 SetSingleStyle( wxLC_REPORT );
612
613 int w, h;
614 GetTextExtent(wxT("CCCCCCCCC"), &w, &h);
615
616 InsertColumn( 0, _("Name"), wxLIST_FORMAT_LEFT, w*2 );
617 InsertColumn( 1, _("Size"), wxLIST_FORMAT_LEFT, w );
618 InsertColumn( 2, _("Date"), wxLIST_FORMAT_LEFT, w );
619 InsertColumn( 3, _("Time"), wxLIST_FORMAT_LEFT, w/2 );
620 #ifdef __UNIX__
621 InsertColumn( 4, _("Permissions"), wxLIST_FORMAT_LEFT, (w*12)/9 );
622 #endif
623
624 UpdateFiles();
625 }
626
627 void wxFileCtrl::ChangeToIconMode()
628 {
629 ClearAll();
630 SetSingleStyle( wxLC_ICON );
631 UpdateFiles();
632 }
633
634 void wxFileCtrl::ShowHidden( bool show )
635 {
636 m_showHidden = show;
637 UpdateFiles();
638 }
639
640 long wxFileCtrl::Add( wxFileData *fd, wxListItem &item )
641 {
642 long ret = -1;
643 item.m_mask = wxLIST_MASK_TEXT + wxLIST_MASK_DATA + wxLIST_MASK_IMAGE;
644 fd->MakeItem( item );
645 long my_style = GetWindowStyleFlag();
646 if (my_style & wxLC_REPORT)
647 {
648 ret = InsertItem( item );
649 for (int i = 1; i < wxFileData::FileList_Max; i++)
650 SetItem( item.m_itemId, i, fd->GetEntry((wxFileData::fileListFieldType)i) );
651 }
652 else if (my_style & wxLC_LIST)
653 {
654 ret = InsertItem( item );
655 }
656 return ret;
657 }
658
659 void wxFileCtrl::UpdateFiles()
660 {
661 // don't do anything before ShowModal() call which sets m_dirName
662 if ( m_dirName == wxT("*") )
663 return;
664
665 wxBusyCursor bcur; // this may take a while...
666
667 FreeAllItemsData();
668 DeleteAllItems();
669
670 wxFileData *fd = (wxFileData *) NULL;
671 wxListItem item;
672 item.m_itemId = 0;
673 item.m_col = 0;
674
675 #if defined(__DOS__) || defined(__WINDOWS__)
676 if ( IsTopMostDir(m_dirName) )
677 {
678 // Pseudo-directory with all available drives listed...
679 for (int drive = 1; drive <= 26; drive++)
680 {
681 wxString path;
682 path.Printf(wxT("%c:\\"), (char)(drive + 'A' - 1));
683 if ( wxIsDriveAvailable(path) )
684 {
685 path.RemoveLast();
686 fd = new wxFileData(path, path, wxFileData::is_drive);
687 Add(fd, item);
688 item.m_itemId++;
689 }
690 }
691 }
692 else
693 #endif
694 {
695 // Real directory...
696 if ( !IsTopMostDir(m_dirName) )
697 {
698 wxString p(wxPathOnly(m_dirName));
699 #ifdef __UNIX__
700 if (p.IsEmpty()) p = wxT("/");
701 #endif
702 fd = new wxFileData( wxT(".."), p, wxFileData::is_dir );
703 Add(fd, item);
704 item.m_itemId++;
705 }
706
707 wxString dirname(m_dirName);
708 #if defined(__DOS__) || defined(__WINDOWS__)
709 if (dirname.length() == 2 && dirname[1u] == wxT(':'))
710 dirname << wxT('\\');
711 #endif
712 wxDir dir(dirname);
713
714 if ( dir.IsOpened() )
715 {
716 wxString dirPrefix(dirname);
717 if (dirPrefix.Last() != wxFILE_SEP_PATH)
718 dirPrefix += wxFILE_SEP_PATH;
719
720 int hiddenFlag = m_showHidden ? wxDIR_HIDDEN : 0;
721
722 bool cont;
723 wxString f;
724
725 // Get the directories first (not matched against wildcards):
726 cont = dir.GetFirst(&f, wxEmptyString, wxDIR_DIRS | hiddenFlag);
727 while (cont)
728 {
729 fd = new wxFileData(f, dirPrefix + f, wxFileData::is_dir);
730 Add(fd, item);
731 item.m_itemId++;
732 cont = dir.GetNext(&f);
733 }
734
735 // Tokenize the wildcard string, so we can handle more than 1
736 // search pattern in a wildcard.
737 wxStringTokenizer tokenWild(m_wild, wxT(";"));
738 while ( tokenWild.HasMoreTokens() )
739 {
740 cont = dir.GetFirst(&f, tokenWild.GetNextToken(),
741 wxDIR_FILES | hiddenFlag);
742 while (cont)
743 {
744 fd = new wxFileData(f, dirPrefix + f, wxFileData::is_file);
745 Add(fd, item);
746 item.m_itemId++;
747 cont = dir.GetNext(&f);
748 }
749 }
750 }
751 }
752
753 SortItems(m_sort_field, m_sort_foward > 0);
754
755 // Finally, enable/disable context-dependent controls:
756 if ( m_goToParentControl )
757 m_goToParentControl->Enable(!IsTopMostDir(m_dirName));
758 #if defined(__DOS__) || defined(__WINDOWS__)
759 if ( m_newDirControl )
760 m_newDirControl->Enable(!IsTopMostDir(m_dirName));
761 #endif
762 }
763
764 void wxFileCtrl::SetWild( const wxString &wild )
765 {
766 m_wild = wild;
767 UpdateFiles();
768 }
769
770 void wxFileCtrl::MakeDir()
771 {
772 wxString new_name( _("NewName") );
773 wxString path( m_dirName );
774 path += wxFILE_SEP_PATH;
775 path += new_name;
776 if (wxFileExists(path))
777 {
778 // try NewName0, NewName1 etc.
779 int i = 0;
780 do {
781 new_name = _("NewName");
782 wxString num;
783 num.Printf( wxT("%d"), i );
784 new_name += num;
785
786 path = m_dirName;
787 path += wxFILE_SEP_PATH;
788 path += new_name;
789 i++;
790 } while (wxFileExists(path));
791 }
792
793 wxLogNull log;
794 if (!wxMkdir(path))
795 {
796 wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
797 dialog.ShowModal();
798 return;
799 }
800
801 wxFileData *fd = new wxFileData( new_name, path, wxFileData::is_dir );
802 wxListItem item;
803 item.m_itemId = 0;
804 item.m_col = 0;
805 long id = Add( fd, item );
806
807 if (id != -1)
808 {
809 SortItems(m_sort_field, m_sort_foward > 0);
810 id = FindItem( 0, (long)fd );
811 EnsureVisible( id );
812 EditLabel( id );
813 }
814 }
815
816 void wxFileCtrl::GoToParentDir()
817 {
818 if (!IsTopMostDir(m_dirName))
819 {
820 size_t len = m_dirName.Len();
821 if (wxEndsWithPathSeparator(m_dirName))
822 m_dirName.Remove( len-1, 1 );
823 wxString fname( wxFileNameFromPath(m_dirName) );
824 m_dirName = wxPathOnly( m_dirName );
825 #if defined(__DOS__) || defined(__WINDOWS__)
826 if (!m_dirName.IsEmpty())
827 {
828 if (m_dirName.Last() == wxT('.'))
829 m_dirName = wxT("");
830 }
831 #elif defined(__UNIX__)
832 if (m_dirName.IsEmpty())
833 m_dirName = wxT("/");
834 #endif
835 UpdateFiles();
836 long id = FindItem( 0, fname );
837 if (id != -1)
838 {
839 SetItemState( id, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
840 EnsureVisible( id );
841 }
842 }
843 }
844
845 void wxFileCtrl::GoToHomeDir()
846 {
847 wxString s = wxGetUserHome( wxString() );
848 GoToDir(s);
849 }
850
851 void wxFileCtrl::GoToDir( const wxString &dir )
852 {
853 m_dirName = dir;
854 UpdateFiles();
855 SetItemState( 0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
856 EnsureVisible( 0 );
857 }
858
859 void wxFileCtrl::GetDir( wxString &dir )
860 {
861 dir = m_dirName;
862 }
863
864 void wxFileCtrl::FreeItemData(const wxListItem& item)
865 {
866 wxFileData *fd = (wxFileData*)item.m_data;
867 delete fd;
868 }
869
870 void wxFileCtrl::OnListDeleteItem( wxListEvent &event )
871 {
872 FreeItemData(event.m_item);
873 }
874
875 void wxFileCtrl::FreeAllItemsData()
876 {
877 wxListItem item;
878 item.m_mask = wxLIST_MASK_DATA;
879
880 item.m_itemId = GetNextItem( -1, wxLIST_NEXT_ALL );
881 while ( item.m_itemId != -1 )
882 {
883 GetItem( item );
884 FreeItemData(item);
885 item.m_itemId = GetNextItem( item.m_itemId, wxLIST_NEXT_ALL );
886 }
887 }
888
889 void wxFileCtrl::OnListEndLabelEdit( wxListEvent &event )
890 {
891 wxFileData *fd = (wxFileData*)event.m_item.m_data;
892 wxASSERT( fd );
893
894 if ((event.GetLabel().IsEmpty()) ||
895 (event.GetLabel() == _(".")) ||
896 (event.GetLabel() == _("..")) ||
897 (event.GetLabel().First( wxFILE_SEP_PATH ) != wxNOT_FOUND))
898 {
899 wxMessageDialog dialog(this, _("Illegal directory name."), _("Error"), wxOK | wxICON_ERROR );
900 dialog.ShowModal();
901 event.Veto();
902 return;
903 }
904
905 wxString new_name( wxPathOnly( fd->GetFullName() ) );
906 new_name += wxFILE_SEP_PATH;
907 new_name += event.GetLabel();
908
909 wxLogNull log;
910
911 if (wxFileExists(new_name))
912 {
913 wxMessageDialog dialog(this, _("File name exists already."), _("Error"), wxOK | wxICON_ERROR );
914 dialog.ShowModal();
915 event.Veto();
916 }
917
918 if (wxRenameFile(fd->GetFullName(),new_name))
919 {
920 fd->SetNewName( new_name, event.GetLabel() );
921 SetItemState( event.GetItem(), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
922 EnsureVisible( event.GetItem() );
923 }
924 else
925 {
926 wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
927 dialog.ShowModal();
928 event.Veto();
929 }
930 }
931
932 void wxFileCtrl::OnListColClick( wxListEvent &event )
933 {
934 int col = event.GetColumn();
935
936 switch (col)
937 {
938 case wxFileData::FileList_Name :
939 case wxFileData::FileList_Type :
940 case wxFileData::FileList_Date :
941 case wxFileData::FileList_Time : break;
942 default : return;
943 }
944
945 if ((wxFileData::fileListFieldType)col == m_sort_field)
946 m_sort_foward = -m_sort_foward;
947 else
948 m_sort_field = (wxFileData::fileListFieldType)col;
949
950 SortItems(m_sort_field, m_sort_foward > 0);
951 }
952
953 void wxFileCtrl::SortItems(wxFileData::fileListFieldType field, bool foward)
954 {
955 m_sort_field = field;
956 m_sort_foward = foward ? 1 : -1;
957
958 switch (m_sort_field)
959 {
960 case wxFileData::FileList_Name :
961 {
962 wxListCtrl::SortItems((wxListCtrlCompare)wxFileDataNameCompare, m_sort_foward);
963 break;
964 }
965 case wxFileData::FileList_Type :
966 {
967 wxListCtrl::SortItems((wxListCtrlCompare)wxFileDataTypeCompare, m_sort_foward);
968 break;
969 }
970 case wxFileData::FileList_Date :
971 case wxFileData::FileList_Time :
972 {
973 wxListCtrl::SortItems((wxListCtrlCompare)wxFileDataTimeCompare, m_sort_foward);
974 break;
975 }
976 default : break;
977 }
978 }
979
980 wxFileCtrl::~wxFileCtrl()
981 {
982 FreeAllItemsData();
983 }
984
985 //-----------------------------------------------------------------------------
986 // wxGenericFileDialog
987 //-----------------------------------------------------------------------------
988
989 #define ID_LIST_MODE (wxID_FILEDLGG )
990 #define ID_REPORT_MODE (wxID_FILEDLGG + 1)
991 #define ID_UP_DIR (wxID_FILEDLGG + 5)
992 #define ID_PARENT_DIR (wxID_FILEDLGG + 6)
993 #define ID_NEW_DIR (wxID_FILEDLGG + 7)
994 #define ID_CHOICE (wxID_FILEDLGG + 8)
995 #define ID_TEXT (wxID_FILEDLGG + 9)
996 #define ID_LIST_CTRL (wxID_FILEDLGG + 10)
997 #define ID_ACTIVATED (wxID_FILEDLGG + 11)
998 #define ID_CHECK (wxID_FILEDLGG + 12)
999
1000 IMPLEMENT_DYNAMIC_CLASS(wxGenericFileDialog,wxDialog)
1001
1002 BEGIN_EVENT_TABLE(wxGenericFileDialog,wxDialog)
1003 EVT_BUTTON(ID_LIST_MODE, wxGenericFileDialog::OnList)
1004 EVT_BUTTON(ID_REPORT_MODE, wxGenericFileDialog::OnReport)
1005 EVT_BUTTON(ID_UP_DIR, wxGenericFileDialog::OnUp)
1006 EVT_BUTTON(ID_PARENT_DIR, wxGenericFileDialog::OnHome)
1007 EVT_BUTTON(ID_NEW_DIR, wxGenericFileDialog::OnNew)
1008 EVT_BUTTON(wxID_OK, wxGenericFileDialog::OnListOk)
1009 EVT_LIST_ITEM_SELECTED(ID_LIST_CTRL, wxGenericFileDialog::OnSelected)
1010 EVT_LIST_ITEM_ACTIVATED(ID_LIST_CTRL, wxGenericFileDialog::OnActivated)
1011 EVT_CHOICE(ID_CHOICE,wxGenericFileDialog::OnChoiceFilter)
1012 EVT_TEXT_ENTER(ID_TEXT,wxGenericFileDialog::OnTextEnter)
1013 EVT_TEXT(ID_TEXT,wxGenericFileDialog::OnTextChange)
1014 EVT_CHECKBOX(ID_CHECK,wxGenericFileDialog::OnCheck)
1015 END_EVENT_TABLE()
1016
1017 long wxGenericFileDialog::ms_lastViewStyle = wxLC_LIST;
1018 bool wxGenericFileDialog::ms_lastShowHidden = FALSE;
1019
1020 wxGenericFileDialog::wxGenericFileDialog(wxWindow *parent,
1021 const wxString& message,
1022 const wxString& defaultDir,
1023 const wxString& defaultFile,
1024 const wxString& wildCard,
1025 long style,
1026 const wxPoint& pos )
1027 : wxDialog( parent, -1, message, pos, wxDefaultSize,
1028 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER )
1029 {
1030 if (wxConfig::Get(FALSE))
1031 {
1032 wxConfig::Get()->Read(wxT("/wxWindows/wxFileDialog/ViewStyle"),
1033 &ms_lastViewStyle);
1034 wxConfig::Get()->Read(wxT("/wxWindows/wxFileDialog/ShowHidden"),
1035 &ms_lastShowHidden);
1036 }
1037
1038 m_message = message;
1039 m_dialogStyle = style;
1040
1041 if (m_dialogStyle == 0)
1042 m_dialogStyle = wxOPEN;
1043 if ((m_dialogStyle & wxMULTIPLE ) && !(m_dialogStyle & wxOPEN))
1044 m_dialogStyle |= wxOPEN;
1045
1046 m_dir = defaultDir;
1047 if ((m_dir.empty()) || (m_dir == wxT(".")))
1048 {
1049 m_dir = wxGetCwd();
1050 }
1051
1052 size_t len = m_dir.Len();
1053 if ((len > 1) && (wxEndsWithPathSeparator(m_dir)))
1054 m_dir.Remove( len-1, 1 );
1055
1056 m_path = m_dir;
1057 m_path += wxFILE_SEP_PATH;
1058 m_path += defaultFile;
1059 m_fileName = defaultFile;
1060 m_wildCard = wildCard;
1061 m_filterIndex = 0;
1062 m_filterExtension = wxEmptyString;
1063
1064 // interpret wildcards
1065
1066 if (m_wildCard.IsEmpty())
1067 m_wildCard = _("All files (*)|*");
1068
1069 wxStringTokenizer tokens( m_wildCard, wxT("|") );
1070 wxString firstWild;
1071 wxString firstWildText;
1072 if (tokens.CountTokens() == 1)
1073 {
1074 firstWildText = tokens.GetNextToken();
1075 firstWild = firstWildText;
1076 }
1077 else
1078 {
1079 wxASSERT_MSG( tokens.CountTokens() % 2 == 0, wxT("Wrong file type descripition") );
1080 firstWildText = tokens.GetNextToken();
1081 firstWild = tokens.GetNextToken();
1082 }
1083 if ( firstWild.Left( 2 ) == wxT("*.") )
1084 m_filterExtension = firstWild.Mid( 1 );
1085 if ( m_filterExtension == wxT(".*") )
1086 m_filterExtension = wxEmptyString;
1087
1088 // layout
1089
1090 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
1091
1092 wxBoxSizer *mainsizer = new wxBoxSizer( wxVERTICAL );
1093
1094 wxBoxSizer *buttonsizer = new wxBoxSizer( wxHORIZONTAL );
1095
1096 wxBitmapButton *but;
1097
1098 but = new wxBitmapButton(this, ID_LIST_MODE,
1099 wxArtProvider::GetBitmap(wxART_LIST_VIEW, wxART_CMN_DIALOG));
1100 #if wxUSE_TOOLTIPS
1101 but->SetToolTip( _("View files as a list view") );
1102 #endif
1103 buttonsizer->Add( but, 0, wxALL, 5 );
1104
1105 but = new wxBitmapButton(this, ID_REPORT_MODE,
1106 wxArtProvider::GetBitmap(wxART_REPORT_VIEW, wxART_CMN_DIALOG));
1107 #if wxUSE_TOOLTIPS
1108 but->SetToolTip( _("View files as a detailed view") );
1109 #endif
1110 buttonsizer->Add( but, 0, wxALL, 5 );
1111
1112 buttonsizer->Add( 30, 5, 1 );
1113
1114 wxWindow *butDirUp =
1115 new wxBitmapButton(this, ID_UP_DIR,
1116 wxArtProvider::GetBitmap(wxART_GO_DIR_UP, wxART_CMN_DIALOG));
1117 #if wxUSE_TOOLTIPS
1118 butDirUp->SetToolTip( _("Go to parent directory") );
1119 #endif
1120 buttonsizer->Add( butDirUp, 0, wxALL, 5 );
1121
1122 #ifndef __DOS__ // VS: Home directory is meaningless in MS-DOS...
1123 but = new wxBitmapButton(this, ID_PARENT_DIR,
1124 wxArtProvider::GetBitmap(wxART_GO_HOME, wxART_CMN_DIALOG));
1125 #if wxUSE_TOOLTIPS
1126 but->SetToolTip( _("Go to home directory") );
1127 #endif
1128 buttonsizer->Add( but, 0, wxALL, 5);
1129
1130 buttonsizer->Add( 20, 20 );
1131 #endif //!__DOS__
1132
1133 wxWindow *butNewDir =
1134 new wxBitmapButton(this, ID_NEW_DIR,
1135 wxArtProvider::GetBitmap(wxART_NEW_DIR, wxART_CMN_DIALOG));
1136 #if wxUSE_TOOLTIPS
1137 butNewDir->SetToolTip( _("Create new directory") );
1138 #endif
1139 buttonsizer->Add( butNewDir, 0, wxALL, 5 );
1140
1141 if (is_pda)
1142 mainsizer->Add( buttonsizer, 0, wxALL | wxEXPAND, 0 );
1143 else
1144 mainsizer->Add( buttonsizer, 0, wxALL | wxEXPAND, 5 );
1145
1146 wxBoxSizer *staticsizer = new wxBoxSizer( wxHORIZONTAL );
1147 if (is_pda)
1148 staticsizer->Add( new wxStaticText( this, -1, _("Current directory:") ), 0, wxRIGHT, 10 );
1149 m_static = new wxStaticText( this, -1, m_dir );
1150 staticsizer->Add( m_static, 1 );
1151 mainsizer->Add( staticsizer, 0, wxEXPAND | wxLEFT|wxRIGHT|wxBOTTOM, 10 );
1152
1153 long style2 = ms_lastViewStyle | wxSUNKEN_BORDER;
1154 if ( !(m_dialogStyle & wxMULTIPLE) )
1155 style2 |= wxLC_SINGLE_SEL;
1156
1157 m_list = new wxFileCtrl( this, ID_LIST_CTRL,
1158 firstWild, ms_lastShowHidden,
1159 wxDefaultPosition, wxSize(540,200),
1160 style2);
1161
1162 m_list->SetNewDirControl(butNewDir);
1163 m_list->SetGoToParentControl(butDirUp);
1164
1165 if (is_pda)
1166 {
1167 // PDAs have a different screen layout
1168 mainsizer->Add( m_list, 1, wxEXPAND | wxLEFT|wxRIGHT, 5 );
1169
1170 wxBoxSizer *choicesizer = new wxBoxSizer( wxHORIZONTAL );
1171 m_choice = new wxChoice( this, ID_CHOICE );
1172 choicesizer->Add( m_choice, 1, wxCENTER|wxALL, 5 );
1173 mainsizer->Add( choicesizer, 0, wxEXPAND );
1174
1175 wxBoxSizer *textsizer = new wxBoxSizer( wxHORIZONTAL );
1176 m_text = new wxTextCtrl( this, ID_TEXT, m_fileName, wxDefaultPosition, wxDefaultSize, wxPROCESS_ENTER );
1177 textsizer->Add( m_text, 1, wxCENTER | wxALL, 5 );
1178 mainsizer->Add( textsizer, 0, wxEXPAND );
1179
1180 m_check = new wxCheckBox( this, ID_CHECK, _("Show hidden files") );
1181 m_check->SetValue( ms_lastShowHidden );
1182 textsizer->Add( m_check, 0, wxCENTER|wxALL, 5 );
1183
1184 buttonsizer = new wxBoxSizer( wxHORIZONTAL );
1185 buttonsizer->Add( new wxButton( this, wxID_OK, _("OK") ), 0, wxCENTER | wxALL, 5 );
1186 buttonsizer->Add( new wxButton( this, wxID_CANCEL, _("Cancel") ), 0, wxCENTER | wxALL, 5 );
1187 mainsizer->Add( buttonsizer, 0, wxALIGN_RIGHT );
1188 }
1189 else
1190 {
1191 mainsizer->Add( m_list, 1, wxEXPAND | wxLEFT|wxRIGHT, 10 );
1192
1193 wxBoxSizer *textsizer = new wxBoxSizer( wxHORIZONTAL );
1194 m_text = new wxTextCtrl( this, ID_TEXT, m_fileName, wxDefaultPosition, wxDefaultSize, wxPROCESS_ENTER );
1195 textsizer->Add( m_text, 1, wxCENTER | wxLEFT|wxRIGHT|wxTOP, 10 );
1196 textsizer->Add( new wxButton( this, wxID_OK, _("OK") ), 0, wxCENTER | wxLEFT|wxRIGHT|wxTOP, 10 );
1197 mainsizer->Add( textsizer, 0, wxEXPAND );
1198
1199 wxBoxSizer *choicesizer = new wxBoxSizer( wxHORIZONTAL );
1200 m_choice = new wxChoice( this, ID_CHOICE );
1201 choicesizer->Add( m_choice, 1, wxCENTER|wxALL, 10 );
1202 m_check = new wxCheckBox( this, ID_CHECK, _("Show hidden files") );
1203 m_check->SetValue( ms_lastShowHidden );
1204 choicesizer->Add( m_check, 0, wxCENTER|wxALL, 10 );
1205 choicesizer->Add( new wxButton( this, wxID_CANCEL, _("Cancel") ), 0, wxCENTER | wxALL, 10 );
1206 mainsizer->Add( choicesizer, 0, wxEXPAND );
1207 }
1208
1209 // FIXME - memory leaks!!
1210
1211 m_choice->Append( firstWildText, (void*) new wxString( firstWild ) );
1212 while (tokens.HasMoreTokens())
1213 {
1214 firstWildText = tokens.GetNextToken();
1215 firstWild = tokens.GetNextToken();
1216 m_choice->Append( firstWildText, (void*) new wxString( firstWild ) );
1217 }
1218 m_choice->SetSelection( 0 );
1219
1220 SetAutoLayout( TRUE );
1221 SetSizer( mainsizer );
1222
1223 mainsizer->Fit( this );
1224 mainsizer->SetSizeHints( this );
1225
1226 Centre( wxBOTH );
1227
1228 m_text->SetFocus();
1229 }
1230
1231 wxGenericFileDialog::~wxGenericFileDialog()
1232 {
1233 if (wxConfig::Get(FALSE))
1234 {
1235 wxConfig::Get()->Write(wxT("/wxWindows/wxFileDialog/ViewStyle"),
1236 ms_lastViewStyle);
1237 wxConfig::Get()->Write(wxT("/wxWindows/wxFileDialog/ShowHidden"),
1238 ms_lastShowHidden);
1239 }
1240
1241 const int count = m_choice->GetCount();
1242 for ( int i = 0; i < count; i++ )
1243 {
1244 delete (wxString *)m_choice->GetClientData(i);
1245 }
1246 }
1247
1248 int wxGenericFileDialog::ShowModal()
1249 {
1250 m_list->GoToDir(m_dir);
1251 m_static->SetLabel(m_list->GetDir());
1252 m_text->SetValue(m_fileName);
1253
1254 return wxDialog::ShowModal();
1255 }
1256
1257 void wxGenericFileDialog::DoSetFilterIndex(int filterindex)
1258 {
1259 wxString *str = (wxString*) m_choice->GetClientData( filterindex );
1260 m_list->SetWild( *str );
1261 m_filterIndex = filterindex;
1262 if ( str->Left(2) == wxT("*.") )
1263 {
1264 m_filterExtension = str->Mid(1);
1265 if (m_filterExtension == _T(".*"))
1266 m_filterExtension.clear();
1267 }
1268 else
1269 {
1270 m_filterExtension.clear();
1271 }
1272 }
1273
1274 void wxGenericFileDialog::SetFilterIndex( int filterindex )
1275 {
1276 m_choice->SetSelection( filterindex );
1277
1278 DoSetFilterIndex(filterindex);
1279 }
1280
1281 void wxGenericFileDialog::OnChoiceFilter( wxCommandEvent &event )
1282 {
1283 DoSetFilterIndex((int)event.GetInt());
1284 }
1285
1286 void wxGenericFileDialog::OnCheck( wxCommandEvent &event )
1287 {
1288 m_list->ShowHidden( (ms_lastShowHidden = event.GetInt() != 0) );
1289 }
1290
1291 void wxGenericFileDialog::OnActivated( wxListEvent &event )
1292 {
1293 HandleAction( event.m_item.m_text );
1294 }
1295
1296 void wxGenericFileDialog::OnTextEnter( wxCommandEvent &WXUNUSED(event) )
1297 {
1298 wxCommandEvent cevent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK);
1299 cevent.SetEventObject( this );
1300 GetEventHandler()->ProcessEvent( cevent );
1301 }
1302
1303 static bool ignoreChanges = FALSE;
1304
1305 void wxGenericFileDialog::OnTextChange( wxCommandEvent &WXUNUSED(event) )
1306 {
1307 if (!ignoreChanges)
1308 {
1309 // Clear selections. Otherwise when the user types in a value they may
1310 // not get the file whose name they typed.
1311 if (m_list->GetSelectedItemCount() > 0)
1312 {
1313 long item = m_list->GetNextItem(-1, wxLIST_NEXT_ALL,
1314 wxLIST_STATE_SELECTED);
1315 while ( item != -1 )
1316 {
1317 m_list->SetItemState(item,0, wxLIST_STATE_SELECTED);
1318 item = m_list->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
1319 }
1320 }
1321 }
1322 }
1323
1324 void wxGenericFileDialog::OnSelected( wxListEvent &event )
1325 {
1326 wxString filename( event.m_item.m_text );
1327 if (filename == wxT("..")) return;
1328
1329 wxString dir;
1330 m_list->GetDir( dir );
1331 if (!IsTopMostDir(dir))
1332 dir += wxFILE_SEP_PATH;
1333 dir += filename;
1334 if (wxDirExists(dir)) return;
1335
1336 ignoreChanges = TRUE;
1337 m_text->SetValue( filename );
1338 ignoreChanges = FALSE;
1339 }
1340
1341 void wxGenericFileDialog::HandleAction( const wxString &fn )
1342 {
1343 wxString filename( fn );
1344 wxString dir;
1345 m_list->GetDir( dir );
1346 if (filename.IsEmpty()) return;
1347 if (filename == wxT(".")) return;
1348
1349 if (filename == wxT(".."))
1350 {
1351 m_list->GoToParentDir();
1352 m_list->SetFocus();
1353 m_static->SetLabel(m_list->GetDir());
1354 return;
1355 }
1356
1357 #ifdef __UNIX__
1358 if (filename == wxT("~"))
1359 {
1360 m_list->GoToHomeDir();
1361 m_list->SetFocus();
1362 m_static->SetLabel(m_list->GetDir());
1363 return;
1364 }
1365
1366 if (filename[0u] == wxT('~'))
1367 {
1368 filename.Remove( 0, 1 );
1369 wxString tmp( wxGetUserHome() );
1370 tmp += wxT('/');
1371 tmp += filename;
1372 filename = tmp;
1373 }
1374 #endif // __UNIX__
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."), _("Error"), wxOK | wxICON_ERROR );
1382 return;
1383 }
1384 m_list->SetWild( filename );
1385 return;
1386 }
1387
1388 if (!IsTopMostDir(dir))
1389 dir += wxFILE_SEP_PATH;
1390 if (!wxIsAbsolutePath(filename))
1391 {
1392 dir += filename;
1393 filename = dir;
1394 }
1395
1396 if (wxDirExists(filename))
1397 {
1398 m_list->GoToDir( filename );
1399 m_static->SetLabel(m_list->GetDir());
1400 return;
1401 }
1402
1403 // append the default extension to the filename if it doesn't have any
1404 //
1405 // VZ: the logic of testing for !wxFileExists() only for the open file
1406 // dialog is not entirely clear to me, why don't we allow saving to a
1407 // file without extension as well?
1408 if ( !(m_dialogStyle & wxOPEN) || !wxFileExists(filename) )
1409 {
1410 wxString ext;
1411 wxSplitPath(filename, NULL, NULL, &ext);
1412 if ( ext.empty() )
1413 {
1414 // append the first extension of the filter string
1415 filename += m_filterExtension.BeforeFirst(_T(';'));
1416 }
1417 }
1418
1419 // check that the file [doesn't] exist if necessary
1420 if ( (m_dialogStyle & wxSAVE) &&
1421 (m_dialogStyle & wxOVERWRITE_PROMPT) &&
1422 wxFileExists( filename ) )
1423 {
1424 wxString msg;
1425 msg.Printf( _("File '%s' already exists, do you really want to "
1426 "overwrite it?"), filename.c_str() );
1427
1428 if (wxMessageBox(msg, _("Confirm"), wxYES_NO) != wxYES)
1429 return;
1430 }
1431 else if ( (m_dialogStyle & wxOPEN) &&
1432 (m_dialogStyle & wxFILE_MUST_EXIST) &&
1433 !wxFileExists(filename) )
1434 {
1435 wxMessageBox(_("Please choose an existing file."), _("Error"),
1436 wxOK | wxICON_ERROR );
1437 }
1438
1439 SetPath( filename );
1440
1441 // change to the directory where the user went if asked
1442 if ( m_dialogStyle & wxCHANGE_DIR )
1443 {
1444 wxString cwd;
1445 wxSplitPath(filename, &cwd, NULL, NULL);
1446
1447 if ( cwd != wxGetWorkingDirectory() )
1448 {
1449 wxSetWorkingDirectory(cwd);
1450 }
1451 }
1452
1453 wxCommandEvent event;
1454 wxDialog::OnOK(event);
1455 }
1456
1457 void wxGenericFileDialog::OnListOk( wxCommandEvent &WXUNUSED(event) )
1458 {
1459 HandleAction( m_text->GetValue() );
1460 }
1461
1462 void wxGenericFileDialog::OnList( wxCommandEvent &WXUNUSED(event) )
1463 {
1464 m_list->ChangeToListMode();
1465 ms_lastViewStyle = wxLC_LIST;
1466 m_list->SetFocus();
1467 }
1468
1469 void wxGenericFileDialog::OnReport( wxCommandEvent &WXUNUSED(event) )
1470 {
1471 m_list->ChangeToReportMode();
1472 ms_lastViewStyle = wxLC_REPORT;
1473 m_list->SetFocus();
1474 }
1475
1476 void wxGenericFileDialog::OnUp( wxCommandEvent &WXUNUSED(event) )
1477 {
1478 m_list->GoToParentDir();
1479 m_list->SetFocus();
1480 m_static->SetLabel(m_list->GetDir());
1481 }
1482
1483 void wxGenericFileDialog::OnHome( wxCommandEvent &WXUNUSED(event) )
1484 {
1485 m_list->GoToHomeDir();
1486 m_list->SetFocus();
1487 m_static->SetLabel(m_list->GetDir());
1488 }
1489
1490 void wxGenericFileDialog::OnNew( wxCommandEvent &WXUNUSED(event) )
1491 {
1492 m_list->MakeDir();
1493 }
1494
1495 void wxGenericFileDialog::SetPath( const wxString& path )
1496 {
1497 // not only set the full path but also update filename and dir
1498 m_path = path;
1499 if ( !path.empty() )
1500 {
1501 wxString ext;
1502 wxSplitPath(path, &m_dir, &m_fileName, &ext);
1503 if (!ext.empty())
1504 {
1505 m_fileName += wxT(".");
1506 m_fileName += ext;
1507 }
1508 }
1509 }
1510
1511 void wxGenericFileDialog::GetPaths( wxArrayString& paths ) const
1512 {
1513 paths.Empty();
1514 if (m_list->GetSelectedItemCount() == 0)
1515 {
1516 paths.Add( GetPath() );
1517 return;
1518 }
1519
1520 paths.Alloc( m_list->GetSelectedItemCount() );
1521
1522 wxString dir;
1523 m_list->GetDir( dir );
1524 #ifdef __UNIX__
1525 if (dir != wxT("/"))
1526 #endif
1527 dir += wxFILE_SEP_PATH;
1528
1529 wxListItem item;
1530 item.m_mask = wxLIST_MASK_TEXT;
1531
1532 item.m_itemId = m_list->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
1533 while ( item.m_itemId != -1 )
1534 {
1535 m_list->GetItem( item );
1536 paths.Add( dir + item.m_text );
1537 item.m_itemId = m_list->GetNextItem( item.m_itemId,
1538 wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
1539 }
1540 }
1541
1542 void wxGenericFileDialog::GetFilenames(wxArrayString& files) const
1543 {
1544 files.Empty();
1545 if (m_list->GetSelectedItemCount() == 0)
1546 {
1547 files.Add( GetFilename() );
1548 return;
1549 }
1550 files.Alloc( m_list->GetSelectedItemCount() );
1551
1552 wxListItem item;
1553 item.m_mask = wxLIST_MASK_TEXT;
1554
1555 item.m_itemId = m_list->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
1556 while ( item.m_itemId != -1 )
1557 {
1558 m_list->GetItem( item );
1559 files.Add( item.m_text );
1560 item.m_itemId = m_list->GetNextItem( item.m_itemId,
1561 wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
1562 }
1563 }
1564
1565 #ifdef USE_GENERIC_FILEDIALOG
1566
1567 IMPLEMENT_DYNAMIC_CLASS(wxFileDialog, wxGenericFileDialog);
1568
1569 // ----------------------------------------------------------------------------
1570 // global functions
1571 // ----------------------------------------------------------------------------
1572
1573 // common part of both wxFileSelectorEx() and wxFileSelector()
1574 static wxString
1575 DoSelectFile(const wxChar *title,
1576 const wxChar *defaultDir,
1577 const wxChar *defaultFileName,
1578 const wxChar *defaultExtension,
1579 int *indexDefaultExtension,
1580 const wxChar *filter,
1581 int flags,
1582 wxWindow *parent,
1583 int x,
1584 int y)
1585 {
1586 // the filter may be either given explicitly or created automatically from
1587 // the default extension
1588 wxString filterReal;
1589 if ( filter )
1590 {
1591 // the user has specified the filter explicitly, use it
1592 filterReal = filter;
1593 }
1594 else if ( !wxIsEmpty(defaultExtension) )
1595 {
1596 // create the filter to match the given extension
1597 filterReal << wxT("*.") << defaultExtension;
1598 }
1599
1600 wxFileDialog fileDialog(parent,
1601 title,
1602 defaultDir,
1603 defaultFileName,
1604 filterReal,
1605 flags,
1606 wxPoint(x, y));
1607
1608 wxString path;
1609 if ( fileDialog.ShowModal() == wxID_OK )
1610 {
1611 path = fileDialog.GetPath();
1612 if ( indexDefaultExtension )
1613 {
1614 *indexDefaultExtension = fileDialog.GetFilterIndex();
1615 }
1616 }
1617
1618 return path;
1619 }
1620
1621 wxString
1622 wxFileSelectorEx(const wxChar *title,
1623 const wxChar *defaultDir,
1624 const wxChar *defaultFileName,
1625 int *indexDefaultExtension,
1626 const wxChar *filter,
1627 int flags,
1628 wxWindow *parent,
1629 int x,
1630 int y)
1631 {
1632 return DoSelectFile(title,
1633 defaultDir,
1634 defaultFileName,
1635 wxT(""), // def ext determined by index
1636 indexDefaultExtension,
1637 filter,
1638 flags,
1639 parent,
1640 x,
1641 y);
1642 }
1643
1644 wxString
1645 wxFileSelector(const wxChar *title,
1646 const wxChar *defaultDir,
1647 const wxChar *defaultFileName,
1648 const wxChar *defaultExtension,
1649 const wxChar *filter,
1650 int flags,
1651 wxWindow *parent,
1652 int x,
1653 int y)
1654 {
1655 return DoSelectFile(title,
1656 defaultDir,
1657 defaultFileName,
1658 defaultExtension,
1659 NULL, // not interested in filter index
1660 filter,
1661 flags,
1662 parent,
1663 x,
1664 y);
1665 }
1666
1667 static wxString GetWildcardString(const wxChar *ext)
1668 {
1669 wxString wild;
1670 if ( ext )
1671 {
1672 if ( *ext == wxT('.') )
1673 ext++;
1674
1675 wild << _T("*.") << ext;
1676 }
1677 else // no extension specified
1678 {
1679 wild = wxFileSelectorDefaultWildcardStr;
1680 }
1681
1682 return wild;
1683 }
1684
1685 wxString wxLoadFileSelector(const wxChar *what,
1686 const wxChar *ext,
1687 const wxChar *nameDef,
1688 wxWindow *parent)
1689 {
1690 wxString prompt;
1691 if ( what && *what )
1692 prompt = wxString::Format(_("Load %s file"), what);
1693 else
1694 prompt = _("Load file");
1695
1696 return wxFileSelector(prompt, NULL, nameDef, ext,
1697 GetWildcardString(ext), 0, parent);
1698 }
1699
1700 wxString wxSaveFileSelector(const wxChar *what,
1701 const wxChar *ext,
1702 const wxChar *nameDef,
1703 wxWindow *parent)
1704 {
1705 wxString prompt;
1706 if ( what && *what )
1707 prompt = wxString::Format(_("Save %s file"), what);
1708 else
1709 prompt = _("Save file");
1710
1711 return wxFileSelector(prompt, NULL, nameDef, ext,
1712 GetWildcardString(ext), 0, parent);
1713 }
1714
1715 // A module to allow icons table cleanup
1716
1717 class wxFileDialogGenericModule: public wxModule
1718 {
1719 DECLARE_DYNAMIC_CLASS(wxFileDialogGenericModule)
1720 public:
1721 wxFileDialogGenericModule() {}
1722 bool OnInit() { return TRUE; }
1723 void OnExit() { if (g_IconsTable) {delete g_IconsTable; g_IconsTable = NULL;} }
1724 };
1725
1726 IMPLEMENT_DYNAMIC_CLASS(wxFileDialogGenericModule, wxModule)
1727
1728 #endif // USE_GENERIC_FILEDIALOG
1729
1730 #endif // wxUSE_FILEDLG
1731