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" 
  26 #include "wx/dialog.h" 
  27 #include "wx/button.h" 
  28 #include "wx/layout.h" 
  29 #include "wx/msgdlg.h" 
  30 #include "wx/textdlg.h" 
  31 #include "wx/filefn.h" 
  32 #include "wx/cmndata.h" 
  33 #include "wx/gdicmn.h" 
  35 #include "wx/imaglist.h" 
  39 #include "wx/tokenzr.h" 
  41 #include "wx/settings.h" 
  44     #include "wx/statline.h" 
  47 #include "wx/generic/dirctrlg.h" 
  74 // If compiled under Windows, this macro can cause problems 
  79 #if !defined(__WXMSW__) || wxUSE_XPM_IN_MSW || wxUSE_XPM_IN_OS2 
  81 static char * icon1_xpm
[] = { 
  82 /* width height ncolors chars_per_pixel */ 
 110 static char * icon2_xpm
[] = { 
 111 /* width height ncolors chars_per_pixel */ 
 139 static char * icon3_xpm
[] = { 
 140 /* width height ncolors chars_per_pixel */ 
 165 static char * icon4_xpm
[] = { 
 192 static char * icon5_xpm
[] = { 
 219 static char *icon6_xpm
[] = { 
 249 static char * icon7_xpm
[] = { 
 276 static char * icon8_xpm
[] = { 
 303 static const int ID_DIRCTRL 
= 1000; 
 304 static const int ID_TEXTCTRL 
= 1001; 
 305 static const int ID_OK 
= 1002; 
 306 static const int ID_CANCEL 
= 1003; 
 307 static const int ID_NEW 
= 1004; 
 308 //static const int ID_CHECK = 1005; 
 310 #if defined(__WXMSW__) || defined(__WXPM__) 
 311 int setdrive(int drive
) 
 315         if (drive 
< 1 || drive 
> 31) 
 317         newdrive
[0] = (char)('A' + (char)drive 
- (char)1); 
 320         if (SetCurrentDirectory((LPSTR
)newdrive
)) 
 326 static bool wxIsDriveAvailable(const wxString dirName
) 
 329     UINT errorMode 
= SetErrorMode(SEM_FAILCRITICALERRORS 
| SEM_NOOPENFILEERRORBOX
); 
 333     // Check if this is a root directory and if so, 
 334     // whether the drive is avaiable. 
 335     if (dirName
.Len() == 3 && dirName
[(size_t)1] == wxT(':')) 
 337         wxString 
dirNameLower(dirName
.Lower()); 
 338 #if defined(__GNUWIN32__) 
 339         success 
= wxPathExists(dirNameLower
); 
 341         int currentDrive 
= _getdrive(); 
 342         int thisDrive 
= (int) (dirNameLower
[(size_t)0] - 'a' + 1) ; 
 343         int err 
= setdrive( thisDrive 
) ; 
 344         setdrive( currentDrive 
); 
 353     (void) SetErrorMode(errorMode
); 
 360 //----------------------------------------------------------------------------- 
 362 //----------------------------------------------------------------------------- 
 364 wxDirItemDataEx::wxDirItemDataEx(const wxString
& path
, const wxString
& name
, 
 369     /* Insert logic to detect hidden files here 
 370      * In UnixLand we just check whether the first char is a dot 
 371      * For FileNameFromPath read LastDirNameInThisPath ;-) */ 
 372     // m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.'); 
 374     // m_hasSubDirs is no longer needed 
 375     m_hasSubDirs 
= TRUE
; // HasSubDirs(); 
 376     m_isExpanded 
= FALSE
; 
 380 wxDirItemDataEx::~wxDirItemDataEx() 
 384 void wxDirItemDataEx::SetNewDirName( wxString path 
) 
 387     m_name 
= wxFileNameFromPath( path 
); 
 390 //----------------------------------------------------------------------------- 
 392 //----------------------------------------------------------------------------- 
 394 IMPLEMENT_DYNAMIC_CLASS(wxGenericDirCtrl
, wxControl
) 
 396 BEGIN_EVENT_TABLE(wxGenericDirCtrl
, wxControl
) 
 397   EVT_TREE_ITEM_EXPANDING     (-1, wxGenericDirCtrl::OnExpandItem
) 
 398   EVT_TREE_ITEM_COLLAPSED     (-1, wxGenericDirCtrl::OnCollapseItem
) 
 399   EVT_TREE_BEGIN_LABEL_EDIT   (-1, wxGenericDirCtrl::OnBeginEditItem
) 
 400   EVT_TREE_END_LABEL_EDIT     (-1, wxGenericDirCtrl::OnEndEditItem
) 
 401   EVT_SIZE                    (wxGenericDirCtrl::OnSize
) 
 404 wxGenericDirCtrl::wxGenericDirCtrl(void) 
 409 bool wxGenericDirCtrl::Create(wxWindow 
*parent
, 
 415                      const wxString
& filter
, 
 417                      const wxString
& name 
) 
 419     if (!wxControl::Create(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
)) 
 422     SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
)); 
 426     long treeStyle 
= wxTR_HAS_BUTTONS 
; // | wxTR_EDIT_LABELS; 
 427     if ((style 
& wxDIRCTRL_3D_INTERNAL
) == 0) 
 428         treeStyle 
|= wxNO_BORDER
; 
 430     long filterStyle 
= 0; 
 431     if ((style 
& wxDIRCTRL_3D_INTERNAL
) == 0) 
 432         filterStyle 
|= wxNO_BORDER
; 
 434     m_treeCtrl 
= new wxTreeCtrl(this, wxID_TREECTRL
, pos
, size
, treeStyle
); 
 436     if (!filter
.IsEmpty() && (style 
& wxDIRCTRL_SHOW_FILTERS
)) 
 437         m_filterListCtrl 
= new wxDirFilterListCtrl(this, wxID_FILTERLISTCTRL
, wxDefaultPosition
, wxDefaultSize
, filterStyle
); 
 442     SetFilterIndex(defaultFilter
); 
 444     if (m_filterListCtrl
) 
 445         m_filterListCtrl
->FillFilterList(filter
, defaultFilter
); 
 447     m_imageList 
= new wxImageList(16, 16, TRUE
); 
 448 #if !defined(__WXMSW__) || wxUSE_XPM_IN_MSW 
 449     m_imageList
->Add(wxIcon(icon1_xpm
)); 
 450     m_imageList
->Add(wxIcon(icon2_xpm
)); 
 451     m_imageList
->Add(wxIcon(icon3_xpm
)); 
 452     m_imageList
->Add(wxIcon(icon4_xpm
)); 
 453     m_imageList
->Add(wxIcon(icon5_xpm
)); 
 454     m_imageList
->Add(wxIcon(icon6_xpm
)); 
 455     m_imageList
->Add(wxIcon(icon7_xpm
)); 
 456     m_imageList
->Add(wxIcon(icon8_xpm
)); 
 457 #elif defined(__WXMSW__) 
 458     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_CLOSED_FOLDER"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 459     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_OPEN_FOLDER"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 460     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_FILE"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 461     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_COMPUTER"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 462     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_DRIVE"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 463     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_CDROM"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 464     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_FLOPPY"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 465     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_REMOVEABLE"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 467 #error "Sorry, we don't have icons available for this platforms." 
 469     m_treeCtrl
->SetImageList(m_imageList
); 
 471     m_showHidden 
= FALSE
; 
 472     wxDirItemDataEx
* rootData 
= new wxDirItemDataEx(wxT(""), wxT(""), TRUE
); 
 476 #if defined(__WXMSW__) || defined(__WXPM__) 
 477     rootName 
= _("Computer"); 
 479     rootName 
= _("Sections"); 
 482     m_rootId 
= m_treeCtrl
->AddRoot( rootName
, 3, -1, rootData
); 
 483     m_treeCtrl
->SetItemHasChildren(m_rootId
); 
 484     m_treeCtrl
->Expand(m_rootId
); // automatically expand first level 
 486     // Expand and select the default path 
 487     if (!m_defaultPath
.IsEmpty()) 
 488         ExpandPath(m_defaultPath
); 
 495 wxGenericDirCtrl::~wxGenericDirCtrl() 
 497    m_treeCtrl
->SetImageList(NULL
); 
 501 void wxGenericDirCtrl::Init() 
 503     m_showHidden 
= FALSE
; 
 506     m_currentFilterStr 
= wxEmptyString
; // Default: any file 
 508     m_filterListCtrl 
= NULL
; 
 511 void wxGenericDirCtrl::AddSection(const wxString
& path
, const wxString
& name
, int imageId
) 
 513     wxDirItemDataEx 
*dir_item 
= new wxDirItemDataEx(path
,name
,TRUE
); 
 515 #if defined(__WXMSW__) || defined(__WXPM__) 
 516     // Windows and OS/2: sections are displayed as drives 
 517     wxTreeItemId id 
= m_treeCtrl
->AppendItem( m_rootId
, name
, imageId
, -1, dir_item
); 
 519     // Unix: sections are displayed as folders 
 520     wxTreeItemId id 
= m_treeCtrl
->AppendItem( m_rootId
, name
, 0, -1, dir_item
); 
 521     m_treeCtrl
->SetItemImage( id
, 1, wxTreeItemIcon_Expanded 
); 
 523     // TODO: other operating systems. 
 525     m_treeCtrl
->SetItemHasChildren(id
); 
 528 void wxGenericDirCtrl::SetupSections() 
 530 #if defined(__WXMSW__) || defined(__WXPM__) 
 533     wxChar driveBuffer
[256]; 
 534     size_t n 
= (size_t) GetLogicalDriveStrings(255, driveBuffer
); 
 539         path
.Printf(wxT("%c:\\"), driveBuffer
[i
]); 
 540         name
.Printf(wxT("(%c:)"), driveBuffer
[i
]); 
 543         int driveType 
= ::GetDriveType(path
); 
 546             case DRIVE_REMOVABLE
: 
 547                 if (path 
== wxT("a:\\") || path 
== wxT("b:\\")) 
 548                     imageId 
= 6; // Floppy 
 566         AddSection(path
, name
, imageId
); 
 568         while (driveBuffer
[i
] != wxT('\0')) 
 571         if (driveBuffer
[i
] == wxT('\0')) 
 578     /* If we can switch to the drive, it exists. */ 
 579     for( drive 
= 1; drive 
<= 26; drive
++ ) 
 582         path
.Printf(wxT("%c:\\"), (char) (drive 
+ 'a' - 1)); 
 583         name
.Printf(wxT("(%c:)"), (char) (drive 
+ 'a' - 1)); 
 585         if (wxIsDriveAvailable(path
)) 
 588             AddSection(path
, name
); 
 594   AddSection(wxT("/"), _("The Computer"), 0); 
 595   AddSection(wxGetHomeDir(), _("My Home"), 0 ); 
 596   AddSection(wxT("/mnt"), _("Mounted Devices"), 0 ); 
 597   AddSection(wxT("/usr/local"), _("User Local"), 0 ); 
 598   AddSection(wxT("/usr"), _("User"), 0 ); 
 599   AddSection(wxT("/var"), _("Variables"), 0 ); 
 600   AddSection(wxT("/etc"), _("Etcetera"), 0 ); 
 601   AddSection(wxT("/tmp"), _("Temporary"), 0 ); 
 605 void wxGenericDirCtrl::OnBeginEditItem(wxTreeEvent 
&event
) 
 607     // don't rename the main entry "Sections" 
 608     if (event
.GetItem() == m_rootId
) 
 614     // don't rename the individual sections 
 615     if (m_treeCtrl
->GetParent( event
.GetItem() ) == m_rootId
) 
 622 void wxGenericDirCtrl::OnEndEditItem(wxTreeEvent 
&event
) 
 624     if ((event
.GetLabel().IsEmpty()) || 
 625         (event
.GetLabel() == _(".")) || 
 626         (event
.GetLabel() == _("..")) || 
 627         (event
.GetLabel().First( wxT("/") ) != wxNOT_FOUND
)) 
 629         wxMessageDialog 
dialog(this, _("Illegal directory name."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 635     wxTreeItemId id 
= event
.GetItem(); 
 636     wxDirItemDataEx 
*data 
= (wxDirItemDataEx
*)m_treeCtrl
->GetItemData( id 
); 
 639     wxString 
new_name( wxPathOnly( data
->m_path 
) ); 
 640     new_name 
+= wxString(wxFILE_SEP_PATH
); 
 641     new_name 
+= event
.GetLabel(); 
 645     if (wxFileExists(new_name
)) 
 647         wxMessageDialog 
dialog(this, _("File name exists already."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 652     if (wxRenameFile(data
->m_path
,new_name
)) 
 654         data
->SetNewDirName( new_name 
); 
 658         wxMessageDialog 
dialog(this, _("Operation not permitted."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 664 void wxGenericDirCtrl::OnExpandItem(wxTreeEvent 
&event
) 
 666     wxTreeItemId parentId 
= event
.GetItem(); 
 671 void wxGenericDirCtrl::OnCollapseItem(wxTreeEvent 
&event 
) 
 673     wxTreeItemId child
, parent 
= event
.GetItem(); 
 675     wxDirItemDataEx 
*data 
= (wxDirItemDataEx 
*) m_treeCtrl
->GetItemData(event
.GetItem()); 
 676     if (!data
->m_isExpanded
) 
 679     data
->m_isExpanded 
= FALSE
; 
 681     /* Workaround because DeleteChildren has disapeared (why?) and 
 682      * CollapseAndReset doesn't work as advertised (deletes parent too) */ 
 683     child 
= m_treeCtrl
->GetFirstChild(parent
, cookie
); 
 686         m_treeCtrl
->Delete(child
); 
 687         /* Not GetNextChild below, because the cookie mechanism can't 
 688          * handle disappearing children! */ 
 689         child 
= m_treeCtrl
->GetFirstChild(parent
, cookie
); 
 693 void wxGenericDirCtrl::ExpandDir(wxTreeItemId parentId
) 
 695     wxDirItemDataEx 
*data 
= (wxDirItemDataEx 
*) m_treeCtrl
->GetItemData(parentId
); 
 697     if (data
->m_isExpanded
) 
 700     data
->m_isExpanded 
= TRUE
; 
 702     if (parentId 
== m_rootId
) 
 710     wxString search
,path
,filename
; 
 712     wxString 
dirName(data
->m_path
); 
 714 #if defined(__WXMSW__) || defined(__WXPM__) 
 715     // Check if this is a root directory and if so, 
 716     // whether the drive is avaiable. 
 717     if (!wxIsDriveAvailable(dirName
)) 
 719         data
->m_isExpanded 
= FALSE
; 
 720         //wxMessageBox(wxT("Sorry, this drive is not available.")); 
 725     // This may take a longish time. Go to busy cursor 
 728 #if defined(__WXMSW__) || defined(__WXPM__) 
 729     if (dirName
.Last() == ':') 
 730         dirName 
+= wxString(wxFILE_SEP_PATH
); 
 734     wxArrayString filenames
; 
 737     wxString eachFilename
; 
 744         if (d
.GetFirst(& eachFilename
, wxEmptyString
, wxDIR_DIRS
)) 
 748                 if ((eachFilename 
!= wxT(".")) && (eachFilename 
!= wxT(".."))) 
 750                     dirs
.Add(eachFilename
); 
 753             while (d
.GetNext(& eachFilename
)) ; 
 758     // Now do the filenames -- but only if we're allowed to 
 759     if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY
) == 0) 
 767             if (d
.GetFirst(& eachFilename
, m_currentFilterStr
, wxDIR_FILES
)) 
 771                     if ((eachFilename 
!= wxT(".")) && (eachFilename 
!= wxT(".."))) 
 773                         filenames
.Add(eachFilename
); 
 776                 while (d
.GetNext(& eachFilename
)) ; 
 782     // Add the sorted dirs 
 784     for (i 
= 0; i 
< dirs
.Count(); i
++) 
 786         wxString 
eachFilename(dirs
[i
]); 
 788         if (path
.Last() != wxFILE_SEP_PATH
) 
 789             path 
+= wxString(wxFILE_SEP_PATH
); 
 790         path 
+= eachFilename
; 
 792         wxDirItemDataEx 
*dir_item 
= new wxDirItemDataEx(path
,eachFilename
,TRUE
); 
 793         wxTreeItemId id 
= m_treeCtrl
->AppendItem( parentId
, eachFilename
, 0, -1, dir_item
); 
 794         m_treeCtrl
->SetItemImage( id
, 1, wxTreeItemIcon_Expanded 
); 
 796         // Has this got any children? If so, make it expandable. 
 797         int options 
= wxDIR_DEFAULT
; 
 798         if (GetWindowStyle() & wxDIRCTRL_DIR_ONLY
) // If only showing dirs, then we specify dirs only here 
 800             options 
= wxDIR_DIRS
; 
 808             // Have to test for wxDIR_DIRS separately in case m_currentFilterStr is non-empty and 
 809             // and filters out any directories 
 810             if (dir2
.GetFirst(& str
, m_currentFilterStr
, options
) || dir2
.GetFirst(& str
, wxEmptyString
, wxDIR_DIRS
)) 
 812                 m_treeCtrl
->SetItemHasChildren(id
); 
 817     // Add the sorted filenames 
 818     if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY
) == 0) 
 820         for (i 
= 0; i 
< filenames
.Count(); i
++) 
 822             wxString 
eachFilename(filenames
[i
]); 
 824             if (path
.Last() != wxFILE_SEP_PATH
) 
 825                 path 
+= wxString(wxFILE_SEP_PATH
); 
 826             path 
+= eachFilename
; 
 827             //path = dirName + wxString(wxT("/")) + eachFilename; 
 828             wxDirItemDataEx 
*dir_item 
= new wxDirItemDataEx(path
,eachFilename
,FALSE
); 
 829             (void)m_treeCtrl
->AppendItem( parentId
, eachFilename
, 2, -1, dir_item
); 
 834 // Find the child that matches the first part of 'path'. 
 835 // E.g. if a child path is "/usr" and 'path' is "/usr/include" 
 836 // then the child for /usr is returned. 
 837 wxTreeItemId 
wxGenericDirCtrl::FindChild(wxTreeItemId parentId
, const wxString
& path
, bool& done
) 
 839     wxString 
path2(path
); 
 841     // Make sure all separators are as per the current platform 
 842     path2
.Replace(wxT("\\"), wxString(wxFILE_SEP_PATH
)); 
 843     path2
.Replace(wxT("/"), wxString(wxFILE_SEP_PATH
)); 
 845     // Append a separator to foil bogus substring matching 
 846     path2 
+= wxString(wxFILE_SEP_PATH
); 
 848     // In MSW or PM, case is not significant 
 849 #if defined(__WXMSW__) || defined(__WXPM__) 
 854     wxTreeItemId childId 
= m_treeCtrl
->GetFirstChild(parentId
, cookie
); 
 855     while (childId
.IsOk()) 
 857         wxDirItemDataEx
* data 
= (wxDirItemDataEx
*) m_treeCtrl
->GetItemData(childId
); 
 859         if (data 
&& data
->m_path 
!= "") 
 861             wxString 
childPath(data
->m_path
); 
 862             if (childPath
.Last() != wxFILE_SEP_PATH
) 
 863                 childPath 
+= wxString(wxFILE_SEP_PATH
); 
 865             // In MSW and PM, case is not significant 
 866 #if defined(__WXMSW__) || defined(__WXPM__) 
 867             childPath
.MakeLower(); 
 870             if (childPath
.Len() <= path2
.Len()) 
 872                 wxString path3 
= path2
.Mid(0, childPath
.Len()); 
 873                 if (childPath 
== path3
) 
 875                     if (path3
.Len() == path2
.Len()) 
 884         childId 
= m_treeCtrl
->GetNextChild(childId
, cookie
); 
 886     wxTreeItemId invalid
; 
 890 // Try to expand as much of the given path as possible, 
 891 // and select the given tree item. 
 892 bool wxGenericDirCtrl::ExpandPath(const wxString
& path
) 
 895     wxTreeItemId id 
= FindChild(m_rootId
, path
, done
); 
 896     wxTreeItemId lastId 
= id
; // The last non-zero id 
 897     while (id
.IsOk() && !done
) 
 901         id 
= FindChild(id
, path
, done
); 
 907         wxDirItemDataEx 
*data 
= (wxDirItemDataEx 
*) m_treeCtrl
->GetItemData(lastId
); 
 910             m_treeCtrl
->Expand(lastId
); 
 912         if ((GetWindowStyle() & wxDIRCTRL_SELECT_FIRST
) && data
->m_isDir
) 
 914             // Find the first file in this directory 
 916             wxTreeItemId childId 
= m_treeCtrl
->GetFirstChild(lastId
, cookie
); 
 917             bool selectedChild 
= FALSE
; 
 918             while (childId
.IsOk()) 
 920                 wxDirItemDataEx
* data 
= (wxDirItemDataEx
*) m_treeCtrl
->GetItemData(childId
); 
 922                 if (data 
&& data
->m_path 
!= "" && !data
->m_isDir
) 
 924                     m_treeCtrl
->SelectItem(childId
); 
 925                     m_treeCtrl
->EnsureVisible(childId
); 
 926                     selectedChild 
= TRUE
; 
 929                 childId 
= m_treeCtrl
->GetNextChild(lastId
, cookie
); 
 933                 m_treeCtrl
->SelectItem(lastId
); 
 934                 m_treeCtrl
->EnsureVisible(lastId
); 
 939             m_treeCtrl
->SelectItem(lastId
); 
 940             m_treeCtrl
->EnsureVisible(lastId
); 
 949 wxString 
wxGenericDirCtrl::GetPath() const 
 951     wxTreeItemId id 
= m_treeCtrl
->GetSelection(); 
 954         wxDirItemDataEx
* data 
= (wxDirItemDataEx
*) m_treeCtrl
->GetItemData(id
); 
 958         return wxEmptyString
; 
 961 wxString 
wxGenericDirCtrl::GetFilePath() const 
 963     wxTreeItemId id 
= m_treeCtrl
->GetSelection(); 
 966         wxDirItemDataEx
* data 
= (wxDirItemDataEx
*) m_treeCtrl
->GetItemData(id
); 
 968             return wxEmptyString
; 
 973         return wxEmptyString
; 
 976 void wxGenericDirCtrl::SetPath(const wxString
& path
) 
 978     m_defaultPath 
= path
; 
 985 void wxGenericDirCtrl::FindChildFiles(wxTreeItemId id
, int dirFlags
, wxArrayString
& filenames
) 
 987     wxDirItemDataEx 
*data 
= (wxDirItemDataEx 
*) m_treeCtrl
->GetItemData(id
); 
 989     // This may take a longish time. Go to busy cursor 
 994     wxString search
,path
,filename
; 
 996     wxString 
dirName(data
->m_path
); 
 998 #if defined(__WXMSW__) || defined(__WXPM__) 
 999     if (dirName
.Last() == ':') 
1000         dirName 
+= wxString(wxFILE_SEP_PATH
); 
1004     wxString eachFilename
; 
1011         if (d
.GetFirst(& eachFilename
, m_currentFilterStr
, dirFlags
)) 
1015                 if ((eachFilename 
!= wxT(".")) && (eachFilename 
!= wxT(".."))) 
1017                     filenames
.Add(eachFilename
); 
1020             while (d
.GetNext(& eachFilename
)) ; 
1026 void wxGenericDirCtrl::SetFilterIndex(int n
) 
1028     m_currentFilter 
= n
; 
1031     if (ExtractWildcard(m_filter
, n
, f
, d
)) 
1032         m_currentFilterStr 
= f
; 
1034         m_currentFilterStr 
= wxT("*.*"); 
1037 void wxGenericDirCtrl::SetFilter(const wxString
& filter
) 
1042     if (ExtractWildcard(m_filter
, m_currentFilter
, f
, d
)) 
1043         m_currentFilterStr 
= f
; 
1045         m_currentFilterStr 
= wxT("*.*"); 
1048 // Extract description and actual filter from overall filter string 
1049 bool wxGenericDirCtrl::ExtractWildcard(const wxString
& filterStr
, int n
, wxString
& filter
, wxString
& description
) 
1051     wxArrayString filters
, descriptions
; 
1052     int count 
= ParseFilter(filterStr
, filters
, descriptions
); 
1053     if (count 
> 0 && n 
< count
) 
1055         filter 
= filters
[n
]; 
1056         description 
= descriptions
[n
]; 
1063 // Parses the global filter, returning the number of filters. 
1064 // Returns 0 if none or if there's a problem. 
1065 // filterStr is in the form: 
1067 // "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpg" 
1069 int wxGenericDirCtrl::ParseFilter(const wxString
& filterStr
, wxArrayString
& filters
, wxArrayString
& descriptions
) 
1071     wxString 
str(filterStr
); 
1073     wxString description
, filter
; 
1075     bool finished 
= FALSE
; 
1078         pos 
= str
.Find(wxT('|')); 
1080             return 0; // Problem 
1081         description 
= str
.Left(pos
); 
1082         str 
= str
.Mid(pos
+1); 
1083         pos 
= str
.Find(wxT('|')); 
1091             filter 
= str
.Left(pos
); 
1092             str 
= str
.Mid(pos
+1); 
1094         descriptions
.Add(description
); 
1095         filters
.Add(filter
); 
1099     return filters
.Count(); 
1102 void wxGenericDirCtrl::DoResize() 
1104     wxSize sz 
= GetClientSize(); 
1105     int verticalSpacing 
= 3; 
1109         if (m_filterListCtrl
) 
1111             filterSz 
= m_filterListCtrl
->GetSize(); 
1112             sz
.y 
-= (filterSz
.y 
+ verticalSpacing
); 
1114         m_treeCtrl
->SetSize(0, 0, sz
.x
, sz
.y
); 
1115         if (m_filterListCtrl
) 
1117             m_filterListCtrl
->SetSize(0, sz
.y 
+ verticalSpacing
, sz
.x
, filterSz
.y
); 
1118             // Don't know why, but this needs refreshing after a resize (wxMSW) 
1119             m_filterListCtrl
->Refresh(); 
1125 void wxGenericDirCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
1130 //----------------------------------------------------------------------------- 
1131 // wxDirFilterListCtrl 
1132 //----------------------------------------------------------------------------- 
1134 IMPLEMENT_CLASS(wxDirFilterListCtrl
, wxChoice
) 
1136 BEGIN_EVENT_TABLE(wxDirFilterListCtrl
, wxChoice
) 
1137     EVT_CHOICE(-1, wxDirFilterListCtrl::OnSelFilter
) 
1140 bool wxDirFilterListCtrl::Create(wxGenericDirCtrl
* parent
, const wxWindowID id
, 
1146     return wxChoice::Create(parent
, id
, pos
, size
, 0, NULL
, style
); 
1149 void wxDirFilterListCtrl::Init() 
1154 void wxDirFilterListCtrl::OnSelFilter(wxCommandEvent
& WXUNUSED(event
)) 
1156     int sel 
= GetSelection(); 
1158     wxString currentPath 
= m_dirCtrl
->GetPath(); 
1160     m_dirCtrl
->SetFilterIndex(sel
); 
1162     // If the filter has changed, the view is out of date, so 
1163     // collapse the tree. 
1164     m_dirCtrl
->GetTreeCtrl()->Collapse(m_dirCtrl
->GetRootId()); 
1165     m_dirCtrl
->GetTreeCtrl()->Expand(m_dirCtrl
->GetRootId()); 
1167     // Try to restore the selection, or at least the directory 
1168     m_dirCtrl
->ExpandPath(currentPath
); 
1171 void wxDirFilterListCtrl::FillFilterList(const wxString
& filter
, int defaultFilter
) 
1174     wxArrayString descriptions
, filters
; 
1175     size_t n 
= (size_t) m_dirCtrl
->ParseFilter(filter
, filters
, descriptions
); 
1177     if (n 
> 0 && defaultFilter 
< (int) n
) 
1180         for (i 
= 0; i 
< n
; i
++) 
1181             Append(descriptions
[i
]); 
1182         SetSelection(defaultFilter
); 
1186 // wxGenericDirDialog implementation 
1187 // This should be moved into dirdlgg.cpp eventually 
1189 BEGIN_EVENT_TABLE(wxGenericDirDialog
, wxDialog
) 
1190     EVT_BUTTON(wxID_OK
,  wxGenericDirDialog::OnOK
) 
1191     EVT_BUTTON(wxID_NEW
,  wxGenericDirDialog::OnNew
) 
1192     EVT_BUTTON               (wxID_NEW
,     wxGenericDirDialog::OnNew
) 
1193     EVT_CLOSE(wxGenericDirDialog::OnCloseWindow
) 
1194     EVT_TREE_KEY_DOWN        (-1,   wxGenericDirDialog::OnTreeKeyDown
) 
1195     EVT_TREE_SEL_CHANGED     (-1,   wxGenericDirDialog::OnTreeSelected
) 
1196     EVT_TEXT_ENTER           (ID_TEXTCTRL
,  wxGenericDirDialog::OnOK
) 
1199 wxGenericDirDialog::wxGenericDirDialog(wxWindow
* parent
, const wxString
& title
, 
1200         const wxString
& defaultPath
, long style
, const wxPoint
& pos
, const wxSize
& sz
, const wxString
& name
): 
1201    wxDialog(parent
, ID_DIRCTRL
, title
, pos
, sz
, style
, name
) 
1204     m_path 
= defaultPath
; 
1206     wxBusyCursor cursor
; 
1208     wxBoxSizer 
*topsizer 
= new wxBoxSizer( wxVERTICAL 
); 
1211     m_dirCtrl 
= new wxGenericDirCtrl(this, ID_DIRCTRL
, 
1212         defaultPath
, wxPoint(5, 5), 
1213         wxSize(300, 200), wxDIRCTRL_DIR_ONLY
|wxSUNKEN_BORDER
); 
1215     topsizer
->Add( m_dirCtrl
, 1, wxTOP
|wxLEFT
|wxRIGHT 
| wxEXPAND
, 10 ); 
1218     m_input 
= new wxTextCtrl( this, ID_TEXTCTRL
, m_path
, wxDefaultPosition 
); 
1219     topsizer
->Add( m_input
, 0, wxTOP
|wxLEFT
|wxRIGHT 
| wxEXPAND
, 10 ); 
1223     topsizer
->Add( new wxStaticLine( this, -1 ), 0, wxEXPAND 
| wxLEFT
|wxRIGHT
|wxTOP
, 10 ); 
1227     wxSizer
* buttonsizer 
= new wxBoxSizer( wxHORIZONTAL 
); 
1228     wxButton
* okButton 
= new wxButton(this, wxID_OK
, _("OK")); 
1229     buttonsizer
->Add( okButton
, 0, wxLEFT
|wxRIGHT
, 10 ); 
1230     wxButton
* cancelButton 
= new wxButton(this, wxID_CANCEL
, _("Cancel")); 
1231     buttonsizer
->Add( cancelButton
, 0, wxLEFT
|wxRIGHT
, 10 ); 
1233     // I'm not convinced we need a New button, and we tend to get annoying 
1234     // accidental-editing with label editing enabled. 
1236     wxButton
* newButton 
= new wxButton( this, wxID_NEW
, _("New...") ); 
1237     buttonsizer
->Add( newButton
, 0, wxLEFT
|wxRIGHT
, 10 ); 
1240     topsizer
->Add( buttonsizer
, 0, wxALL 
| wxCENTER
, 10 ); 
1242     okButton
->SetDefault(); 
1243     m_dirCtrl
->SetFocus(); 
1245     SetAutoLayout( TRUE 
); 
1246     SetSizer( topsizer 
); 
1248     topsizer
->SetSizeHints( this ); 
1249     topsizer
->Fit( this ); 
1254 void wxGenericDirDialog::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
)) 
1256     EndModal(wxID_CANCEL
); 
1259 void wxGenericDirDialog::OnOK(wxCommandEvent
& WXUNUSED(event
)) 
1261     m_path 
= m_input
->GetValue(); 
1262     // Does the path exist? (User may have typed anything in m_input) 
1263     if (wxPathExists(m_path
)) { 
1264         // OK, path exists, we're done. 
1268     // Interact with user, find out if the dir is a typo or to be created 
1269     wxString 
msg( _("The directory ") ); 
1271     msg 
= msg 
+ _("\ndoes not exist\nCreate it now?") ; 
1272     wxMessageDialog 
dialog(this, msg
, _("Directory does not exist"), wxYES_NO 
| wxICON_WARNING 
); 
1273     if ( dialog
.ShowModal() == wxID_YES 
) { 
1274         // Okay, let's make it 
1276         if (wxMkdir(m_path
)) { 
1277             // The new dir was created okay. 
1283             msg 
= _("Failed to create directory ")+m_path
+ 
1284                 _("\n(Do you have the required permissions?)"); 
1285             wxMessageDialog 
errmsg(this, msg
, _("Error creating directory"), wxOK 
| wxICON_ERROR
); 
1287             // We still don't have a valid dir. Back to the main dialog. 
1290     // User has answered NO to create dir. 
1293 void wxGenericDirDialog::SetPath(const wxString
& path
) 
1295     m_dirCtrl
->SetPath(path
); 
1299 wxString 
wxGenericDirDialog::GetPath(void) const 
1304 int wxGenericDirDialog::ShowModal() 
1306     //m_input->SetValue( m_path ); 
1307     return wxDialog::ShowModal(); 
1310 void wxGenericDirDialog::OnTreeSelected( wxTreeEvent 
&event 
) 
1315     wxDirItemDataEx 
*data 
= (wxDirItemDataEx
*)m_dirCtrl
->GetTreeCtrl()->GetItemData(event
.GetItem()); 
1317        m_input
->SetValue( data
->m_path 
); 
1320 void wxGenericDirDialog::OnTreeKeyDown( wxTreeEvent 
&WXUNUSED(event
) ) 
1325     wxDirItemDataEx 
*data 
= (wxDirItemDataEx
*)m_dirCtrl
->GetTreeCtrl()->GetItemData(m_dirCtrl
->GetTreeCtrl()->GetSelection()); 
1327         m_input
->SetValue( data
->m_path 
); 
1330 void wxGenericDirDialog::OnNew( wxCommandEvent
& WXUNUSED(event
) ) 
1332     wxTreeItemId id 
= m_dirCtrl
->GetTreeCtrl()->GetSelection(); 
1333     if ((id 
== m_dirCtrl
->GetTreeCtrl()->GetRootItem()) || 
1334         (m_dirCtrl
->GetTreeCtrl()->GetParent(id
) == m_dirCtrl
->GetTreeCtrl()->GetRootItem())) 
1336         wxMessageDialog 
msg(this, _("You cannot add a new directory to this section."), 
1337                             _("Create directory"), wxOK 
| wxICON_INFORMATION 
); 
1342     wxTreeItemId parent 
= id 
; // m_dirCtrl->GetTreeCtrl()->GetParent( id ); 
1343     wxDirItemDataEx 
*data 
= (wxDirItemDataEx
*)m_dirCtrl
->GetTreeCtrl()->GetItemData( parent 
); 
1346     wxString 
new_name( wxT("NewName") ); 
1347     wxString 
path( data
->m_path 
); 
1348     if (path
.Last() != wxFILE_SEP_PATH
) 
1349         path 
+= wxFILE_SEP_PATH
; 
1351     if (wxFileExists(path
)) 
1353         // try NewName0, NewName1 etc. 
1356             new_name 
= wxT("NewName"); 
1358             num
.Printf( wxT("%d"), i 
); 
1361             path 
= data
->m_path
; 
1362             if (path
.Last() != wxFILE_SEP_PATH
) 
1363                 path 
+= wxFILE_SEP_PATH
; 
1366         } while (wxFileExists(path
)); 
1372         wxMessageDialog 
dialog(this, _("Operation not permitted."), _("Error"), wxOK 
| wxICON_ERROR 
); 
1377     wxDirItemDataEx 
*new_data 
= new wxDirItemDataEx( path
, new_name
, TRUE 
); 
1379     // TODO: THIS CODE DOESN'T WORK YET. We need to avoid duplication of the first child 
1381     wxTreeItemId new_id 
= m_dirCtrl
->GetTreeCtrl()->AppendItem( parent
, new_name
, 0, 0, new_data 
); 
1382     m_dirCtrl
->GetTreeCtrl()->EnsureVisible( new_id 
); 
1383     m_dirCtrl
->GetTreeCtrl()->EditLabel( new_id 
);