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