]> git.saurik.com Git - wxWidgets.git/blob - src/generic/dirctrlg.cpp
Disable wxUSE_ENH_METAFILE for wxGTK builds.
[wxWidgets.git] / src / generic / dirctrlg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/dirctrlg.cpp
3 // Purpose: wxGenericDirCtrl
4 // Author: Harm van der Heijden, Robert Roebling, Julian Smart
5 // Modified by:
6 // Created: 12/12/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Harm van der Heijden, Robert Roebling and Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_DIRDLG || wxUSE_FILEDLG
20
21 #include "wx/generic/dirctrlg.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/hash.h"
25 #include "wx/intl.h"
26 #include "wx/log.h"
27 #include "wx/utils.h"
28 #include "wx/button.h"
29 #include "wx/icon.h"
30 #include "wx/settings.h"
31 #include "wx/msgdlg.h"
32 #include "wx/choice.h"
33 #include "wx/textctrl.h"
34 #include "wx/layout.h"
35 #include "wx/sizer.h"
36 #include "wx/textdlg.h"
37 #include "wx/gdicmn.h"
38 #include "wx/image.h"
39 #include "wx/module.h"
40 #endif
41
42 #include "wx/filename.h"
43 #include "wx/filefn.h"
44 #include "wx/imaglist.h"
45 #include "wx/tokenzr.h"
46 #include "wx/dir.h"
47 #include "wx/artprov.h"
48 #include "wx/mimetype.h"
49
50 #if wxUSE_STATLINE
51 #include "wx/statline.h"
52 #endif
53
54 #if defined(__WXMAC__)
55 #include "wx/osx/private.h" // includes mac headers
56 #endif
57
58 #ifdef __WINDOWS__
59 #include <windows.h>
60 #include "wx/msw/winundef.h"
61 #include "wx/volume.h"
62
63 // FIXME - Mingw32 1.0 has both _getdrive() and _chdrive(). For now, let's assume
64 // older releases don't, but it should be verified and the checks modified
65 // accordingly.
66 #if !defined(__GNUWIN32__) || (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
67 #if !defined(__WXWINCE__)
68 #include <direct.h>
69 #endif
70 #include <stdlib.h>
71 #include <ctype.h>
72 #endif
73
74 #endif // __WINDOWS__
75
76 #if defined(__OS2__) || defined(__DOS__)
77 #ifdef __OS2__
78 #define INCL_BASE
79 #include <os2.h>
80 #ifndef __EMX__
81 #include <direct.h>
82 #endif
83 #include <stdlib.h>
84 #include <ctype.h>
85 #endif
86 #endif // __OS2__
87
88 #if defined(__WXMAC__)
89 // #include "MoreFilesX.h"
90 #endif
91
92 #ifdef __BORLANDC__
93 #include "dos.h"
94 #endif
95
96 extern WXDLLEXPORT_DATA(const char) wxFileSelectorDefaultWildcardStr[];
97
98 // If compiled under Windows, this macro can cause problems
99 #ifdef GetFirstChild
100 #undef GetFirstChild
101 #endif
102
103 bool wxIsDriveAvailable(const wxString& dirName);
104
105 // ----------------------------------------------------------------------------
106 // events
107 // ----------------------------------------------------------------------------
108
109 wxDEFINE_EVENT( wxEVT_DIRCTRL_SELECTIONCHANGED, wxTreeEvent );
110 wxDEFINE_EVENT( wxEVT_DIRCTRL_FILEACTIVATED, wxTreeEvent );
111
112 // ----------------------------------------------------------------------------
113 // wxGetAvailableDrives, for WINDOWS, DOS, OS2, MAC, UNIX (returns "/")
114 // ----------------------------------------------------------------------------
115
116 size_t wxGetAvailableDrives(wxArrayString &paths, wxArrayString &names, wxArrayInt &icon_ids)
117 {
118 #ifdef wxHAS_FILESYSTEM_VOLUMES
119
120 #ifdef __WXWINCE__
121 // No logical drives; return "\"
122 paths.Add(wxT("\\"));
123 names.Add(wxT("\\"));
124 icon_ids.Add(wxFileIconsTable::computer);
125 #elif defined(__WIN32__) && wxUSE_FSVOLUME
126 // TODO: this code (using wxFSVolumeBase) should be used for all platforms
127 // but unfortunately wxFSVolumeBase is not implemented everywhere
128 const wxArrayString as = wxFSVolumeBase::GetVolumes();
129
130 for (size_t i = 0; i < as.GetCount(); i++)
131 {
132 wxString path = as[i];
133 wxFSVolume vol(path);
134 int imageId;
135 switch (vol.GetKind())
136 {
137 case wxFS_VOL_FLOPPY:
138 if ( (path == wxT("a:\\")) || (path == wxT("b:\\")) )
139 imageId = wxFileIconsTable::floppy;
140 else
141 imageId = wxFileIconsTable::removeable;
142 break;
143 case wxFS_VOL_DVDROM:
144 case wxFS_VOL_CDROM:
145 imageId = wxFileIconsTable::cdrom;
146 break;
147 case wxFS_VOL_NETWORK:
148 if (path[0] == wxT('\\'))
149 continue; // skip "\\computer\folder"
150 imageId = wxFileIconsTable::drive;
151 break;
152 case wxFS_VOL_DISK:
153 case wxFS_VOL_OTHER:
154 default:
155 imageId = wxFileIconsTable::drive;
156 break;
157 }
158 paths.Add(path);
159 names.Add(vol.GetDisplayName());
160 icon_ids.Add(imageId);
161 }
162 #elif defined(__OS2__)
163 APIRET rc;
164 ULONG ulDriveNum = 0;
165 ULONG ulDriveMap = 0;
166 rc = ::DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap);
167 if ( rc == 0)
168 {
169 size_t i = 0;
170 while (i < 26)
171 {
172 if (ulDriveMap & ( 1 << i ))
173 {
174 const wxString path = wxFileName::GetVolumeString(
175 'A' + i, wxPATH_GET_SEPARATOR);
176 const wxString name = wxFileName::GetVolumeString(
177 'A' + i, wxPATH_NO_SEPARATOR);
178
179 // Note: If _filesys is unsupported by some compilers,
180 // we can always replace it by DosQueryFSAttach
181 char filesysname[20];
182 #ifdef __WATCOMC__
183 ULONG cbBuffer = sizeof(filesysname);
184 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)filesysname;
185 APIRET rc = ::DosQueryFSAttach(name.fn_str(),0,FSAIL_QUERYNAME,pfsqBuffer,&cbBuffer);
186 if (rc != NO_ERROR)
187 {
188 filesysname[0] = '\0';
189 }
190 #else
191 _filesys(name.fn_str(), filesysname, sizeof(filesysname));
192 #endif
193 /* FAT, LAN, HPFS, CDFS, NFS */
194 int imageId;
195 if (path == wxT("A:\\") || path == wxT("B:\\"))
196 imageId = wxFileIconsTable::floppy;
197 else if (!strcmp(filesysname, "CDFS"))
198 imageId = wxFileIconsTable::cdrom;
199 else if (!strcmp(filesysname, "LAN") ||
200 !strcmp(filesysname, "NFS"))
201 imageId = wxFileIconsTable::drive;
202 else
203 imageId = wxFileIconsTable::drive;
204 paths.Add(path);
205 names.Add(name);
206 icon_ids.Add(imageId);
207 }
208 i ++;
209 }
210 }
211 #else // !__WIN32__, !__OS2__
212 /* If we can switch to the drive, it exists. */
213 for ( char drive = 'A'; drive <= 'Z'; drive++ )
214 {
215 const wxString
216 path = wxFileName::GetVolumeString(drive, wxPATH_GET_SEPARATOR);
217
218 if (wxIsDriveAvailable(path))
219 {
220 paths.Add(path);
221 names.Add(wxFileName::GetVolumeString(drive, wxPATH_NO_SEPARATOR));
222 icon_ids.Add(drive <= 2 ? wxFileIconsTable::floppy
223 : wxFileIconsTable::drive);
224 }
225 }
226 #endif // __WIN32__/!__WIN32__
227
228 #elif defined(__WXMAC__) && wxOSX_USE_COCOA_OR_CARBON
229
230 ItemCount volumeIndex = 1;
231 OSErr err = noErr ;
232
233 while( noErr == err )
234 {
235 HFSUniStr255 volumeName ;
236 FSRef fsRef ;
237 FSVolumeInfo volumeInfo ;
238 err = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoFlags , &volumeInfo , &volumeName, &fsRef);
239 if( noErr == err )
240 {
241 wxString path = wxMacFSRefToPath( &fsRef ) ;
242 wxString name = wxMacHFSUniStrToString( &volumeName ) ;
243
244 if ( (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) || (volumeInfo.flags & kFSVolFlagHardwareLockedMask) )
245 {
246 icon_ids.Add(wxFileIconsTable::cdrom);
247 }
248 else
249 {
250 icon_ids.Add(wxFileIconsTable::drive);
251 }
252 // todo other removable
253
254 paths.Add(path);
255 names.Add(name);
256 volumeIndex++ ;
257 }
258 }
259
260 #elif defined(__UNIX__)
261 paths.Add(wxT("/"));
262 names.Add(wxT("/"));
263 icon_ids.Add(wxFileIconsTable::computer);
264 #else
265 #error "Unsupported platform in wxGenericDirCtrl!"
266 #endif
267 wxASSERT_MSG( (paths.GetCount() == names.GetCount()), wxT("The number of paths and their human readable names should be equal in number."));
268 wxASSERT_MSG( (paths.GetCount() == icon_ids.GetCount()), wxT("Wrong number of icons for available drives."));
269 return paths.GetCount();
270 }
271
272 // ----------------------------------------------------------------------------
273 // wxIsDriveAvailable
274 // ----------------------------------------------------------------------------
275
276 #if defined(__DOS__)
277
278 bool wxIsDriveAvailable(const wxString& dirName)
279 {
280 // FIXME: this method leads to hang up under Watcom for some reason
281 #ifdef __WATCOMC__
282 wxUnusedVar(dirName);
283 #else
284 if ( dirName.length() == 3 && dirName[1u] == wxT(':') )
285 {
286 wxString dirNameLower(dirName.Lower());
287 // VS: always return true for removable media, since Win95 doesn't
288 // like it when MS-DOS app accesses empty floppy drive
289 return (dirNameLower[0u] == wxT('a') ||
290 dirNameLower[0u] == wxT('b') ||
291 wxDirExists(dirNameLower));
292 }
293 else
294 #endif
295 return true;
296 }
297
298 #elif defined(__WINDOWS__) || defined(__OS2__)
299
300 int setdrive(int WXUNUSED_IN_WINCE(drive))
301 {
302 #ifdef __WXWINCE__
303 return 0;
304 #elif defined(__GNUWIN32__) && \
305 (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
306 return _chdrive(drive);
307 #else
308 wxChar newdrive[4];
309
310 if (drive < 1 || drive > 31)
311 return -1;
312 newdrive[0] = (wxChar)(wxT('A') + drive - 1);
313 newdrive[1] = wxT(':');
314 #ifdef __OS2__
315 newdrive[2] = wxT('\\');
316 newdrive[3] = wxT('\0');
317 #else
318 newdrive[2] = wxT('\0');
319 #endif
320 #if defined(__WINDOWS__)
321 if (::SetCurrentDirectory(newdrive))
322 #else
323 // VA doesn't know what LPSTR is and has its own set
324 if (!DosSetCurrentDir((PSZ)newdrive))
325 #endif
326 return 0;
327 else
328 return -1;
329 #endif // !GNUWIN32
330 }
331
332 bool wxIsDriveAvailable(const wxString& WXUNUSED_IN_WINCE(dirName))
333 {
334 #ifdef __WXWINCE__
335 return false;
336 #else
337 #ifdef __WIN32__
338 UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
339 #endif
340 bool success = true;
341
342 // Check if this is a root directory and if so,
343 // whether the drive is available.
344 if (dirName.length() == 3 && dirName[(size_t)1] == wxT(':'))
345 {
346 wxString dirNameLower(dirName.Lower());
347 #if defined(__GNUWIN32__) && !(defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
348 success = wxDirExists(dirNameLower);
349 #else
350 #if defined(__OS2__)
351 // Avoid changing to drive since no media may be inserted.
352 if (dirNameLower[(size_t)0] == 'a' || dirNameLower[(size_t)0] == 'b')
353 return success;
354 #endif
355 int currentDrive = _getdrive();
356 int thisDrive = (int) (dirNameLower[(size_t)0] - 'a' + 1) ;
357 int err = setdrive( thisDrive ) ;
358 setdrive( currentDrive );
359
360 if (err == -1)
361 {
362 success = false;
363 }
364 #endif
365 }
366 #ifdef __WIN32__
367 (void) SetErrorMode(errorMode);
368 #endif
369
370 return success;
371 #endif
372 }
373 #endif // __WINDOWS__ || __OS2__
374
375 #endif // wxUSE_DIRDLG || wxUSE_FILEDLG
376
377
378
379 #if wxUSE_DIRDLG
380
381 // Function which is called by quick sort. We want to override the default wxArrayString behaviour,
382 // and sort regardless of case.
383 static int wxCMPFUNC_CONV wxDirCtrlStringCompareFunction(const wxString& strFirst, const wxString& strSecond)
384 {
385 return strFirst.CmpNoCase(strSecond);
386 }
387
388 //-----------------------------------------------------------------------------
389 // wxDirItemData
390 //-----------------------------------------------------------------------------
391
392 wxDirItemData::wxDirItemData(const wxString& path, const wxString& name,
393 bool isDir)
394 {
395 m_path = path;
396 m_name = name;
397 /* Insert logic to detect hidden files here
398 * In UnixLand we just check whether the first char is a dot
399 * For FileNameFromPath read LastDirNameInThisPath ;-) */
400 // m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.');
401 m_isHidden = false;
402 m_isExpanded = false;
403 m_isDir = isDir;
404 }
405
406 void wxDirItemData::SetNewDirName(const wxString& path)
407 {
408 m_path = path;
409 m_name = wxFileNameFromPath(path);
410 }
411
412 bool wxDirItemData::HasSubDirs() const
413 {
414 if (m_path.empty())
415 return false;
416
417 wxDir dir;
418 {
419 wxLogNull nolog;
420 if ( !dir.Open(m_path) )
421 return false;
422 }
423
424 return dir.HasSubDirs();
425 }
426
427 bool wxDirItemData::HasFiles(const wxString& WXUNUSED(spec)) const
428 {
429 if (m_path.empty())
430 return false;
431
432 wxDir dir;
433 {
434 wxLogNull nolog;
435 if ( !dir.Open(m_path) )
436 return false;
437 }
438
439 return dir.HasFiles();
440 }
441
442 //-----------------------------------------------------------------------------
443 // wxGenericDirCtrl
444 //-----------------------------------------------------------------------------
445
446 BEGIN_EVENT_TABLE(wxGenericDirCtrl, wxControl)
447 EVT_TREE_ITEM_EXPANDING (wxID_TREECTRL, wxGenericDirCtrl::OnExpandItem)
448 EVT_TREE_ITEM_COLLAPSED (wxID_TREECTRL, wxGenericDirCtrl::OnCollapseItem)
449 EVT_TREE_BEGIN_LABEL_EDIT (wxID_TREECTRL, wxGenericDirCtrl::OnBeginEditItem)
450 EVT_TREE_END_LABEL_EDIT (wxID_TREECTRL, wxGenericDirCtrl::OnEndEditItem)
451 EVT_TREE_SEL_CHANGED (wxID_TREECTRL, wxGenericDirCtrl::OnTreeSelChange)
452 EVT_TREE_ITEM_ACTIVATED (wxID_TREECTRL, wxGenericDirCtrl::OnItemActivated)
453 EVT_SIZE (wxGenericDirCtrl::OnSize)
454 END_EVENT_TABLE()
455
456 wxGenericDirCtrl::wxGenericDirCtrl(void)
457 {
458 Init();
459 }
460
461 void wxGenericDirCtrl::ExpandRoot()
462 {
463 ExpandDir(m_rootId); // automatically expand first level
464
465 // Expand and select the default path
466 if (!m_defaultPath.empty())
467 {
468 ExpandPath(m_defaultPath);
469 }
470 #ifdef __UNIX__
471 else
472 {
473 // On Unix, there's only one node under the (hidden) root node. It
474 // represents the / path, so the user would always have to expand it;
475 // let's do it ourselves
476 ExpandPath( wxT("/") );
477 }
478 #endif
479 }
480
481 bool wxGenericDirCtrl::Create(wxWindow *parent,
482 const wxWindowID treeid,
483 const wxString& dir,
484 const wxPoint& pos,
485 const wxSize& size,
486 long style,
487 const wxString& filter,
488 int defaultFilter,
489 const wxString& name)
490 {
491 if (!wxControl::Create(parent, treeid, pos, size, style, wxDefaultValidator, name))
492 return false;
493
494 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
495 SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
496
497 Init();
498
499 long treeStyle = wxTR_HAS_BUTTONS;
500
501 // On Windows CE, if you hide the root, you get a crash when
502 // attempting to access data for children of the root item.
503 #ifndef __WXWINCE__
504 treeStyle |= wxTR_HIDE_ROOT;
505 #endif
506
507 #ifdef __WXGTK20__
508 treeStyle |= wxTR_NO_LINES;
509 #endif
510
511 if (style & wxDIRCTRL_EDIT_LABELS)
512 treeStyle |= wxTR_EDIT_LABELS;
513
514 if (style & wxDIRCTRL_MULTIPLE)
515 treeStyle |= wxTR_MULTIPLE;
516
517 if ((style & wxDIRCTRL_3D_INTERNAL) == 0)
518 treeStyle |= wxNO_BORDER;
519
520 m_treeCtrl = CreateTreeCtrl(this, wxID_TREECTRL,
521 wxPoint(0,0), GetClientSize(), treeStyle);
522
523 if (!filter.empty() && (style & wxDIRCTRL_SHOW_FILTERS))
524 m_filterListCtrl = new wxDirFilterListCtrl(this, wxID_FILTERLISTCTRL);
525
526 m_defaultPath = dir;
527 m_filter = filter;
528
529 if (m_filter.empty())
530 m_filter = wxFileSelectorDefaultWildcardStr;
531
532 SetFilterIndex(defaultFilter);
533
534 if (m_filterListCtrl)
535 m_filterListCtrl->FillFilterList(filter, defaultFilter);
536
537 m_treeCtrl->SetImageList(wxTheFileIconsTable->GetSmallImageList());
538
539 m_showHidden = false;
540 wxDirItemData* rootData = new wxDirItemData(wxEmptyString, wxEmptyString, true);
541
542 wxString rootName;
543
544 #if defined(__WINDOWS__) || defined(__OS2__) || defined(__DOS__)
545 rootName = _("Computer");
546 #else
547 rootName = _("Sections");
548 #endif
549
550 m_rootId = m_treeCtrl->AddRoot( rootName, 3, -1, rootData);
551 m_treeCtrl->SetItemHasChildren(m_rootId);
552
553 ExpandRoot();
554
555 SetInitialSize(size);
556 DoResize();
557
558 return true;
559 }
560
561 wxGenericDirCtrl::~wxGenericDirCtrl()
562 {
563 }
564
565 void wxGenericDirCtrl::Init()
566 {
567 m_showHidden = false;
568 m_currentFilter = 0;
569 m_currentFilterStr = wxEmptyString; // Default: any file
570 m_treeCtrl = NULL;
571 m_filterListCtrl = NULL;
572 }
573
574 wxTreeCtrl* wxGenericDirCtrl::CreateTreeCtrl(wxWindow *parent, wxWindowID treeid, const wxPoint& pos, const wxSize& size, long treeStyle)
575 {
576 return new wxTreeCtrl(parent, treeid, pos, size, treeStyle);
577 }
578
579 void wxGenericDirCtrl::ShowHidden( bool show )
580 {
581 if ( m_showHidden == show )
582 return;
583
584 m_showHidden = show;
585
586 if ( HasFlag(wxDIRCTRL_MULTIPLE) )
587 {
588 wxArrayString paths;
589 GetPaths(paths);
590 ReCreateTree();
591 for ( unsigned n = 0; n < paths.size(); n++ )
592 {
593 ExpandPath(paths[n]);
594 }
595 }
596 else
597 {
598 wxString path = GetPath();
599 ReCreateTree();
600 SetPath(path);
601 }
602 }
603
604 const wxTreeItemId
605 wxGenericDirCtrl::AddSection(const wxString& path, const wxString& name, int imageId)
606 {
607 wxDirItemData *dir_item = new wxDirItemData(path,name,true);
608
609 wxTreeItemId treeid = AppendItem( m_rootId, name, imageId, -1, dir_item);
610
611 m_treeCtrl->SetItemHasChildren(treeid);
612
613 return treeid;
614 }
615
616 void wxGenericDirCtrl::SetupSections()
617 {
618 wxArrayString paths, names;
619 wxArrayInt icons;
620
621 size_t n, count = wxGetAvailableDrives(paths, names, icons);
622
623 #ifdef __WXGTK20__
624 wxString home = wxGetHomeDir();
625 AddSection( home, _("Home directory"), 1);
626 home += wxT("/Desktop");
627 AddSection( home, _("Desktop"), 1);
628 #endif
629
630 for (n = 0; n < count; n++)
631 AddSection(paths[n], names[n], icons[n]);
632 }
633
634 void wxGenericDirCtrl::SetFocus()
635 {
636 // we don't need focus ourselves, give it to the tree so that the user
637 // could navigate it
638 if (m_treeCtrl)
639 m_treeCtrl->SetFocus();
640 }
641
642 void wxGenericDirCtrl::OnBeginEditItem(wxTreeEvent &event)
643 {
644 // don't rename the main entry "Sections"
645 if (event.GetItem() == m_rootId)
646 {
647 event.Veto();
648 return;
649 }
650
651 // don't rename the individual sections
652 if (m_treeCtrl->GetItemParent( event.GetItem() ) == m_rootId)
653 {
654 event.Veto();
655 return;
656 }
657 }
658
659 void wxGenericDirCtrl::OnEndEditItem(wxTreeEvent &event)
660 {
661 if (event.IsEditCancelled())
662 return;
663
664 if ((event.GetLabel().empty()) ||
665 (event.GetLabel() == wxT(".")) ||
666 (event.GetLabel() == wxT("..")) ||
667 (event.GetLabel().Find(wxT('/')) != wxNOT_FOUND) ||
668 (event.GetLabel().Find(wxT('\\')) != wxNOT_FOUND) ||
669 (event.GetLabel().Find(wxT('|')) != wxNOT_FOUND))
670 {
671 wxMessageDialog dialog(this, _("Illegal directory name."), _("Error"), wxOK | wxICON_ERROR );
672 dialog.ShowModal();
673 event.Veto();
674 return;
675 }
676
677 wxTreeItemId treeid = event.GetItem();
678 wxDirItemData *data = GetItemData( treeid );
679 wxASSERT( data );
680
681 wxString new_name( wxPathOnly( data->m_path ) );
682 new_name += wxString(wxFILE_SEP_PATH);
683 new_name += event.GetLabel();
684
685 wxLogNull log;
686
687 if (wxFileExists(new_name))
688 {
689 wxMessageDialog dialog(this, _("File name exists already."), _("Error"), wxOK | wxICON_ERROR );
690 dialog.ShowModal();
691 event.Veto();
692 }
693
694 if (wxRenameFile(data->m_path,new_name))
695 {
696 data->SetNewDirName( new_name );
697 }
698 else
699 {
700 wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
701 dialog.ShowModal();
702 event.Veto();
703 }
704 }
705
706 void wxGenericDirCtrl::OnTreeSelChange(wxTreeEvent &event)
707 {
708 wxTreeEvent changedEvent(wxEVT_DIRCTRL_SELECTIONCHANGED, GetId());
709
710 changedEvent.SetEventObject(this);
711 changedEvent.SetItem(event.GetItem());
712 changedEvent.SetClientObject(m_treeCtrl->GetItemData(event.GetItem()));
713
714 if (GetEventHandler()->SafelyProcessEvent(changedEvent) && !changedEvent.IsAllowed())
715 event.Veto();
716 else
717 event.Skip();
718 }
719
720 void wxGenericDirCtrl::OnItemActivated(wxTreeEvent &event)
721 {
722 wxTreeItemId treeid = event.GetItem();
723 const wxDirItemData *data = GetItemData(treeid);
724
725 if (data->m_isDir)
726 {
727 // is dir
728 event.Skip();
729 }
730 else
731 {
732 // is file
733 wxTreeEvent changedEvent(wxEVT_DIRCTRL_FILEACTIVATED, GetId());
734
735 changedEvent.SetEventObject(this);
736 changedEvent.SetItem(treeid);
737 changedEvent.SetClientObject(m_treeCtrl->GetItemData(treeid));
738
739 if (GetEventHandler()->SafelyProcessEvent(changedEvent) && !changedEvent.IsAllowed())
740 event.Veto();
741 else
742 event.Skip();
743 }
744 }
745
746 void wxGenericDirCtrl::OnExpandItem(wxTreeEvent &event)
747 {
748 wxTreeItemId parentId = event.GetItem();
749
750 // VS: this is needed because the event handler is called from wxTreeCtrl
751 // ctor when wxTR_HIDE_ROOT was specified
752
753 if (!m_rootId.IsOk())
754 m_rootId = m_treeCtrl->GetRootItem();
755
756 ExpandDir(parentId);
757 }
758
759 void wxGenericDirCtrl::OnCollapseItem(wxTreeEvent &event )
760 {
761 CollapseDir(event.GetItem());
762 }
763
764 void wxGenericDirCtrl::CollapseDir(wxTreeItemId parentId)
765 {
766 wxTreeItemId child;
767
768 wxDirItemData *data = GetItemData(parentId);
769 if (!data->m_isExpanded)
770 return;
771
772 data->m_isExpanded = false;
773
774 m_treeCtrl->Freeze();
775 if (parentId != m_treeCtrl->GetRootItem())
776 m_treeCtrl->CollapseAndReset(parentId);
777 m_treeCtrl->DeleteChildren(parentId);
778 m_treeCtrl->Thaw();
779 }
780
781 void wxGenericDirCtrl::PopulateNode(wxTreeItemId parentId)
782 {
783 wxDirItemData *data = GetItemData(parentId);
784
785 if (data->m_isExpanded)
786 return;
787
788 data->m_isExpanded = true;
789
790 if (parentId == m_treeCtrl->GetRootItem())
791 {
792 SetupSections();
793 return;
794 }
795
796 wxASSERT(data);
797
798 wxString search,path,filename;
799
800 wxString dirName(data->m_path);
801
802 #if (defined(__WINDOWS__) && !defined(__WXWINCE__)) || defined(__DOS__) || defined(__OS2__)
803 // Check if this is a root directory and if so,
804 // whether the drive is avaiable.
805 if (!wxIsDriveAvailable(dirName))
806 {
807 data->m_isExpanded = false;
808 //wxMessageBox(wxT("Sorry, this drive is not available."));
809 return;
810 }
811 #endif
812
813 // This may take a longish time. Go to busy cursor
814 wxBusyCursor busy;
815
816 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)
817 if (dirName.Last() == ':')
818 dirName += wxString(wxFILE_SEP_PATH);
819 #endif
820
821 wxArrayString dirs;
822 wxArrayString filenames;
823
824 wxDir d;
825 wxString eachFilename;
826
827 wxLogNull log;
828 d.Open(dirName);
829
830 if (d.IsOpened())
831 {
832 int style = wxDIR_DIRS;
833 if (m_showHidden) style |= wxDIR_HIDDEN;
834 if (d.GetFirst(& eachFilename, wxEmptyString, style))
835 {
836 do
837 {
838 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
839 {
840 dirs.Add(eachFilename);
841 }
842 }
843 while (d.GetNext(&eachFilename));
844 }
845 }
846 dirs.Sort(wxDirCtrlStringCompareFunction);
847
848 // Now do the filenames -- but only if we're allowed to
849 if (!HasFlag(wxDIRCTRL_DIR_ONLY))
850 {
851 d.Open(dirName);
852
853 if (d.IsOpened())
854 {
855 int style = wxDIR_FILES;
856 if (m_showHidden) style |= wxDIR_HIDDEN;
857 // Process each filter (ex: "JPEG Files (*.jpg;*.jpeg)|*.jpg;*.jpeg")
858 wxStringTokenizer strTok;
859 wxString curFilter;
860 strTok.SetString(m_currentFilterStr,wxT(";"));
861 while(strTok.HasMoreTokens())
862 {
863 curFilter = strTok.GetNextToken();
864 if (d.GetFirst(& eachFilename, curFilter, style))
865 {
866 do
867 {
868 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
869 {
870 filenames.Add(eachFilename);
871 }
872 }
873 while (d.GetNext(& eachFilename));
874 }
875 }
876 }
877 filenames.Sort(wxDirCtrlStringCompareFunction);
878 }
879
880 // Now we really know whether we have any children so tell the tree control
881 // about it.
882 m_treeCtrl->SetItemHasChildren(parentId, !dirs.empty() || !filenames.empty());
883
884 // Add the sorted dirs
885 size_t i;
886 for (i = 0; i < dirs.GetCount(); i++)
887 {
888 eachFilename = dirs[i];
889 path = dirName;
890 if (!wxEndsWithPathSeparator(path))
891 path += wxString(wxFILE_SEP_PATH);
892 path += eachFilename;
893
894 wxDirItemData *dir_item = new wxDirItemData(path,eachFilename,true);
895 wxTreeItemId treeid = AppendItem( parentId, eachFilename,
896 wxFileIconsTable::folder, -1, dir_item);
897 m_treeCtrl->SetItemImage( treeid, wxFileIconsTable::folder_open,
898 wxTreeItemIcon_Expanded );
899
900 // assume that it does have children by default as it can take a long
901 // time to really check for this (think remote drives...)
902 //
903 // and if we're wrong, we'll correct the icon later if
904 // the user really tries to open this item
905 m_treeCtrl->SetItemHasChildren(treeid);
906 }
907
908 // Add the sorted filenames
909 if (!HasFlag(wxDIRCTRL_DIR_ONLY))
910 {
911 for (i = 0; i < filenames.GetCount(); i++)
912 {
913 eachFilename = filenames[i];
914 path = dirName;
915 if (!wxEndsWithPathSeparator(path))
916 path += wxString(wxFILE_SEP_PATH);
917 path += eachFilename;
918 //path = dirName + wxString(wxT("/")) + eachFilename;
919 wxDirItemData *dir_item = new wxDirItemData(path,eachFilename,false);
920 int image_id = wxFileIconsTable::file;
921 if (eachFilename.Find(wxT('.')) != wxNOT_FOUND)
922 image_id = wxTheFileIconsTable->GetIconID(eachFilename.AfterLast(wxT('.')));
923 (void) AppendItem( parentId, eachFilename, image_id, -1, dir_item);
924 }
925 }
926 }
927
928 void wxGenericDirCtrl::ExpandDir(wxTreeItemId parentId)
929 {
930 // ExpandDir() will not actually expand the tree node, just populate it
931 PopulateNode(parentId);
932 }
933
934 void wxGenericDirCtrl::ReCreateTree()
935 {
936 CollapseDir(m_treeCtrl->GetRootItem());
937 ExpandRoot();
938 }
939
940 void wxGenericDirCtrl::CollapseTree()
941 {
942 wxTreeItemIdValue cookie;
943 wxTreeItemId child = m_treeCtrl->GetFirstChild(m_rootId, cookie);
944 while (child.IsOk())
945 {
946 CollapseDir(child);
947 child = m_treeCtrl->GetNextChild(m_rootId, cookie);
948 }
949 }
950
951 // Find the child that matches the first part of 'path'.
952 // E.g. if a child path is "/usr" and 'path' is "/usr/include"
953 // then the child for /usr is returned.
954 wxTreeItemId wxGenericDirCtrl::FindChild(wxTreeItemId parentId, const wxString& path, bool& done)
955 {
956 wxString path2(path);
957
958 // Make sure all separators are as per the current platform
959 path2.Replace(wxT("\\"), wxString(wxFILE_SEP_PATH));
960 path2.Replace(wxT("/"), wxString(wxFILE_SEP_PATH));
961
962 // Append a separator to foil bogus substring matching
963 path2 += wxString(wxFILE_SEP_PATH);
964
965 // In MSW or PM, case is not significant
966 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)
967 path2.MakeLower();
968 #endif
969
970 wxTreeItemIdValue cookie;
971 wxTreeItemId childId = m_treeCtrl->GetFirstChild(parentId, cookie);
972 while (childId.IsOk())
973 {
974 wxDirItemData* data = GetItemData(childId);
975
976 if (data && !data->m_path.empty())
977 {
978 wxString childPath(data->m_path);
979 if (!wxEndsWithPathSeparator(childPath))
980 childPath += wxString(wxFILE_SEP_PATH);
981
982 // In MSW and PM, case is not significant
983 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)
984 childPath.MakeLower();
985 #endif
986
987 if (childPath.length() <= path2.length())
988 {
989 wxString path3 = path2.Mid(0, childPath.length());
990 if (childPath == path3)
991 {
992 if (path3.length() == path2.length())
993 done = true;
994 else
995 done = false;
996 return childId;
997 }
998 }
999 }
1000
1001 childId = m_treeCtrl->GetNextChild(parentId, cookie);
1002 }
1003 wxTreeItemId invalid;
1004 return invalid;
1005 }
1006
1007 // Try to expand as much of the given path as possible,
1008 // and select the given tree item.
1009 bool wxGenericDirCtrl::ExpandPath(const wxString& path)
1010 {
1011 bool done = false;
1012 wxTreeItemId treeid = FindChild(m_rootId, path, done);
1013 wxTreeItemId lastId = treeid; // The last non-zero treeid
1014 while (treeid.IsOk() && !done)
1015 {
1016 ExpandDir(treeid);
1017
1018 treeid = FindChild(treeid, path, done);
1019 if (treeid.IsOk())
1020 lastId = treeid;
1021 }
1022 if (!lastId.IsOk())
1023 return false;
1024
1025 wxDirItemData *data = GetItemData(lastId);
1026 if (data->m_isDir)
1027 {
1028 m_treeCtrl->Expand(lastId);
1029 }
1030 if (HasFlag(wxDIRCTRL_SELECT_FIRST) && data->m_isDir)
1031 {
1032 // Find the first file in this directory
1033 wxTreeItemIdValue cookie;
1034 wxTreeItemId childId = m_treeCtrl->GetFirstChild(lastId, cookie);
1035 bool selectedChild = false;
1036 while (childId.IsOk())
1037 {
1038 data = GetItemData(childId);
1039
1040 if (data && data->m_path != wxEmptyString && !data->m_isDir)
1041 {
1042 m_treeCtrl->SelectItem(childId);
1043 m_treeCtrl->EnsureVisible(childId);
1044 selectedChild = true;
1045 break;
1046 }
1047 childId = m_treeCtrl->GetNextChild(lastId, cookie);
1048 }
1049 if (!selectedChild)
1050 {
1051 m_treeCtrl->SelectItem(lastId);
1052 m_treeCtrl->EnsureVisible(lastId);
1053 }
1054 }
1055 else
1056 {
1057 m_treeCtrl->SelectItem(lastId);
1058 m_treeCtrl->EnsureVisible(lastId);
1059 }
1060
1061 return true;
1062 }
1063
1064
1065 bool wxGenericDirCtrl::CollapsePath(const wxString& path)
1066 {
1067 bool done = false;
1068 wxTreeItemId treeid = FindChild(m_rootId, path, done);
1069 wxTreeItemId lastId = treeid; // The last non-zero treeid
1070
1071 while ( treeid.IsOk() && !done )
1072 {
1073 CollapseDir(treeid);
1074
1075 treeid = FindChild(treeid, path, done);
1076
1077 if ( treeid.IsOk() )
1078 lastId = treeid;
1079 }
1080
1081 if ( !lastId.IsOk() )
1082 return false;
1083
1084 m_treeCtrl->SelectItem(lastId);
1085 m_treeCtrl->EnsureVisible(lastId);
1086
1087 return true;
1088 }
1089
1090 wxDirItemData* wxGenericDirCtrl::GetItemData(wxTreeItemId itemId)
1091 {
1092 return static_cast<wxDirItemData*>(m_treeCtrl->GetItemData(itemId));
1093 }
1094
1095 wxString wxGenericDirCtrl::GetPath(wxTreeItemId itemId) const
1096 {
1097 const wxDirItemData*
1098 data = static_cast<wxDirItemData*>(m_treeCtrl->GetItemData(itemId));
1099
1100 return data->m_path;
1101 }
1102
1103 wxString wxGenericDirCtrl::GetPath() const
1104 {
1105 // Allow calling GetPath() in multiple selection from OnSelFilter
1106 if (m_treeCtrl->HasFlag(wxTR_MULTIPLE))
1107 {
1108 wxArrayTreeItemIds items;
1109 m_treeCtrl->GetSelections(items);
1110 if (items.size() > 0)
1111 {
1112 // return first string only
1113 wxTreeItemId treeid = items[0];
1114 return GetPath(treeid);
1115 }
1116
1117 return wxEmptyString;
1118 }
1119
1120 wxTreeItemId treeid = m_treeCtrl->GetSelection();
1121 if (treeid)
1122 {
1123 return GetPath(treeid);
1124 }
1125 else
1126 return wxEmptyString;
1127 }
1128
1129 void wxGenericDirCtrl::GetPaths(wxArrayString& paths) const
1130 {
1131 paths.clear();
1132
1133 wxArrayTreeItemIds items;
1134 m_treeCtrl->GetSelections(items);
1135 for ( unsigned n = 0; n < items.size(); n++ )
1136 {
1137 wxTreeItemId treeid = items[n];
1138 paths.push_back(GetPath(treeid));
1139 }
1140 }
1141
1142 wxString wxGenericDirCtrl::GetFilePath() const
1143 {
1144 wxTreeItemId treeid = m_treeCtrl->GetSelection();
1145 if (treeid)
1146 {
1147 wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(treeid);
1148 if (data->m_isDir)
1149 return wxEmptyString;
1150 else
1151 return data->m_path;
1152 }
1153 else
1154 return wxEmptyString;
1155 }
1156
1157 void wxGenericDirCtrl::GetFilePaths(wxArrayString& paths) const
1158 {
1159 paths.clear();
1160
1161 wxArrayTreeItemIds items;
1162 m_treeCtrl->GetSelections(items);
1163 for ( unsigned n = 0; n < items.size(); n++ )
1164 {
1165 wxTreeItemId treeid = items[n];
1166 wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(treeid);
1167 if ( !data->m_isDir )
1168 paths.Add(data->m_path);
1169 }
1170 }
1171
1172 void wxGenericDirCtrl::SetPath(const wxString& path)
1173 {
1174 m_defaultPath = path;
1175 if (m_rootId)
1176 ExpandPath(path);
1177 }
1178
1179 void wxGenericDirCtrl::SelectPath(const wxString& path, bool select)
1180 {
1181 bool done = false;
1182 wxTreeItemId treeid = FindChild(m_rootId, path, done);
1183 wxTreeItemId lastId = treeid; // The last non-zero treeid
1184 while ( treeid.IsOk() && !done )
1185 {
1186 treeid = FindChild(treeid, path, done);
1187 if ( treeid.IsOk() )
1188 lastId = treeid;
1189 }
1190 if ( !lastId.IsOk() )
1191 return;
1192
1193 if ( done )
1194 {
1195 m_treeCtrl->SelectItem(treeid, select);
1196 }
1197 }
1198
1199 void wxGenericDirCtrl::SelectPaths(const wxArrayString& paths)
1200 {
1201 if ( HasFlag(wxDIRCTRL_MULTIPLE) )
1202 {
1203 UnselectAll();
1204 for ( unsigned n = 0; n < paths.size(); n++ )
1205 {
1206 SelectPath(paths[n]);
1207 }
1208 }
1209 }
1210
1211 void wxGenericDirCtrl::UnselectAll()
1212 {
1213 m_treeCtrl->UnselectAll();
1214 }
1215
1216 // Not used
1217 #if 0
1218 void wxGenericDirCtrl::FindChildFiles(wxTreeItemId treeid, int dirFlags, wxArrayString& filenames)
1219 {
1220 wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(treeid);
1221
1222 // This may take a longish time. Go to busy cursor
1223 wxBusyCursor busy;
1224
1225 wxASSERT(data);
1226
1227 wxString search,path,filename;
1228
1229 wxString dirName(data->m_path);
1230
1231 #if defined(__WINDOWS__) || defined(__OS2__)
1232 if (dirName.Last() == ':')
1233 dirName += wxString(wxFILE_SEP_PATH);
1234 #endif
1235
1236 wxDir d;
1237 wxString eachFilename;
1238
1239 wxLogNull log;
1240 d.Open(dirName);
1241
1242 if (d.IsOpened())
1243 {
1244 if (d.GetFirst(& eachFilename, m_currentFilterStr, dirFlags))
1245 {
1246 do
1247 {
1248 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
1249 {
1250 filenames.Add(eachFilename);
1251 }
1252 }
1253 while (d.GetNext(& eachFilename)) ;
1254 }
1255 }
1256 }
1257 #endif
1258
1259 void wxGenericDirCtrl::SetFilterIndex(int n)
1260 {
1261 m_currentFilter = n;
1262
1263 wxString f, d;
1264 if (ExtractWildcard(m_filter, n, f, d))
1265 m_currentFilterStr = f;
1266 else
1267 #ifdef __UNIX__
1268 m_currentFilterStr = wxT("*");
1269 #else
1270 m_currentFilterStr = wxT("*.*");
1271 #endif
1272 }
1273
1274 void wxGenericDirCtrl::SetFilter(const wxString& filter)
1275 {
1276 m_filter = filter;
1277
1278 if (!filter.empty() && !m_filterListCtrl && HasFlag(wxDIRCTRL_SHOW_FILTERS))
1279 m_filterListCtrl = new wxDirFilterListCtrl(this, wxID_FILTERLISTCTRL);
1280 else if (filter.empty() && m_filterListCtrl)
1281 {
1282 m_filterListCtrl->Destroy();
1283 m_filterListCtrl = NULL;
1284 }
1285
1286 wxString f, d;
1287 if (ExtractWildcard(m_filter, m_currentFilter, f, d))
1288 m_currentFilterStr = f;
1289 else
1290 #ifdef __UNIX__
1291 m_currentFilterStr = wxT("*");
1292 #else
1293 m_currentFilterStr = wxT("*.*");
1294 #endif
1295 // current filter index is meaningless after filter change, set it to zero
1296 SetFilterIndex(0);
1297 if (m_filterListCtrl)
1298 m_filterListCtrl->FillFilterList(m_filter, 0);
1299 }
1300
1301 // Extract description and actual filter from overall filter string
1302 bool wxGenericDirCtrl::ExtractWildcard(const wxString& filterStr, int n, wxString& filter, wxString& description)
1303 {
1304 wxArrayString filters, descriptions;
1305 int count = wxParseCommonDialogsFilter(filterStr, descriptions, filters);
1306 if (count > 0 && n < count)
1307 {
1308 filter = filters[n];
1309 description = descriptions[n];
1310 return true;
1311 }
1312
1313 return false;
1314 }
1315
1316
1317 void wxGenericDirCtrl::DoResize()
1318 {
1319 wxSize sz = GetClientSize();
1320 int verticalSpacing = 3;
1321 if (m_treeCtrl)
1322 {
1323 wxSize filterSz ;
1324 if (m_filterListCtrl)
1325 {
1326 filterSz = m_filterListCtrl->GetSize();
1327 sz.y -= (filterSz.y + verticalSpacing);
1328 }
1329 m_treeCtrl->SetSize(0, 0, sz.x, sz.y);
1330 if (m_filterListCtrl)
1331 {
1332 m_filterListCtrl->SetSize(0, sz.y + verticalSpacing, sz.x, filterSz.y);
1333 // Don't know why, but this needs refreshing after a resize (wxMSW)
1334 m_filterListCtrl->Refresh();
1335 }
1336 }
1337 }
1338
1339
1340 void wxGenericDirCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
1341 {
1342 DoResize();
1343 }
1344
1345 wxTreeItemId wxGenericDirCtrl::AppendItem (const wxTreeItemId & parent,
1346 const wxString & text,
1347 int image, int selectedImage,
1348 wxTreeItemData * data)
1349 {
1350 wxTreeCtrl *treeCtrl = GetTreeCtrl ();
1351
1352 wxASSERT (treeCtrl);
1353
1354 if (treeCtrl)
1355 {
1356 return treeCtrl->AppendItem (parent, text, image, selectedImage, data);
1357 }
1358 else
1359 {
1360 return wxTreeItemId();
1361 }
1362 }
1363
1364
1365 //-----------------------------------------------------------------------------
1366 // wxDirFilterListCtrl
1367 //-----------------------------------------------------------------------------
1368
1369 IMPLEMENT_CLASS(wxDirFilterListCtrl, wxChoice)
1370
1371 BEGIN_EVENT_TABLE(wxDirFilterListCtrl, wxChoice)
1372 EVT_CHOICE(wxID_ANY, wxDirFilterListCtrl::OnSelFilter)
1373 END_EVENT_TABLE()
1374
1375 bool wxDirFilterListCtrl::Create(wxGenericDirCtrl* parent,
1376 const wxWindowID treeid,
1377 const wxPoint& pos,
1378 const wxSize& size,
1379 long style)
1380 {
1381 m_dirCtrl = parent;
1382
1383 // by default our border style is determined by the style of our parent
1384 if ( !(style & wxBORDER_MASK) )
1385 {
1386 style |= parent->HasFlag(wxDIRCTRL_3D_INTERNAL) ? wxBORDER_SUNKEN
1387 : wxBORDER_NONE;
1388 }
1389
1390 return wxChoice::Create(parent, treeid, pos, size, 0, NULL, style);
1391 }
1392
1393 void wxDirFilterListCtrl::Init()
1394 {
1395 m_dirCtrl = NULL;
1396 }
1397
1398 void wxDirFilterListCtrl::OnSelFilter(wxCommandEvent& WXUNUSED(event))
1399 {
1400 int sel = GetSelection();
1401
1402 if (m_dirCtrl->HasFlag(wxDIRCTRL_MULTIPLE))
1403 {
1404 wxArrayString paths;
1405 m_dirCtrl->GetPaths(paths);
1406
1407 m_dirCtrl->SetFilterIndex(sel);
1408
1409 // If the filter has changed, the view is out of date, so
1410 // collapse the tree.
1411 m_dirCtrl->ReCreateTree();
1412
1413 // Expand and select the previously selected paths
1414 for (unsigned int i = 0; i < paths.GetCount(); i++)
1415 {
1416 m_dirCtrl->ExpandPath(paths.Item(i));
1417 }
1418 }
1419 else
1420 {
1421 wxString currentPath = m_dirCtrl->GetPath();
1422
1423 m_dirCtrl->SetFilterIndex(sel);
1424 m_dirCtrl->ReCreateTree();
1425
1426 // Try to restore the selection, or at least the directory
1427 m_dirCtrl->ExpandPath(currentPath);
1428 }
1429 }
1430
1431 void wxDirFilterListCtrl::FillFilterList(const wxString& filter, int defaultFilter)
1432 {
1433 Clear();
1434 wxArrayString descriptions, filters;
1435 size_t n = (size_t) wxParseCommonDialogsFilter(filter, descriptions, filters);
1436
1437 if (n > 0 && defaultFilter < (int) n)
1438 {
1439 for (size_t i = 0; i < n; i++)
1440 Append(descriptions[i]);
1441 SetSelection(defaultFilter);
1442 }
1443 }
1444 #endif // wxUSE_DIRDLG
1445
1446 #if wxUSE_DIRDLG || wxUSE_FILEDLG
1447
1448 // ----------------------------------------------------------------------------
1449 // wxFileIconsTable icons
1450 // ----------------------------------------------------------------------------
1451
1452 #ifndef __WXGTK20__
1453 /* Computer (c) Julian Smart */
1454 static const char* const file_icons_tbl_computer_xpm[] = {
1455 /* columns rows colors chars-per-pixel */
1456 "16 16 42 1",
1457 "r c #4E7FD0",
1458 "$ c #7198D9",
1459 "; c #DCE6F6",
1460 "q c #FFFFFF",
1461 "u c #4A7CCE",
1462 "# c #779DDB",
1463 "w c #95B2E3",
1464 "y c #7FA2DD",
1465 "f c #3263B4",
1466 "= c #EAF0FA",
1467 "< c #B1C7EB",
1468 "% c #6992D7",
1469 "9 c #D9E4F5",
1470 "o c #9BB7E5",
1471 "6 c #F7F9FD",
1472 ", c #BED0EE",
1473 "3 c #F0F5FC",
1474 "1 c #A8C0E8",
1475 " c None",
1476 "0 c #FDFEFF",
1477 "4 c #C4D5F0",
1478 "@ c #81A4DD",
1479 "e c #4377CD",
1480 "- c #E2EAF8",
1481 "i c #9FB9E5",
1482 "> c #CCDAF2",
1483 "+ c #89A9DF",
1484 "s c #5584D1",
1485 "t c #5D89D3",
1486 ": c #D2DFF4",
1487 "5 c #FAFCFE",
1488 "2 c #F5F8FD",
1489 "8 c #DFE8F7",
1490 "& c #5E8AD4",
1491 "X c #638ED5",
1492 "a c #CEDCF2",
1493 "p c #90AFE2",
1494 "d c #2F5DA9",
1495 "* c #5282D0",
1496 "7 c #E5EDF9",
1497 ". c #A2BCE6",
1498 "O c #8CACE0",
1499 /* pixels */
1500 " ",
1501 " .XXXXXXXXXXX ",
1502 " oXO++@#$%&*X ",
1503 " oX=-;:>,<1%X ",
1504 " oX23=-;:4,$X ",
1505 " oX5633789:@X ",
1506 " oX05623=78+X ",
1507 " oXqq05623=OX ",
1508 " oX,,,,,<<<$X ",
1509 " wXXXXXXXXXXe ",
1510 " XrtX%$$y@+O,, ",
1511 " uyiiiiiiiii@< ",
1512 " ouiiiiiiiiiip<a",
1513 " rustX%$$y@+Ow,,",
1514 " dfffffffffffffd",
1515 " "
1516 };
1517 #endif // !GTK+ 2
1518
1519 // ----------------------------------------------------------------------------
1520 // wxFileIconsTable & friends
1521 // ----------------------------------------------------------------------------
1522
1523 // global instance of a wxFileIconsTable
1524 wxFileIconsTable* wxTheFileIconsTable = NULL;
1525
1526 // A module to allow icons table cleanup
1527
1528 class wxFileIconsTableModule: public wxModule
1529 {
1530 DECLARE_DYNAMIC_CLASS(wxFileIconsTableModule)
1531 public:
1532 wxFileIconsTableModule() {}
1533 bool OnInit() { wxTheFileIconsTable = new wxFileIconsTable; return true; }
1534 void OnExit()
1535 {
1536 wxDELETE(wxTheFileIconsTable);
1537 }
1538 };
1539
1540 IMPLEMENT_DYNAMIC_CLASS(wxFileIconsTableModule, wxModule)
1541
1542 class wxFileIconEntry : public wxObject
1543 {
1544 public:
1545 wxFileIconEntry(int i) { iconid = i; }
1546
1547 int iconid;
1548 };
1549
1550 wxFileIconsTable::wxFileIconsTable()
1551 {
1552 m_HashTable = NULL;
1553 m_smallImageList = NULL;
1554 }
1555
1556 wxFileIconsTable::~wxFileIconsTable()
1557 {
1558 if (m_HashTable)
1559 {
1560 WX_CLEAR_HASH_TABLE(*m_HashTable);
1561 delete m_HashTable;
1562 }
1563 if (m_smallImageList) delete m_smallImageList;
1564 }
1565
1566 // delayed initialization - wait until first use (wxArtProv not created yet)
1567 void wxFileIconsTable::Create()
1568 {
1569 wxCHECK_RET(!m_smallImageList && !m_HashTable, wxT("creating icons twice"));
1570 m_HashTable = new wxHashTable(wxKEY_STRING);
1571 m_smallImageList = new wxImageList(16, 16);
1572
1573 // folder:
1574 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_FOLDER,
1575 wxART_CMN_DIALOG,
1576 wxSize(16, 16)));
1577 // folder_open
1578 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_FOLDER_OPEN,
1579 wxART_CMN_DIALOG,
1580 wxSize(16, 16)));
1581 // computer
1582 #ifdef __WXGTK20__
1583 // GTK24 uses this icon in the file open dialog
1584 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_HARDDISK,
1585 wxART_CMN_DIALOG,
1586 wxSize(16, 16)));
1587 #else
1588 m_smallImageList->Add(wxIcon(file_icons_tbl_computer_xpm));
1589 #endif
1590 // drive
1591 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_HARDDISK,
1592 wxART_CMN_DIALOG,
1593 wxSize(16, 16)));
1594 // cdrom
1595 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_CDROM,
1596 wxART_CMN_DIALOG,
1597 wxSize(16, 16)));
1598 // floppy
1599 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_FLOPPY,
1600 wxART_CMN_DIALOG,
1601 wxSize(16, 16)));
1602 // removeable
1603 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_REMOVABLE,
1604 wxART_CMN_DIALOG,
1605 wxSize(16, 16)));
1606 // file
1607 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_NORMAL_FILE,
1608 wxART_CMN_DIALOG,
1609 wxSize(16, 16)));
1610 // executable
1611 if (GetIconID(wxEmptyString, wxT("application/x-executable")) == file)
1612 {
1613 m_smallImageList->Add(wxArtProvider::GetBitmap(wxART_EXECUTABLE_FILE,
1614 wxART_CMN_DIALOG,
1615 wxSize(16, 16)));
1616 delete m_HashTable->Get(wxT("exe"));
1617 m_HashTable->Delete(wxT("exe"));
1618 m_HashTable->Put(wxT("exe"), new wxFileIconEntry(executable));
1619 }
1620 /* else put into list by GetIconID
1621 (KDE defines application/x-executable for *.exe and has nice icon)
1622 */
1623 }
1624
1625 wxImageList *wxFileIconsTable::GetSmallImageList()
1626 {
1627 if (!m_smallImageList)
1628 Create();
1629
1630 return m_smallImageList;
1631 }
1632
1633 #if wxUSE_MIMETYPE && wxUSE_IMAGE && (!defined(__WINDOWS__) || wxUSE_WXDIB)
1634 // VS: we don't need this function w/o wxMimeTypesManager because we'll only have
1635 // one icon and we won't resize it
1636
1637 static wxBitmap CreateAntialiasedBitmap(const wxImage& img)
1638 {
1639 const unsigned int size = 16;
1640
1641 wxImage smallimg (size, size);
1642 unsigned char *p1, *p2, *ps;
1643 unsigned char mr = img.GetMaskRed(),
1644 mg = img.GetMaskGreen(),
1645 mb = img.GetMaskBlue();
1646
1647 unsigned x, y;
1648 unsigned sr, sg, sb, smask;
1649
1650 p1 = img.GetData(), p2 = img.GetData() + 3 * size*2, ps = smallimg.GetData();
1651 smallimg.SetMaskColour(mr, mr, mr);
1652
1653 for (y = 0; y < size; y++)
1654 {
1655 for (x = 0; x < size; x++)
1656 {
1657 sr = sg = sb = smask = 0;
1658 if (p1[0] != mr || p1[1] != mg || p1[2] != mb)
1659 sr += p1[0], sg += p1[1], sb += p1[2];
1660 else smask++;
1661 p1 += 3;
1662 if (p1[0] != mr || p1[1] != mg || p1[2] != mb)
1663 sr += p1[0], sg += p1[1], sb += p1[2];
1664 else smask++;
1665 p1 += 3;
1666 if (p2[0] != mr || p2[1] != mg || p2[2] != mb)
1667 sr += p2[0], sg += p2[1], sb += p2[2];
1668 else smask++;
1669 p2 += 3;
1670 if (p2[0] != mr || p2[1] != mg || p2[2] != mb)
1671 sr += p2[0], sg += p2[1], sb += p2[2];
1672 else smask++;
1673 p2 += 3;
1674
1675 if (smask > 2)
1676 ps[0] = ps[1] = ps[2] = mr;
1677 else
1678 {
1679 ps[0] = (unsigned char)(sr >> 2);
1680 ps[1] = (unsigned char)(sg >> 2);
1681 ps[2] = (unsigned char)(sb >> 2);
1682 }
1683 ps += 3;
1684 }
1685 p1 += size*2 * 3, p2 += size*2 * 3;
1686 }
1687
1688 return wxBitmap(smallimg);
1689 }
1690
1691 // This function is currently not unused anymore
1692 #if 0
1693 // finds empty borders and return non-empty area of image:
1694 static wxImage CutEmptyBorders(const wxImage& img)
1695 {
1696 unsigned char mr = img.GetMaskRed(),
1697 mg = img.GetMaskGreen(),
1698 mb = img.GetMaskBlue();
1699 unsigned char *dt = img.GetData(), *dttmp;
1700 unsigned w = img.GetWidth(), h = img.GetHeight();
1701
1702 unsigned top, bottom, left, right, i;
1703 bool empt;
1704
1705 #define MK_DTTMP(x,y) dttmp = dt + ((x + y * w) * 3)
1706 #define NOEMPTY_PIX(empt) if (dttmp[0] != mr || dttmp[1] != mg || dttmp[2] != mb) {empt = false; break;}
1707
1708 for (empt = true, top = 0; empt && top < h; top++)
1709 {
1710 MK_DTTMP(0, top);
1711 for (i = 0; i < w; i++, dttmp+=3)
1712 NOEMPTY_PIX(empt)
1713 }
1714 for (empt = true, bottom = h-1; empt && bottom > top; bottom--)
1715 {
1716 MK_DTTMP(0, bottom);
1717 for (i = 0; i < w; i++, dttmp+=3)
1718 NOEMPTY_PIX(empt)
1719 }
1720 for (empt = true, left = 0; empt && left < w; left++)
1721 {
1722 MK_DTTMP(left, 0);
1723 for (i = 0; i < h; i++, dttmp+=3*w)
1724 NOEMPTY_PIX(empt)
1725 }
1726 for (empt = true, right = w-1; empt && right > left; right--)
1727 {
1728 MK_DTTMP(right, 0);
1729 for (i = 0; i < h; i++, dttmp+=3*w)
1730 NOEMPTY_PIX(empt)
1731 }
1732 top--, left--, bottom++, right++;
1733
1734 return img.GetSubImage(wxRect(left, top, right - left + 1, bottom - top + 1));
1735 }
1736 #endif // #if 0
1737
1738 #endif // wxUSE_MIMETYPE
1739
1740 int wxFileIconsTable::GetIconID(const wxString& extension, const wxString& mime)
1741 {
1742 if (!m_smallImageList)
1743 Create();
1744
1745 #if wxUSE_MIMETYPE
1746 if (!extension.empty())
1747 {
1748 wxFileIconEntry *entry = (wxFileIconEntry*) m_HashTable->Get(extension);
1749 if (entry) return (entry -> iconid);
1750 }
1751
1752 wxFileType *ft = (mime.empty()) ?
1753 wxTheMimeTypesManager -> GetFileTypeFromExtension(extension) :
1754 wxTheMimeTypesManager -> GetFileTypeFromMimeType(mime);
1755
1756 wxIconLocation iconLoc;
1757 wxIcon ic;
1758
1759 {
1760 wxLogNull logNull;
1761 if ( ft && ft->GetIcon(&iconLoc) )
1762 {
1763 ic = wxIcon( iconLoc );
1764 }
1765 }
1766
1767 delete ft;
1768
1769 if ( !ic.IsOk() )
1770 {
1771 int newid = file;
1772 m_HashTable->Put(extension, new wxFileIconEntry(newid));
1773 return newid;
1774 }
1775
1776 wxBitmap bmp;
1777 bmp.CopyFromIcon(ic);
1778
1779 if ( !bmp.IsOk() )
1780 {
1781 int newid = file;
1782 m_HashTable->Put(extension, new wxFileIconEntry(newid));
1783 return newid;
1784 }
1785
1786 const unsigned int size = 16;
1787
1788 int treeid = m_smallImageList->GetImageCount();
1789 if ((bmp.GetWidth() == (int) size) && (bmp.GetHeight() == (int) size))
1790 {
1791 m_smallImageList->Add(bmp);
1792 }
1793 #if wxUSE_IMAGE && (!defined(__WINDOWS__) || wxUSE_WXDIB)
1794 else
1795 {
1796 wxImage img = bmp.ConvertToImage();
1797
1798 if ((img.GetWidth() != size*2) || (img.GetHeight() != size*2))
1799 // m_smallImageList->Add(CreateAntialiasedBitmap(CutEmptyBorders(img).Rescale(size*2, size*2)));
1800 m_smallImageList->Add(CreateAntialiasedBitmap(img.Rescale(size*2, size*2)));
1801 else
1802 m_smallImageList->Add(CreateAntialiasedBitmap(img));
1803 }
1804 #endif // wxUSE_IMAGE
1805
1806 m_HashTable->Put(extension, new wxFileIconEntry(treeid));
1807 return treeid;
1808
1809 #else // !wxUSE_MIMETYPE
1810
1811 wxUnusedVar(mime);
1812 if (extension == wxT("exe"))
1813 return executable;
1814 else
1815 return file;
1816 #endif // wxUSE_MIMETYPE/!wxUSE_MIMETYPE
1817 }
1818
1819 #endif // wxUSE_DIRDLG || wxUSE_FILEDLG