1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxGenericDirCtrl 
   4 // Author:      Harm van der Heijden, Robert Roebling, Julian Smart 
   8 // Copyright:   (c) Harm van der Heijden, Robert Roebling and Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 #pragma implementation "dirctrlg.h" 
  16 // For compilers that support precompilation, includes "wx.h". 
  17 #include "wx/wxprec.h" 
  25 #include "wx/generic/dirctrlg.h" 
  27 #include "wx/module.h" 
  29 #include "wx/button.h" 
  30 #include "wx/layout.h" 
  31 #include "wx/msgdlg.h" 
  32 #include "wx/textctrl.h" 
  33 #include "wx/textdlg.h" 
  34 #include "wx/filefn.h" 
  35 #include "wx/cmndata.h" 
  36 #include "wx/gdicmn.h" 
  38 #include "wx/imaglist.h" 
  42 #include "wx/tokenzr.h" 
  44 #include "wx/settings.h" 
  45 #include "wx/artprov.h" 
  47 #include "wx/mimetype.h" 
  49 #include "wx/choice.h" 
  52     #include "wx/statline.h" 
  55 #if defined(__WXMAC__) 
  56   #include  "wx/mac/private.h"  // includes mac headers 
  62 // FIXME - Mingw32 1.0 has both _getdrive() and _chdrive(). For now, let's assume 
  63 //         older releases don't, but it should be verified and the checks modified 
  65 #if !defined(__GNUWIN32__) || (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1) 
  66 #if !defined(__WXWINCE__) 
  84 extern bool wxIsDriveAvailable(const wxString
& dirName
); 
  87 #if defined(__WXMAC__) 
  89 #    include "MoreFilesX.h" 
  91 #    include "MoreFilesExtras.h" 
  99 // If compiled under Windows, this macro can cause problems 
 104 // declared in filedlg.h, defined in fldlgcmn.cpp 
 105 extern int wxParseFileFilter(const wxString
& filterStr
, wxArrayString
& descriptions
, wxArrayString
& filters
); 
 107 // ---------------------------------------------------------------------------- 
 108 // wxGetAvailableDrives, for WINDOWS, DOS, WXPM, MAC, UNIX (returns "/") 
 109 // ---------------------------------------------------------------------------- 
 111 size_t wxGetAvailableDrives(wxArrayString 
&paths
, wxArrayString 
&names
, wxArrayInt 
&icon_ids
) 
 113 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__WXPM__) 
 116     // No logical drives; return "\" 
 117     paths
.Add(wxT("\\")); 
 118     names
.Add(wxT("\\")); 
 120 #elif defined(__WIN32__) 
 121     wxChar driveBuffer
[256]; 
 122     size_t n 
= (size_t) GetLogicalDriveStrings(255, driveBuffer
); 
 127         path
.Printf(wxT("%c:\\"), driveBuffer
[i
]); 
 128         name
.Printf(wxT("%c:"), driveBuffer
[i
]); 
 130         int imageId 
= wxFileIconsTable::drive
; 
 131         int driveType 
= ::GetDriveType(path
); 
 134             case DRIVE_REMOVABLE
: 
 135                 if (path 
== wxT("a:\\") || path 
== wxT("b:\\")) 
 136                     imageId 
= wxFileIconsTable::floppy
; 
 138                     imageId 
= wxFileIconsTable::removeable
; 
 141                 imageId 
= wxFileIconsTable::cdrom
; 
 146                 imageId 
= wxFileIconsTable::drive
; 
 152         icon_ids
.Add(imageId
); 
 154         while (driveBuffer
[i
] != wxT('\0')) 
 157         if (driveBuffer
[i
] == wxT('\0')) 
 163     /* If we can switch to the drive, it exists. */ 
 164     for( drive 
= 1; drive 
<= 26; drive
++ ) 
 167         path
.Printf(wxT("%c:\\"), (char) (drive 
+ 'a' - 1)); 
 168         name
.Printf(wxT("%c:"), (char) (drive 
+ 'A' - 1)); 
 170         if (wxIsDriveAvailable(path
)) 
 174             icon_ids
.Add((drive 
<= 2) ? wxFileIconsTable::floppy 
: wxFileIconsTable::drive
); 
 177 #endif // __WIN32__/!__WIN32__ 
 179 #elif defined(__WXMAC__) 
 182     ItemCount   theVolCount
; 
 183     char        thePath
[FILENAME_MAX
]; 
 185     if (FSGetMountedVolumes(&theVolRefs
, &theVolCount
) == noErr
) { 
 187         ::HLock( (Handle
)theVolRefs 
) ; 
 188         for (index 
= 0; index 
< theVolCount
; ++index
) { 
 189             // get the POSIX path associated with the FSRef 
 190             if ( FSRefMakePath(&((*theVolRefs
)[index
]), 
 191                                  (UInt8 
*)thePath
, sizeof(thePath
)) != noErr 
) { 
 194             // add path separator at end if necessary 
 195             wxString 
path( thePath 
) ; 
 196             if (path
.Last() != wxFILE_SEP_PATH
) { 
 197                 path 
+= wxFILE_SEP_PATH
; 
 199             // get Mac volume name for display 
 200             FSVolumeRefNum vRefNum 
; 
 201             HFSUniStr255 volumeName 
; 
 203             if ( FSGetVRefNum(&((*theVolRefs
)[index
]), &vRefNum
) != noErr 
) { 
 206             if ( FSGetVInfo(vRefNum
, &volumeName
, NULL
, NULL
) != noErr 
) { 
 209             // get C string from Unicode HFS name 
 210             //   see: http://developer.apple.com/carbon/tipsandtricks.html 
 211             CFStringRef cfstr 
= CFStringCreateWithCharacters( kCFAllocatorDefault
, 
 214             //  Do something with str 
 215             char *cstr 
= NewPtr(CFStringGetLength(cfstr
) + 1); 
 216             if (( cstr 
== NULL 
) || 
 217                 !CFStringGetCString(cfstr
, cstr
, CFStringGetLength(cfstr
) + 1, 
 218                                     kCFStringEncodingMacRoman
)) 
 223             wxString 
name( cstr 
); 
 227             GetVolParmsInfoBuffer volParmsInfo
; 
 229             if ( FSGetVolParms(vRefNum
, sizeof(volParmsInfo
), &volParmsInfo
, &actualSize
) != noErr 
) { 
 236             if ( VolIsEjectable(&volParmsInfo
) ) 
 237                 icon_ids
.Add(wxFileIconsTable::cdrom
); 
 239                 icon_ids
.Add(wxFileIconsTable::drive
); 
 241         ::HUnlock( (Handle
)theVolRefs 
); 
 242         ::DisposeHandle( (Handle
)theVolRefs 
); 
 249         short actualCount 
= 0 ; 
 250         if (OnLine(&volume
, 1, &actualCount
, &index 
) != noErr 
|| actualCount
==0) 
 255         wxString name 
= wxMacFSSpec2MacFilename( &volume 
); 
 256         paths
.Add(name 
+ wxFILE_SEP_PATH
); 
 258         icon_ids
.Add(wxFileIconsTable::drive
); 
 262 #elif defined(__UNIX__) 
 265     icon_ids
.Add(wxFileIconsTable::computer
); 
 267     #error "Unsupported platform in wxGenericDirCtrl!" 
 269     return paths
.GetCount(); 
 272 // ---------------------------------------------------------------------------- 
 273 // wxIsDriveAvailable 
 274 // ---------------------------------------------------------------------------- 
 278 bool wxIsDriveAvailable(const wxString
& dirName
) 
 280     // FIXME_MGL - this method leads to hang up under Watcom for some reason 
 282     if ( dirName
.Len() == 3 && dirName
[1u] == wxT(':') ) 
 284         wxString 
dirNameLower(dirName
.Lower()); 
 285         // VS: always return TRUE for removable media, since Win95 doesn't 
 286         //     like it when MS-DOS app accesses empty floppy drive 
 287         return (dirNameLower
[0u] == wxT('a') || 
 288                 dirNameLower
[0u] == wxT('b') || 
 289                 wxPathExists(dirNameLower
)); 
 296 #elif defined(__WINDOWS__) || defined(__WXPM__) 
 298 int setdrive(int drive
) 
 302 #elif defined(__GNUWIN32__) && \ 
 303     (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1) 
 304     return _chdrive(drive
); 
 308         if (drive 
< 1 || drive 
> 31) 
 310         newdrive
[0] = (wxChar
)(wxT('A') + drive 
- 1); 
 311         newdrive
[1] = wxT(':'); 
 312         newdrive
[2] = wxT('\0'); 
 313 #if defined(__WXMSW__) 
 314         if (::SetCurrentDirectory(newdrive
)) 
 316     // VA doesn't know what LPSTR is and has its own set 
 317         if (DosSetCurrentDir((PSZ
)newdrive
)) 
 325 bool wxIsDriveAvailable(const wxString
& dirName
) 
 331     UINT errorMode 
= SetErrorMode(SEM_FAILCRITICALERRORS 
| SEM_NOOPENFILEERRORBOX
); 
 335     // Check if this is a root directory and if so, 
 336     // whether the drive is available. 
 337     if (dirName
.Len() == 3 && dirName
[(size_t)1] == wxT(':')) 
 339         wxString 
dirNameLower(dirName
.Lower()); 
 340 #if defined(__GNUWIN32__) && !(defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1) 
 341         success 
= wxPathExists(dirNameLower
); 
 343         int currentDrive 
= _getdrive(); 
 344         int thisDrive 
= (int) (dirNameLower
[(size_t)0] - 'a' + 1) ; 
 345         int err 
= setdrive( thisDrive 
) ; 
 346         setdrive( currentDrive 
); 
 355     (void) SetErrorMode(errorMode
); 
 361 #endif // __WINDOWS__ || __WXPM__ 
 364 // Function which is called by quick sort. We want to override the default wxArrayString behaviour, 
 365 // and sort regardless of case. 
 366 static int LINKAGEMODE 
wxDirCtrlStringCompareFunction(wxString
* strFirst
, wxString
* strSecond
) 
 368     return strFirst
->CmpNoCase(*strSecond
); 
 371 //----------------------------------------------------------------------------- 
 373 //----------------------------------------------------------------------------- 
 375 wxDirItemData::wxDirItemData(const wxString
& path
, const wxString
& name
, 
 380     /* Insert logic to detect hidden files here 
 381      * In UnixLand we just check whether the first char is a dot 
 382      * For FileNameFromPath read LastDirNameInThisPath ;-) */ 
 383     // m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.'); 
 385     m_isExpanded 
= FALSE
; 
 389 wxDirItemData::~wxDirItemData() 
 393 void wxDirItemData::SetNewDirName(const wxString
& path
) 
 396     m_name 
= wxFileNameFromPath(path
); 
 399 bool wxDirItemData::HasSubDirs() const 
 401     if (m_path
.IsEmpty()) 
 407         if ( !dir
.Open(m_path
) ) 
 411     return dir
.HasSubDirs(); 
 414 bool wxDirItemData::HasFiles(const wxString
& WXUNUSED(spec
)) const 
 416     if (m_path
.IsEmpty()) 
 422         if ( !dir
.Open(m_path
) ) 
 426     return dir
.HasFiles(); 
 429 //----------------------------------------------------------------------------- 
 431 //----------------------------------------------------------------------------- 
 433 IMPLEMENT_DYNAMIC_CLASS(wxGenericDirCtrl
, wxControl
) 
 435 BEGIN_EVENT_TABLE(wxGenericDirCtrl
, wxControl
) 
 436   EVT_TREE_ITEM_EXPANDING     (-1, wxGenericDirCtrl::OnExpandItem
) 
 437   EVT_TREE_ITEM_COLLAPSED     (-1, wxGenericDirCtrl::OnCollapseItem
) 
 438   EVT_TREE_BEGIN_LABEL_EDIT   (-1, wxGenericDirCtrl::OnBeginEditItem
) 
 439   EVT_TREE_END_LABEL_EDIT     (-1, wxGenericDirCtrl::OnEndEditItem
) 
 440   EVT_SIZE                    (wxGenericDirCtrl::OnSize
) 
 443 wxGenericDirCtrl::wxGenericDirCtrl(void) 
 448 bool wxGenericDirCtrl::Create(wxWindow 
*parent
, 
 454                               const wxString
& filter
, 
 456                               const wxString
& name
) 
 458     if (!wxControl::Create(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
)) 
 461     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
)); 
 465     long treeStyle 
= wxTR_HAS_BUTTONS 
| wxTR_HIDE_ROOT
; 
 467     if (style 
& wxDIRCTRL_EDIT_LABELS
) 
 468         treeStyle 
|= wxTR_EDIT_LABELS
; 
 470     if ((style 
& wxDIRCTRL_3D_INTERNAL
) == 0) 
 471         treeStyle 
|= wxNO_BORDER
; 
 473         treeStyle 
|= wxBORDER_SUNKEN
; 
 475     long filterStyle 
= 0; 
 476     if ((style 
& wxDIRCTRL_3D_INTERNAL
) == 0) 
 477         filterStyle 
|= wxNO_BORDER
; 
 479         filterStyle 
|= wxBORDER_SUNKEN
; 
 481     m_treeCtrl 
= new wxTreeCtrl(this, wxID_TREECTRL
, pos
, size
, treeStyle
); 
 483     if (!filter
.IsEmpty() && (style 
& wxDIRCTRL_SHOW_FILTERS
)) 
 484         m_filterListCtrl 
= new wxDirFilterListCtrl(this, wxID_FILTERLISTCTRL
, wxDefaultPosition
, wxDefaultSize
, filterStyle
); 
 489     SetFilterIndex(defaultFilter
); 
 491     if (m_filterListCtrl
) 
 492         m_filterListCtrl
->FillFilterList(filter
, defaultFilter
); 
 494     m_treeCtrl
->SetImageList(wxTheFileIconsTable
->GetSmallImageList()); 
 496     m_showHidden 
= FALSE
; 
 497     wxDirItemData
* rootData 
= new wxDirItemData(wxT(""), wxT(""), TRUE
); 
 501 #if defined(__WINDOWS__) || defined(__WXPM__) || defined(__DOS__) 
 502     rootName 
= _("Computer"); 
 504     rootName 
= _("Sections"); 
 507     m_rootId 
= m_treeCtrl
->AddRoot( rootName
, 3, -1, rootData
); 
 508     m_treeCtrl
->SetItemHasChildren(m_rootId
); 
 509     ExpandDir(m_rootId
); // automatically expand first level 
 511     // Expand and select the default path 
 512     if (!m_defaultPath
.IsEmpty()) 
 513         ExpandPath(m_defaultPath
); 
 520 wxGenericDirCtrl::~wxGenericDirCtrl() 
 524 void wxGenericDirCtrl::Init() 
 526     m_showHidden 
= FALSE
; 
 528     m_currentFilterStr 
= wxEmptyString
; // Default: any file 
 530     m_filterListCtrl 
= NULL
; 
 533 void wxGenericDirCtrl::ShowHidden( bool show 
) 
 537     wxString path 
= GetPath(); 
 543 wxGenericDirCtrl::AddSection(const wxString
& path
, const wxString
& name
, int imageId
) 
 545     wxDirItemData 
*dir_item 
= new wxDirItemData(path
,name
,TRUE
); 
 547     wxTreeItemId id 
= AppendItem( m_rootId
, name
, imageId
, -1, dir_item
); 
 549     m_treeCtrl
->SetItemHasChildren(id
); 
 554 void wxGenericDirCtrl::SetupSections() 
 556     wxArrayString paths
, names
; 
 559     size_t n
, count 
= wxGetAvailableDrives(paths
, names
, icons
); 
 561     for (n 
= 0; n 
< count
; n
++) 
 563         AddSection(paths
[n
], names
[n
], icons
[n
]); 
 567 void wxGenericDirCtrl::OnBeginEditItem(wxTreeEvent 
&event
) 
 569     // don't rename the main entry "Sections" 
 570     if (event
.GetItem() == m_rootId
) 
 576     // don't rename the individual sections 
 577     if (m_treeCtrl
->GetItemParent( event
.GetItem() ) == m_rootId
) 
 584 void wxGenericDirCtrl::OnEndEditItem(wxTreeEvent 
&event
) 
 586     if ((event
.GetLabel().IsEmpty()) || 
 587         (event
.GetLabel() == _(".")) || 
 588         (event
.GetLabel() == _("..")) || 
 589         (event
.GetLabel().Find(wxT('/')) != wxNOT_FOUND
) || 
 590         (event
.GetLabel().Find(wxT('\\')) != wxNOT_FOUND
) || 
 591         (event
.GetLabel().Find(wxT('|')) != wxNOT_FOUND
)) 
 593         wxMessageDialog 
dialog(this, _("Illegal directory name."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 599     wxTreeItemId id 
= event
.GetItem(); 
 600     wxDirItemData 
*data 
= (wxDirItemData
*)m_treeCtrl
->GetItemData( id 
); 
 603     wxString 
new_name( wxPathOnly( data
->m_path 
) ); 
 604     new_name 
+= wxString(wxFILE_SEP_PATH
); 
 605     new_name 
+= event
.GetLabel(); 
 609     if (wxFileExists(new_name
)) 
 611         wxMessageDialog 
dialog(this, _("File name exists already."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 616     if (wxRenameFile(data
->m_path
,new_name
)) 
 618         data
->SetNewDirName( new_name 
); 
 622         wxMessageDialog 
dialog(this, _("Operation not permitted."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 628 void wxGenericDirCtrl::OnExpandItem(wxTreeEvent 
&event
) 
 630     wxTreeItemId parentId 
= event
.GetItem(); 
 632     // VS: this is needed because the event handler is called from wxTreeCtrl 
 633     //     ctor when wxTR_HIDE_ROOT was specified 
 635     if (!m_rootId
.IsOk()) 
 637         m_rootId 
= m_treeCtrl
->GetRootItem(); 
 642 void wxGenericDirCtrl::OnCollapseItem(wxTreeEvent 
&event 
) 
 644     CollapseDir(event
.GetItem()); 
 647 void wxGenericDirCtrl::CollapseDir(wxTreeItemId parentId
) 
 651     wxDirItemData 
*data 
= (wxDirItemData 
*) m_treeCtrl
->GetItemData(parentId
); 
 652     if (!data
->m_isExpanded
) 
 655     data
->m_isExpanded 
= FALSE
; 
 657     /* Workaround because DeleteChildren has disapeared (why?) and 
 658      * CollapseAndReset doesn't work as advertised (deletes parent too) */ 
 659     child 
= m_treeCtrl
->GetFirstChild(parentId
, cookie
); 
 662         m_treeCtrl
->Delete(child
); 
 663         /* Not GetNextChild below, because the cookie mechanism can't 
 664          * handle disappearing children! */ 
 665         child 
= m_treeCtrl
->GetFirstChild(parentId
, cookie
); 
 669 void wxGenericDirCtrl::ExpandDir(wxTreeItemId parentId
) 
 671     wxDirItemData 
*data 
= (wxDirItemData 
*) m_treeCtrl
->GetItemData(parentId
); 
 673     if (data
->m_isExpanded
) 
 676     data
->m_isExpanded 
= TRUE
; 
 678     if (parentId 
== m_treeCtrl
->GetRootItem()) 
 686     wxString search
,path
,filename
; 
 688     wxString 
dirName(data
->m_path
); 
 690 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__WXPM__) 
 691     // Check if this is a root directory and if so, 
 692     // whether the drive is avaiable. 
 693     if (!wxIsDriveAvailable(dirName
)) 
 695         data
->m_isExpanded 
= FALSE
; 
 696         //wxMessageBox(wxT("Sorry, this drive is not available.")); 
 701     // This may take a longish time. Go to busy cursor 
 704 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__WXPM__) 
 705     if (dirName
.Last() == ':') 
 706         dirName 
+= wxString(wxFILE_SEP_PATH
); 
 710     wxArrayString filenames
; 
 713     wxString eachFilename
; 
 720         int style 
= wxDIR_DIRS
; 
 721         if (m_showHidden
) style 
|= wxDIR_HIDDEN
; 
 722         if (d
.GetFirst(& eachFilename
, wxEmptyString
, style
)) 
 726                 if ((eachFilename 
!= wxT(".")) && (eachFilename 
!= wxT(".."))) 
 728                     dirs
.Add(eachFilename
); 
 731             while (d
.GetNext(& eachFilename
)); 
 734     dirs
.Sort(wxDirCtrlStringCompareFunction
); 
 736     // Now do the filenames -- but only if we're allowed to 
 737     if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY
) == 0) 
 745             if (d
.GetFirst(& eachFilename
, m_currentFilterStr
, wxDIR_FILES
)) 
 749                     if ((eachFilename 
!= wxT(".")) && (eachFilename 
!= wxT(".."))) 
 751                         filenames
.Add(eachFilename
); 
 754                 while (d
.GetNext(& eachFilename
)); 
 757         filenames
.Sort(wxDirCtrlStringCompareFunction
); 
 760     // Add the sorted dirs 
 762     for (i 
= 0; i 
< dirs
.Count(); i
++) 
 764         wxString 
eachFilename(dirs
[i
]); 
 766         if (!wxEndsWithPathSeparator(path
)) 
 767             path 
+= wxString(wxFILE_SEP_PATH
); 
 768         path 
+= eachFilename
; 
 770         wxDirItemData 
*dir_item 
= new wxDirItemData(path
,eachFilename
,TRUE
); 
 771         wxTreeItemId id 
= AppendItem( parentId
, eachFilename
, 
 772                                       wxFileIconsTable::folder
, -1, dir_item
); 
 773         m_treeCtrl
->SetItemImage( id
, wxFileIconsTable::folder_open
, 
 774                                   wxTreeItemIcon_Expanded 
); 
 776         // Has this got any children? If so, make it expandable. 
 777         // (There are two situations when a dir has children: either it 
 778         // has subdirectories or it contains files that weren't filtered 
 779         // out. The latter only applies to dirctrl with files.) 
 780         if ( dir_item
->HasSubDirs() || 
 781              (((GetWindowStyle() & wxDIRCTRL_DIR_ONLY
) == 0) && 
 782                dir_item
->HasFiles(m_currentFilterStr
)) ) 
 784             m_treeCtrl
->SetItemHasChildren(id
); 
 788     // Add the sorted filenames 
 789     if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY
) == 0) 
 791         for (i 
= 0; i 
< filenames
.Count(); i
++) 
 793             wxString 
eachFilename(filenames
[i
]); 
 795             if (!wxEndsWithPathSeparator(path
)) 
 796                 path 
+= wxString(wxFILE_SEP_PATH
); 
 797             path 
+= eachFilename
; 
 798             //path = dirName + wxString(wxT("/")) + eachFilename; 
 799             wxDirItemData 
*dir_item 
= new wxDirItemData(path
,eachFilename
,FALSE
); 
 800             int image_id 
= wxFileIconsTable::file
; 
 801             if (eachFilename
.Find(wxT('.')) != wxNOT_FOUND
) 
 802                 image_id 
= wxTheFileIconsTable
->GetIconID(eachFilename
.AfterLast(wxT('.'))); 
 803             (void) AppendItem( parentId
, eachFilename
, image_id
, -1, dir_item
); 
 808 void wxGenericDirCtrl::ReCreateTree() 
 810     CollapseDir(m_treeCtrl
->GetRootItem()); 
 811     ExpandDir(m_treeCtrl
->GetRootItem()); 
 814 // Find the child that matches the first part of 'path'. 
 815 // E.g. if a child path is "/usr" and 'path' is "/usr/include" 
 816 // then the child for /usr is returned. 
 817 wxTreeItemId 
wxGenericDirCtrl::FindChild(wxTreeItemId parentId
, const wxString
& path
, bool& done
) 
 819     wxString 
path2(path
); 
 821     // Make sure all separators are as per the current platform 
 822     path2
.Replace(wxT("\\"), wxString(wxFILE_SEP_PATH
)); 
 823     path2
.Replace(wxT("/"), wxString(wxFILE_SEP_PATH
)); 
 825     // Append a separator to foil bogus substring matching 
 826     path2 
+= wxString(wxFILE_SEP_PATH
); 
 828     // In MSW or PM, case is not significant 
 829 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__WXPM__) 
 834     wxTreeItemId childId 
= m_treeCtrl
->GetFirstChild(parentId
, cookie
); 
 835     while (childId
.IsOk()) 
 837         wxDirItemData
* data 
= (wxDirItemData
*) m_treeCtrl
->GetItemData(childId
); 
 839         if (data 
&& !data
->m_path
.IsEmpty()) 
 841             wxString 
childPath(data
->m_path
); 
 842             if (!wxEndsWithPathSeparator(childPath
)) 
 843                 childPath 
+= wxString(wxFILE_SEP_PATH
); 
 845             // In MSW and PM, case is not significant 
 846 #if defined(__WINDOWS__) || defined(__DOS__) || defined(__WXPM__) 
 847             childPath
.MakeLower(); 
 850             if (childPath
.Len() <= path2
.Len()) 
 852                 wxString path3 
= path2
.Mid(0, childPath
.Len()); 
 853                 if (childPath 
== path3
) 
 855                     if (path3
.Len() == path2
.Len()) 
 864         childId 
= m_treeCtrl
->GetNextChild(parentId
, cookie
); 
 866     wxTreeItemId invalid
; 
 870 // Try to expand as much of the given path as possible, 
 871 // and select the given tree item. 
 872 bool wxGenericDirCtrl::ExpandPath(const wxString
& path
) 
 875     wxTreeItemId id 
= FindChild(m_rootId
, path
, done
); 
 876     wxTreeItemId lastId 
= id
; // The last non-zero id 
 877     while (id
.IsOk() && !done
) 
 881         id 
= FindChild(id
, path
, done
); 
 887         wxDirItemData 
*data 
= (wxDirItemData 
*) m_treeCtrl
->GetItemData(lastId
); 
 890             m_treeCtrl
->Expand(lastId
); 
 892         if ((GetWindowStyle() & wxDIRCTRL_SELECT_FIRST
) && data
->m_isDir
) 
 894             // Find the first file in this directory 
 896             wxTreeItemId childId 
= m_treeCtrl
->GetFirstChild(lastId
, cookie
); 
 897             bool selectedChild 
= FALSE
; 
 898             while (childId
.IsOk()) 
 900                 wxDirItemData
* data 
= (wxDirItemData
*) m_treeCtrl
->GetItemData(childId
); 
 902                 if (data 
&& data
->m_path 
!= wxT("") && !data
->m_isDir
) 
 904                     m_treeCtrl
->SelectItem(childId
); 
 905                     m_treeCtrl
->EnsureVisible(childId
); 
 906                     selectedChild 
= TRUE
; 
 909                 childId 
= m_treeCtrl
->GetNextChild(lastId
, cookie
); 
 913                 m_treeCtrl
->SelectItem(lastId
); 
 914                 m_treeCtrl
->EnsureVisible(lastId
); 
 919             m_treeCtrl
->SelectItem(lastId
); 
 920             m_treeCtrl
->EnsureVisible(lastId
); 
 929 wxString 
wxGenericDirCtrl::GetPath() const 
 931     wxTreeItemId id 
= m_treeCtrl
->GetSelection(); 
 934         wxDirItemData
* data 
= (wxDirItemData
*) m_treeCtrl
->GetItemData(id
); 
 938         return wxEmptyString
; 
 941 wxString 
wxGenericDirCtrl::GetFilePath() const 
 943     wxTreeItemId id 
= m_treeCtrl
->GetSelection(); 
 946         wxDirItemData
* data 
= (wxDirItemData
*) m_treeCtrl
->GetItemData(id
); 
 948             return wxEmptyString
; 
 953         return wxEmptyString
; 
 956 void wxGenericDirCtrl::SetPath(const wxString
& path
) 
 958     m_defaultPath 
= path
; 
 965 void wxGenericDirCtrl::FindChildFiles(wxTreeItemId id
, int dirFlags
, wxArrayString
& filenames
) 
 967     wxDirItemData 
*data 
= (wxDirItemData 
*) m_treeCtrl
->GetItemData(id
); 
 969     // This may take a longish time. Go to busy cursor 
 974     wxString search
,path
,filename
; 
 976     wxString 
dirName(data
->m_path
); 
 978 #if defined(__WXMSW__) || defined(__WXPM__) 
 979     if (dirName
.Last() == ':') 
 980         dirName 
+= wxString(wxFILE_SEP_PATH
); 
 984     wxString eachFilename
; 
 991         if (d
.GetFirst(& eachFilename
, m_currentFilterStr
, dirFlags
)) 
 995                 if ((eachFilename 
!= wxT(".")) && (eachFilename 
!= wxT(".."))) 
 997                     filenames
.Add(eachFilename
); 
1000             while (d
.GetNext(& eachFilename
)) ; 
1006 void wxGenericDirCtrl::SetFilterIndex(int n
) 
1008     m_currentFilter 
= n
; 
1011     if (ExtractWildcard(m_filter
, n
, f
, d
)) 
1012         m_currentFilterStr 
= f
; 
1014         m_currentFilterStr 
= wxT("*.*"); 
1017 void wxGenericDirCtrl::SetFilter(const wxString
& filter
) 
1022     if (ExtractWildcard(m_filter
, m_currentFilter
, f
, d
)) 
1023         m_currentFilterStr 
= f
; 
1025         m_currentFilterStr 
= wxT("*.*"); 
1028 // Extract description and actual filter from overall filter string 
1029 bool wxGenericDirCtrl::ExtractWildcard(const wxString
& filterStr
, int n
, wxString
& filter
, wxString
& description
) 
1031     wxArrayString filters
, descriptions
; 
1032     int count 
= ParseFilter(filterStr
, filters
, descriptions
); 
1033     if (count 
> 0 && n 
< count
) 
1035         filter 
= filters
[n
]; 
1036         description 
= descriptions
[n
]; 
1043 // Parses the global filter, returning the number of filters. 
1044 // Returns 0 if none or if there's a problem. 
1045 // filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpg" 
1047 int wxGenericDirCtrl::ParseFilter(const wxString
& filterStr
, wxArrayString
& filters
, wxArrayString
& descriptions
) 
1049     return wxParseFileFilter(filterStr
, descriptions
, filters 
); 
1052 void wxGenericDirCtrl::DoResize() 
1054     wxSize sz 
= GetClientSize(); 
1055     int verticalSpacing 
= 3; 
1059         if (m_filterListCtrl
) 
1062             // For some reason, this is required in order for the 
1063             // correct control height to always be returned, rather 
1064             // than the drop-down list height which is sometimes returned. 
1065             wxSize oldSize 
= m_filterListCtrl
->GetSize(); 
1066             m_filterListCtrl
->SetSize(-1, -1, oldSize
.x
+10, -1, wxSIZE_USE_EXISTING
); 
1067             m_filterListCtrl
->SetSize(-1, -1, oldSize
.x
, -1, wxSIZE_USE_EXISTING
); 
1069             filterSz 
= m_filterListCtrl
->GetSize(); 
1070             sz
.y 
-= (filterSz
.y 
+ verticalSpacing
); 
1072         m_treeCtrl
->SetSize(0, 0, sz
.x
, sz
.y
); 
1073         if (m_filterListCtrl
) 
1075             m_filterListCtrl
->SetSize(0, sz
.y 
+ verticalSpacing
, sz
.x
, filterSz
.y
); 
1076             // Don't know why, but this needs refreshing after a resize (wxMSW) 
1077             m_filterListCtrl
->Refresh(); 
1083 void wxGenericDirCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
1088 wxTreeItemId 
wxGenericDirCtrl::AppendItem (const wxTreeItemId 
& parent
, 
1089                                            const wxString 
& text
, 
1090                                            int image
, int selectedImage
, 
1091                                            wxTreeItemData 
* data
) 
1093   wxTreeCtrl 
*treeCtrl 
= GetTreeCtrl (); 
1095   wxASSERT (treeCtrl
); 
1099     return treeCtrl
->AppendItem (parent
, text
, image
, selectedImage
, data
); 
1103     return wxTreeItemId(); 
1108 //----------------------------------------------------------------------------- 
1109 // wxDirFilterListCtrl 
1110 //----------------------------------------------------------------------------- 
1112 IMPLEMENT_CLASS(wxDirFilterListCtrl
, wxChoice
) 
1114 BEGIN_EVENT_TABLE(wxDirFilterListCtrl
, wxChoice
) 
1115     EVT_CHOICE(-1, wxDirFilterListCtrl::OnSelFilter
) 
1118 bool wxDirFilterListCtrl::Create(wxGenericDirCtrl
* parent
, const wxWindowID id
, 
1124     return wxChoice::Create(parent
, id
, pos
, size
, 0, NULL
, style
); 
1127 void wxDirFilterListCtrl::Init() 
1132 void wxDirFilterListCtrl::OnSelFilter(wxCommandEvent
& WXUNUSED(event
)) 
1134     int sel 
= GetSelection(); 
1136     wxString currentPath 
= m_dirCtrl
->GetPath(); 
1138     m_dirCtrl
->SetFilterIndex(sel
); 
1140     // If the filter has changed, the view is out of date, so 
1141     // collapse the tree. 
1142     m_dirCtrl
->ReCreateTree(); 
1144     // Try to restore the selection, or at least the directory 
1145     m_dirCtrl
->ExpandPath(currentPath
); 
1148 void wxDirFilterListCtrl::FillFilterList(const wxString
& filter
, int defaultFilter
) 
1151     wxArrayString descriptions
, filters
; 
1152     size_t n 
= (size_t) m_dirCtrl
->ParseFilter(filter
, filters
, descriptions
); 
1154     if (n 
> 0 && defaultFilter 
< (int) n
) 
1157         for (i 
= 0; i 
< n
; i
++) 
1158             Append(descriptions
[i
]); 
1159         SetSelection(defaultFilter
); 
1164 // ---------------------------------------------------------------------------- 
1165 // wxFileIconsTable icons 
1166 // ---------------------------------------------------------------------------- 
1169 static const char * file_icons_tbl_folder_open_xpm
[] = { 
1170 /* width height ncolors chars_per_pixel */ 
1198 static const char * file_icons_tbl_computer_xpm
[] = { 
1225 static const char * file_icons_tbl_drive_xpm
[] = { 
1252 static const char *file_icons_tbl_cdrom_xpm
[] = { 
1282 static const char * file_icons_tbl_floppy_xpm
[] = { 
1309 static const char * file_icons_tbl_removeable_xpm
[] = { 
1335 // ---------------------------------------------------------------------------- 
1336 // wxFileIconsTable & friends 
1337 // ---------------------------------------------------------------------------- 
1339 // global instance of a wxFileIconsTable 
1340 wxFileIconsTable
* wxTheFileIconsTable 
= (wxFileIconsTable 
*)NULL
; 
1342 // A module to allow icons table cleanup 
1344 class wxFileIconsTableModule
: public wxModule
 
1346 DECLARE_DYNAMIC_CLASS(wxFileIconsTableModule
) 
1348     wxFileIconsTableModule() {} 
1349     bool OnInit() { wxTheFileIconsTable 
= new wxFileIconsTable
; return TRUE
; } 
1352         if (wxTheFileIconsTable
) 
1354             delete wxTheFileIconsTable
; 
1355             wxTheFileIconsTable 
= NULL
; 
1360 IMPLEMENT_DYNAMIC_CLASS(wxFileIconsTableModule
, wxModule
) 
1362 class wxFileIconEntry 
: public wxObject
 
1365     wxFileIconEntry(int i
) { id 
= i
; } 
1370 wxFileIconsTable::wxFileIconsTable() 
1373     m_smallImageList 
= NULL
; 
1376 wxFileIconsTable::~wxFileIconsTable() 
1380         WX_CLEAR_HASH_TABLE(*m_HashTable
); 
1383     if (m_smallImageList
) delete m_smallImageList
; 
1386 // delayed initialization - wait until first use (wxArtProv not created yet) 
1387 void wxFileIconsTable::Create() 
1389     wxCHECK_RET(!m_smallImageList 
&& !m_HashTable
, wxT("creating icons twice")); 
1390     m_HashTable 
= new wxHashTable(wxKEY_STRING
); 
1391     m_smallImageList 
= new wxImageList(16, 16); 
1394     m_smallImageList
->Add(wxArtProvider::GetBitmap(wxART_FOLDER
, wxART_CMN_DIALOG
)); 
1396     m_smallImageList
->Add(wxIcon(file_icons_tbl_folder_open_xpm
)); 
1398     m_smallImageList
->Add(wxIcon(file_icons_tbl_computer_xpm
)); 
1400     m_smallImageList
->Add(wxIcon(file_icons_tbl_drive_xpm
)); 
1402     m_smallImageList
->Add(wxIcon(file_icons_tbl_cdrom_xpm
)); 
1404     m_smallImageList
->Add(wxIcon(file_icons_tbl_floppy_xpm
)); 
1406     m_smallImageList
->Add(wxIcon(file_icons_tbl_removeable_xpm
)); 
1408     m_smallImageList
->Add(wxArtProvider::GetBitmap(wxART_NORMAL_FILE
, wxART_CMN_DIALOG
)); 
1410     if (GetIconID(wxEmptyString
, _T("application/x-executable")) == file
) 
1412         m_smallImageList
->Add(wxArtProvider::GetBitmap(wxART_EXECUTABLE_FILE
, wxART_CMN_DIALOG
)); 
1413         delete m_HashTable
->Get(_T("exe")); 
1414         m_HashTable
->Delete(_T("exe")); 
1415         m_HashTable
->Put(_T("exe"), new wxFileIconEntry(executable
)); 
1417     /* else put into list by GetIconID 
1418        (KDE defines application/x-executable for *.exe and has nice icon) 
1422 wxImageList 
*wxFileIconsTable::GetSmallImageList() 
1424     if (!m_smallImageList
) 
1427     return m_smallImageList
; 
1431 // VS: we don't need this function w/o wxMimeTypesManager because we'll only have 
1432 //     one icon and we won't resize it 
1434 static wxBitmap 
CreateAntialiasedBitmap(const wxImage
& img
) 
1436     wxImage 
smallimg (16, 16); 
1437     unsigned char *p1
, *p2
, *ps
; 
1438     unsigned char mr 
= img
.GetMaskRed(), 
1439                   mg 
= img
.GetMaskGreen(), 
1440                   mb 
= img
.GetMaskBlue(); 
1443     unsigned sr
, sg
, sb
, smask
; 
1445     p1 
= img
.GetData(), p2 
= img
.GetData() + 3 * 32, ps 
= smallimg
.GetData(); 
1446     smallimg
.SetMaskColour(mr
, mr
, mr
); 
1448     for (y 
= 0; y 
< 16; y
++) 
1450         for (x 
= 0; x 
< 16; x
++) 
1452             sr 
= sg 
= sb 
= smask 
= 0; 
1453             if (p1
[0] != mr 
|| p1
[1] != mg 
|| p1
[2] != mb
) 
1454                 sr 
+= p1
[0], sg 
+= p1
[1], sb 
+= p1
[2]; 
1457             if (p1
[0] != mr 
|| p1
[1] != mg 
|| p1
[2] != mb
) 
1458                 sr 
+= p1
[0], sg 
+= p1
[1], sb 
+= p1
[2]; 
1461             if (p2
[0] != mr 
|| p2
[1] != mg 
|| p2
[2] != mb
) 
1462                 sr 
+= p2
[0], sg 
+= p2
[1], sb 
+= p2
[2]; 
1465             if (p2
[0] != mr 
|| p2
[1] != mg 
|| p2
[2] != mb
) 
1466                 sr 
+= p2
[0], sg 
+= p2
[1], sb 
+= p2
[2]; 
1471                 ps
[0] = ps
[1] = ps
[2] = mr
; 
1473                 ps
[0] = sr 
>> 2, ps
[1] = sg 
>> 2, ps
[2] = sb 
>> 2; 
1476         p1 
+= 32 * 3, p2 
+= 32 * 3; 
1479     return wxBitmap(smallimg
); 
1482 // finds empty borders and return non-empty area of image: 
1483 static wxImage 
CutEmptyBorders(const wxImage
& img
) 
1485     unsigned char mr 
= img
.GetMaskRed(), 
1486                   mg 
= img
.GetMaskGreen(), 
1487                   mb 
= img
.GetMaskBlue(); 
1488     unsigned char *dt 
= img
.GetData(), *dttmp
; 
1489     unsigned w 
= img
.GetWidth(), h 
= img
.GetHeight(); 
1491     unsigned top
, bottom
, left
, right
, i
; 
1494 #define MK_DTTMP(x,y)      dttmp = dt + ((x + y * w) * 3) 
1495 #define NOEMPTY_PIX(empt)  if (dttmp[0] != mr || dttmp[1] != mg || dttmp[2] != mb) {empt = FALSE; break;} 
1497     for (empt 
= TRUE
, top 
= 0; empt 
&& top 
< h
; top
++) 
1500         for (i 
= 0; i 
< w
; i
++, dttmp
+=3) 
1503     for (empt 
= TRUE
, bottom 
= h
-1; empt 
&& bottom 
> top
; bottom
--) 
1505         MK_DTTMP(0, bottom
); 
1506         for (i 
= 0; i 
< w
; i
++, dttmp
+=3) 
1509     for (empt 
= TRUE
, left 
= 0; empt 
&& left 
< w
; left
++) 
1512         for (i 
= 0; i 
< h
; i
++, dttmp
+=3*w
) 
1515     for (empt 
= TRUE
, right 
= w
-1; empt 
&& right 
> left
; right
--) 
1518         for (i 
= 0; i 
< h
; i
++, dttmp
+=3*w
) 
1521     top
--, left
--, bottom
++, right
++; 
1523     return img
.GetSubImage(wxRect(left
, top
, right 
- left 
+ 1, bottom 
- top 
+ 1)); 
1525 #endif // wxUSE_MIMETYPE 
1527 int wxFileIconsTable::GetIconID(const wxString
& extension
, const wxString
& mime
) 
1529     if (!m_smallImageList
) 
1533     if (!extension
.IsEmpty()) 
1535         wxFileIconEntry 
*entry 
= (wxFileIconEntry
*) m_HashTable
->Get(extension
); 
1536         if (entry
) return (entry 
-> id
); 
1539     wxFileType 
*ft 
= (mime
.IsEmpty()) ? 
1540                    wxTheMimeTypesManager 
-> GetFileTypeFromExtension(extension
) : 
1541                    wxTheMimeTypesManager 
-> GetFileTypeFromMimeType(mime
); 
1543     wxIconLocation iconLoc
; 
1545     if ( ft 
&& ft
->GetIcon(&iconLoc
) ) 
1547         ic 
= wxIcon(iconLoc
); 
1555         m_HashTable
->Put(extension
, new wxFileIconEntry(newid
)); 
1560     tmpBmp
.CopyFromIcon(ic
); 
1561     wxImage img 
= tmpBmp
.ConvertToImage(); 
1563     int id 
= m_smallImageList
->GetImageCount(); 
1564     if (img
.GetWidth() == 16 && img
.GetHeight() == 16) 
1565         m_smallImageList
->Add(wxBitmap(img
)); 
1568         if (img
.GetWidth() != 32 || img
.GetHeight() != 32) 
1569             m_smallImageList
->Add(CreateAntialiasedBitmap(CutEmptyBorders(img
).Rescale(32, 32))); 
1571             m_smallImageList
->Add(CreateAntialiasedBitmap(img
)); 
1573     m_HashTable
->Put(extension
, new wxFileIconEntry(id
)); 
1576 #else // !wxUSE_MIMETYPE 
1578     if (extension 
== wxT("exe")) 
1582 #endif // wxUSE_MIMETYPE/!wxUSE_MIMETYPE 
1585 #endif // wxUSE_DIRDLG