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" 
  64 // If compiled under Windows, this macro can cause problems 
  69 #if !defined(__WXMSW__) || wxUSE_XPM_IN_MSW 
  71 static char * icon1_xpm
[] = { 
  72 /* width height ncolors chars_per_pixel */ 
 100 static char * icon2_xpm
[] = { 
 101 /* width height ncolors chars_per_pixel */ 
 129 static char * icon3_xpm
[] = { 
 130 /* width height ncolors chars_per_pixel */ 
 155 static char * icon4_xpm
[] = { 
 182 static char * icon5_xpm
[] = { 
 209 static char *icon6_xpm
[] = { 
 239 static char * icon7_xpm
[] = { 
 266 static char * icon8_xpm
[] = { 
 293 static const int ID_DIRCTRL 
= 1000; 
 294 static const int ID_TEXTCTRL 
= 1001; 
 295 static const int ID_OK 
= 1002; 
 296 static const int ID_CANCEL 
= 1003; 
 297 static const int ID_NEW 
= 1004; 
 298 //static const int ID_CHECK = 1005; 
 300 #if defined(__WXMSW__) 
 301 static bool wxIsDriveAvailable(const wxString dirName
) 
 304     UINT errorMode 
= SetErrorMode(SEM_FAILCRITICALERRORS 
| SEM_NOOPENFILEERRORBOX
); 
 308     // Check if this is a root directory and if so, 
 309     // whether the drive is avaiable. 
 310     if (dirName
.Len() == 3 && dirName
[(size_t)1] == wxT(':')) 
 312         wxString 
dirNameLower(dirName
.Lower()); 
 313 #if defined(__GNUWIN32__) 
 314         success 
= wxPathExists(dirNameLower
); 
 316         int currentDrive 
= _getdrive(); 
 317         int thisDrive 
= (int) (dirNameLower
[(size_t)0] - 'a' + 1) ; 
 318         int err 
= _chdrive( thisDrive 
) ; 
 319         _chdrive( currentDrive 
); 
 328     (void) SetErrorMode(errorMode
); 
 335 //----------------------------------------------------------------------------- 
 337 //----------------------------------------------------------------------------- 
 339 wxDirItemDataEx::wxDirItemDataEx(const wxString
& path
, const wxString
& name
, 
 344     /* Insert logic to detect hidden files here 
 345      * In UnixLand we just check whether the first char is a dot 
 346      * For FileNameFromPath read LastDirNameInThisPath ;-) */ 
 347     // m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.'); 
 349     // m_hasSubDirs is no longer needed 
 350     m_hasSubDirs 
= TRUE
; // HasSubDirs(); 
 351     m_isExpanded 
= FALSE
; 
 355 wxDirItemDataEx::~wxDirItemDataEx() 
 359 void wxDirItemDataEx::SetNewDirName( wxString path 
) 
 362     m_name 
= wxFileNameFromPath( path 
); 
 365 //----------------------------------------------------------------------------- 
 367 //----------------------------------------------------------------------------- 
 369 IMPLEMENT_DYNAMIC_CLASS(wxGenericDirCtrl
, wxControl
) 
 371 BEGIN_EVENT_TABLE(wxGenericDirCtrl
, wxControl
) 
 372   EVT_TREE_ITEM_EXPANDING     (-1, wxGenericDirCtrl::OnExpandItem
) 
 373   EVT_TREE_ITEM_COLLAPSED     (-1, wxGenericDirCtrl::OnCollapseItem
) 
 374   EVT_TREE_BEGIN_LABEL_EDIT   (-1, wxGenericDirCtrl::OnBeginEditItem
) 
 375   EVT_TREE_END_LABEL_EDIT     (-1, wxGenericDirCtrl::OnEndEditItem
) 
 376   EVT_SIZE                    (wxGenericDirCtrl::OnSize
) 
 379 wxGenericDirCtrl::wxGenericDirCtrl(void) 
 384 bool wxGenericDirCtrl::Create(wxWindow 
*parent
, 
 390                      const wxString
& filter
, 
 392                      const wxString
& name 
) 
 394     if (!wxControl::Create(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
)) 
 397     SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
)); 
 401     long treeStyle 
= wxTR_HAS_BUTTONS 
; // | wxTR_EDIT_LABELS; 
 402     if ((style 
& wxDIRCTRL_3D_INTERNAL
) == 0) 
 403         treeStyle 
|= wxNO_BORDER
; 
 405     long filterStyle 
= 0; 
 406     if ((style 
& wxDIRCTRL_3D_INTERNAL
) == 0) 
 407         filterStyle 
|= wxNO_BORDER
; 
 409     m_treeCtrl 
= new wxTreeCtrl(this, wxID_TREECTRL
, pos
, size
, treeStyle
); 
 411     if (!filter
.IsEmpty() && (style 
& wxDIRCTRL_SHOW_FILTERS
)) 
 412         m_filterListCtrl 
= new wxDirFilterListCtrl(this, wxID_FILTERLISTCTRL
, wxDefaultPosition
, wxDefaultSize
, filterStyle
); 
 417     SetFilterIndex(defaultFilter
); 
 419     if (m_filterListCtrl
) 
 420         m_filterListCtrl
->FillFilterList(filter
, defaultFilter
); 
 422     m_imageList 
= new wxImageList(16, 16, TRUE
); 
 423 #if !defined(__WXMSW__) || wxUSE_XPM_IN_MSW 
 424     m_imageList
->Add(wxIcon(icon1_xpm
)); 
 425     m_imageList
->Add(wxIcon(icon2_xpm
)); 
 426     m_imageList
->Add(wxIcon(icon3_xpm
)); 
 427     m_imageList
->Add(wxIcon(icon4_xpm
)); 
 428     m_imageList
->Add(wxIcon(icon5_xpm
)); 
 429     m_imageList
->Add(wxIcon(icon6_xpm
)); 
 430     m_imageList
->Add(wxIcon(icon7_xpm
)); 
 431     m_imageList
->Add(wxIcon(icon8_xpm
)); 
 432 #elif defined(__WXMSW__) 
 433     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_CLOSED_FOLDER"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 434     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_OPEN_FOLDER"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 435     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_FILE"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 436     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_COMPUTER"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 437     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_DRIVE"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 438     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_CDROM"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 439     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_FLOPPY"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 440     m_imageList
->Add(wxIcon(wxT("wxICON_SMALL_REMOVEABLE"), wxBITMAP_TYPE_ICO_RESOURCE
)); 
 442 #error "Sorry, we don't have icons available for this platforms." 
 444     m_treeCtrl
->SetImageList(m_imageList
); 
 446     m_showHidden 
= FALSE
; 
 447     wxDirItemDataEx
* rootData 
= new wxDirItemDataEx(wxT(""), wxT(""), TRUE
); 
 452     rootName 
= _("Computer"); 
 454     rootName 
= _("Sections"); 
 457     m_rootId 
= m_treeCtrl
->AddRoot( rootName
, 3, -1, rootData
); 
 458     m_treeCtrl
->SetItemHasChildren(m_rootId
); 
 459     m_treeCtrl
->Expand(m_rootId
); // automatically expand first level 
 461     // Expand and select the default path 
 462     if (!m_defaultPath
.IsEmpty()) 
 463         ExpandPath(m_defaultPath
); 
 470 wxGenericDirCtrl::~wxGenericDirCtrl() 
 472    m_treeCtrl
->SetImageList(NULL
); 
 476 void wxGenericDirCtrl::Init() 
 478     m_showHidden 
= FALSE
; 
 481     m_currentFilterStr 
= wxEmptyString
; // Default: any file 
 483     m_filterListCtrl 
= NULL
; 
 486 void wxGenericDirCtrl::AddSection(const wxString
& path
, const wxString
& name
, int imageId
) 
 488     wxDirItemDataEx 
*dir_item 
= new wxDirItemDataEx(path
,name
,TRUE
); 
 491     // Windows: sections are displayed as drives 
 492     wxTreeItemId id 
= m_treeCtrl
->AppendItem( m_rootId
, name
, imageId
, -1, dir_item
); 
 494     // Unix: sections are displayed as folders 
 495     wxTreeItemId id 
= m_treeCtrl
->AppendItem( m_rootId
, name
, 0, -1, dir_item
); 
 496     m_treeCtrl
->SetItemImage( id
, 1, wxTreeItemIcon_Expanded 
); 
 498     // TODO: other operating systems. 
 500     m_treeCtrl
->SetItemHasChildren(id
); 
 503 void wxGenericDirCtrl::SetupSections() 
 508     wxChar driveBuffer
[256]; 
 509     size_t n 
= (size_t) GetLogicalDriveStrings(255, driveBuffer
); 
 514         path
.Printf(wxT("%c:\\"), driveBuffer
[i
]); 
 515         name
.Printf(wxT("(%c:)"), driveBuffer
[i
]); 
 518         int driveType 
= ::GetDriveType(path
); 
 521             case DRIVE_REMOVABLE
: 
 522                 if (path 
== wxT("a:\\") || path 
== wxT("b:\\")) 
 523                     imageId 
= 6; // Floppy 
 541         AddSection(path
, name
, imageId
); 
 543         while (driveBuffer
[i
] != wxT('\0')) 
 546         if (driveBuffer
[i
] == wxT('\0')) 
 553     /* If we can switch to the drive, it exists. */ 
 554     for( drive 
= 1; drive 
<= 26; drive
++ ) 
 557         path
.Printf(wxT("%c:\\"), (char) (drive 
+ 'a' - 1)); 
 558         name
.Printf(wxT("(%c:)"), (char) (drive 
+ 'a' - 1)); 
 560         if (wxIsDriveAvailable(path
)) 
 563             AddSection(path
, name
); 
 569   AddSection(wxT("/"), _("The Computer"), 0); 
 570   AddSection(wxGetHomeDir(), _("My Home"), 0 ); 
 571   AddSection(wxT("/mnt"), _("Mounted Devices"), 0 ); 
 572   AddSection(wxT("/usr/local"), _("User Local"), 0 ); 
 573   AddSection(wxT("/usr"), _("User"), 0 ); 
 574   AddSection(wxT("/var"), _("Variables"), 0 ); 
 575   AddSection(wxT("/etc"), _("Etcetera"), 0 ); 
 576   AddSection(wxT("/tmp"), _("Temporary"), 0 ); 
 580 void wxGenericDirCtrl::OnBeginEditItem(wxTreeEvent 
&event
) 
 582     // don't rename the main entry "Sections" 
 583     if (event
.GetItem() == m_rootId
) 
 589     // don't rename the individual sections 
 590     if (m_treeCtrl
->GetParent( event
.GetItem() ) == m_rootId
) 
 597 void wxGenericDirCtrl::OnEndEditItem(wxTreeEvent 
&event
) 
 599     if ((event
.GetLabel().IsEmpty()) || 
 600         (event
.GetLabel() == _(".")) || 
 601         (event
.GetLabel() == _("..")) || 
 602         (event
.GetLabel().First( wxT("/") ) != wxNOT_FOUND
)) 
 604         wxMessageDialog 
dialog(this, _("Illegal directory name."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 610     wxTreeItemId id 
= event
.GetItem(); 
 611     wxDirItemDataEx 
*data 
= (wxDirItemDataEx
*)m_treeCtrl
->GetItemData( id 
); 
 614     wxString 
new_name( wxPathOnly( data
->m_path 
) ); 
 615     new_name 
+= wxString(wxFILE_SEP_PATH
); 
 616     new_name 
+= event
.GetLabel(); 
 620     if (wxFileExists(new_name
)) 
 622         wxMessageDialog 
dialog(this, _("File name exists already."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 627     if (wxRenameFile(data
->m_path
,new_name
)) 
 629         data
->SetNewDirName( new_name 
); 
 633         wxMessageDialog 
dialog(this, _("Operation not permitted."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 639 void wxGenericDirCtrl::OnExpandItem(wxTreeEvent 
&event
) 
 641     wxTreeItemId parentId 
= event
.GetItem(); 
 646 void wxGenericDirCtrl::OnCollapseItem(wxTreeEvent 
&event 
) 
 648     wxTreeItemId child
, parent 
= event
.GetItem(); 
 650     wxDirItemDataEx 
*data 
= (wxDirItemDataEx 
*) m_treeCtrl
->GetItemData(event
.GetItem()); 
 651     if (!data
->m_isExpanded
) 
 654     data
->m_isExpanded 
= FALSE
; 
 656     /* Workaround because DeleteChildren has disapeared (why?) and 
 657      * CollapseAndReset doesn't work as advertised (deletes parent too) */ 
 658     child 
= m_treeCtrl
->GetFirstChild(parent
, cookie
); 
 661         m_treeCtrl
->Delete(child
); 
 662         /* Not GetNextChild below, because the cookie mechanism can't 
 663          * handle disappearing children! */ 
 664         child 
= m_treeCtrl
->GetFirstChild(parent
, cookie
); 
 668 void wxGenericDirCtrl::ExpandDir(wxTreeItemId parentId
) 
 670     wxDirItemDataEx 
*data 
= (wxDirItemDataEx 
*) m_treeCtrl
->GetItemData(parentId
); 
 672     if (data
->m_isExpanded
) 
 675     data
->m_isExpanded 
= TRUE
; 
 677     if (parentId 
== m_rootId
) 
 685     wxString search
,path
,filename
; 
 687     wxString 
dirName(data
->m_path
); 
 690     // Check if this is a root directory and if so, 
 691     // whether the drive is avaiable. 
 692     if (!wxIsDriveAvailable(dirName
)) 
 694         data
->m_isExpanded 
= FALSE
; 
 695         //wxMessageBox(wxT("Sorry, this drive is not available.")); 
 700     // This may take a longish time. Go to busy cursor 
 704     if (dirName
.Last() == ':') 
 705         dirName 
+= wxString(wxFILE_SEP_PATH
); 
 709     wxArrayString filenames
; 
 712     wxString eachFilename
; 
 719         if (d
.GetFirst(& eachFilename
, wxEmptyString
, wxDIR_DIRS
)) 
 723                 if ((eachFilename 
!= wxT(".")) && (eachFilename 
!= wxT(".."))) 
 725                     dirs
.Add(eachFilename
); 
 728             while (d
.GetNext(& eachFilename
)) ; 
 733     // Now do the filenames -- but only if we're allowed to 
 734     if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY
) == 0) 
 742             if (d
.GetFirst(& eachFilename
, m_currentFilterStr
, wxDIR_FILES
)) 
 746                     if ((eachFilename 
!= wxT(".")) && (eachFilename 
!= wxT(".."))) 
 748                         filenames
.Add(eachFilename
); 
 751                 while (d
.GetNext(& eachFilename
)) ; 
 757     // Add the sorted dirs 
 759     for (i 
= 0; i 
< dirs
.Count(); i
++) 
 761         wxString 
eachFilename(dirs
[i
]); 
 763         if (path
.Last() != wxFILE_SEP_PATH
) 
 764             path 
+= wxString(wxFILE_SEP_PATH
); 
 765         path 
+= eachFilename
; 
 767         wxDirItemDataEx 
*dir_item 
= new wxDirItemDataEx(path
,eachFilename
,TRUE
); 
 768         wxTreeItemId id 
= m_treeCtrl
->AppendItem( parentId
, eachFilename
, 0, -1, dir_item
); 
 769         m_treeCtrl
->SetItemImage( id
, 1, wxTreeItemIcon_Expanded 
); 
 771         // Has this got any children? If so, make it expandable. 
 772         int options 
= wxDIR_DEFAULT
; 
 773         if (GetWindowStyle() & wxDIRCTRL_DIR_ONLY
) // If only showing dirs, then we specify dirs only here 
 775             options 
= wxDIR_DIRS
; 
 783             // Have to test for wxDIR_DIRS separately in case m_currentFilterStr is non-empty and 
 784             // and filters out any directories 
 785             if (dir2
.GetFirst(& str
, m_currentFilterStr
, options
) || dir2
.GetFirst(& str
, wxEmptyString
, wxDIR_DIRS
)) 
 787                 m_treeCtrl
->SetItemHasChildren(id
); 
 792     // Add the sorted filenames 
 793     if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY
) == 0) 
 795         for (i 
= 0; i 
< filenames
.Count(); i
++) 
 797             wxString 
eachFilename(filenames
[i
]); 
 799             if (path
.Last() != wxFILE_SEP_PATH
) 
 800                 path 
+= wxString(wxFILE_SEP_PATH
); 
 801             path 
+= eachFilename
; 
 802             //path = dirName + wxString(wxT("/")) + eachFilename; 
 803             wxDirItemDataEx 
*dir_item 
= new wxDirItemDataEx(path
,eachFilename
,FALSE
); 
 804             (void)m_treeCtrl
->AppendItem( parentId
, eachFilename
, 2, -1, dir_item
); 
 809 // Find the child that matches the first part of 'path'. 
 810 // E.g. if a child path is "/usr" and 'path' is "/usr/include" 
 811 // then the child for /usr is returned. 
 812 wxTreeItemId 
wxGenericDirCtrl::FindChild(wxTreeItemId parentId
, const wxString
& path
, bool& done
) 
 814     wxString 
path2(path
); 
 816     // Make sure all separators are as per the current platform 
 817     path2
.Replace(wxT("\\"), wxString(wxFILE_SEP_PATH
)); 
 818     path2
.Replace(wxT("/"), wxString(wxFILE_SEP_PATH
)); 
 820     // Append a separator to foil bogus substring matching 
 821     path2 
+= wxString(wxFILE_SEP_PATH
); 
 823     // In MSW, case is not significant 
 829     wxTreeItemId childId 
= m_treeCtrl
->GetFirstChild(parentId
, cookie
); 
 830     while (childId
.IsOk()) 
 832         wxDirItemDataEx
* data 
= (wxDirItemDataEx
*) m_treeCtrl
->GetItemData(childId
); 
 834         if (data 
&& data
->m_path 
!= "") 
 836             wxString 
childPath(data
->m_path
); 
 837             if (childPath
.Last() != wxFILE_SEP_PATH
) 
 838                 childPath 
+= wxString(wxFILE_SEP_PATH
); 
 840             // In MSW, case is not significant 
 842             childPath
.MakeLower(); 
 845             if (childPath
.Len() <= path2
.Len()) 
 847                 wxString path3 
= path2
.Mid(0, childPath
.Len()); 
 848                 if (childPath 
== path3
) 
 850                     if (path3
.Len() == path2
.Len()) 
 859         childId 
= m_treeCtrl
->GetNextChild(childId
, cookie
); 
 861     wxTreeItemId invalid
; 
 865 // Try to expand as much of the given path as possible, 
 866 // and select the given tree item. 
 867 bool wxGenericDirCtrl::ExpandPath(const wxString
& path
) 
 870     wxTreeItemId id 
= FindChild(m_rootId
, path
, done
); 
 871     wxTreeItemId lastId 
= id
; // The last non-zero id 
 872     while (id
.IsOk() && !done
) 
 876         id 
= FindChild(id
, path
, done
); 
 882         wxDirItemDataEx 
*data 
= (wxDirItemDataEx 
*) m_treeCtrl
->GetItemData(lastId
); 
 885             m_treeCtrl
->Expand(lastId
); 
 887         if ((GetWindowStyle() & wxDIRCTRL_SELECT_FIRST
) && data
->m_isDir
) 
 889             // Find the first file in this directory 
 891             wxTreeItemId childId 
= m_treeCtrl
->GetFirstChild(lastId
, cookie
); 
 892             bool selectedChild 
= FALSE
; 
 893             while (childId
.IsOk()) 
 895                 wxDirItemDataEx
* data 
= (wxDirItemDataEx
*) m_treeCtrl
->GetItemData(childId
); 
 897                 if (data 
&& data
->m_path 
!= "" && !data
->m_isDir
) 
 899                     m_treeCtrl
->SelectItem(childId
); 
 900                     m_treeCtrl
->EnsureVisible(childId
); 
 901                     selectedChild 
= TRUE
; 
 904                 childId 
= m_treeCtrl
->GetNextChild(lastId
, cookie
); 
 908                 m_treeCtrl
->SelectItem(lastId
); 
 909                 m_treeCtrl
->EnsureVisible(lastId
); 
 914             m_treeCtrl
->SelectItem(lastId
); 
 915             m_treeCtrl
->EnsureVisible(lastId
); 
 924 wxString 
wxGenericDirCtrl::GetPath() const 
 926     wxTreeItemId id 
= m_treeCtrl
->GetSelection(); 
 929         wxDirItemDataEx
* data 
= (wxDirItemDataEx
*) m_treeCtrl
->GetItemData(id
); 
 933         return wxEmptyString
; 
 936 wxString 
wxGenericDirCtrl::GetFilePath() const 
 938     wxTreeItemId id 
= m_treeCtrl
->GetSelection(); 
 941         wxDirItemDataEx
* data 
= (wxDirItemDataEx
*) m_treeCtrl
->GetItemData(id
); 
 943             return wxEmptyString
; 
 948         return wxEmptyString
; 
 951 void wxGenericDirCtrl::SetPath(const wxString
& path
) 
 953     m_defaultPath 
= path
; 
 960 void wxGenericDirCtrl::FindChildFiles(wxTreeItemId id
, int dirFlags
, wxArrayString
& filenames
) 
 962     wxDirItemDataEx 
*data 
= (wxDirItemDataEx 
*) m_treeCtrl
->GetItemData(id
); 
 964     // This may take a longish time. Go to busy cursor 
 969     wxString search
,path
,filename
; 
 971     wxString 
dirName(data
->m_path
); 
 974     if (dirName
.Last() == ':') 
 975         dirName 
+= wxString(wxFILE_SEP_PATH
); 
 979     wxString eachFilename
; 
 986         if (d
.GetFirst(& eachFilename
, m_currentFilterStr
, dirFlags
)) 
 990                 if ((eachFilename 
!= wxT(".")) && (eachFilename 
!= wxT(".."))) 
 992                     filenames
.Add(eachFilename
); 
 995             while (d
.GetNext(& eachFilename
)) ; 
1001 void wxGenericDirCtrl::SetFilterIndex(int n
) 
1003     m_currentFilter 
= n
; 
1006     if (ExtractWildcard(m_filter
, n
, f
, d
)) 
1007         m_currentFilterStr 
= f
; 
1009         m_currentFilterStr 
= wxT("*.*"); 
1012 void wxGenericDirCtrl::SetFilter(const wxString
& filter
) 
1017     if (ExtractWildcard(m_filter
, m_currentFilter
, f
, d
)) 
1018         m_currentFilterStr 
= f
; 
1020         m_currentFilterStr 
= wxT("*.*"); 
1023 // Extract description and actual filter from overall filter string 
1024 bool wxGenericDirCtrl::ExtractWildcard(const wxString
& filterStr
, int n
, wxString
& filter
, wxString
& description
) 
1026     wxArrayString filters
, descriptions
; 
1027     int count 
= ParseFilter(filterStr
, filters
, descriptions
); 
1028     if (count 
> 0 && n 
< count
) 
1030         filter 
= filters
[n
]; 
1031         description 
= descriptions
[n
]; 
1038 // Parses the global filter, returning the number of filters. 
1039 // Returns 0 if none or if there's a problem. 
1040 // filterStr is in the form: 
1042 // "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpg" 
1044 int wxGenericDirCtrl::ParseFilter(const wxString
& filterStr
, wxArrayString
& filters
, wxArrayString
& descriptions
) 
1046     wxString 
str(filterStr
); 
1048     wxString description
, filter
; 
1050     bool finished 
= FALSE
; 
1053         pos 
= str
.Find(wxT('|')); 
1055             return 0; // Problem 
1056         description 
= str
.Left(pos
); 
1057         str 
= str
.Mid(pos
+1); 
1058         pos 
= str
.Find(wxT('|')); 
1066             filter 
= str
.Left(pos
); 
1067             str 
= str
.Mid(pos
+1); 
1069         descriptions
.Add(description
); 
1070         filters
.Add(filter
); 
1074     return filters
.Count(); 
1077 void wxGenericDirCtrl::DoResize() 
1079     wxSize sz 
= GetClientSize(); 
1080     int verticalSpacing 
= 3; 
1084         if (m_filterListCtrl
) 
1086             filterSz 
= m_filterListCtrl
->GetSize(); 
1087             sz
.y 
-= (filterSz
.y 
+ verticalSpacing
); 
1089         m_treeCtrl
->SetSize(0, 0, sz
.x
, sz
.y
); 
1090         if (m_filterListCtrl
) 
1092             m_filterListCtrl
->SetSize(0, sz
.y 
+ verticalSpacing
, sz
.x
, filterSz
.y
); 
1093             // Don't know why, but this needs refreshing after a resize (wxMSW) 
1094             m_filterListCtrl
->Refresh(); 
1100 void wxGenericDirCtrl::OnSize(wxSizeEvent 
&event
) 
1105 //----------------------------------------------------------------------------- 
1106 // wxDirFilterListCtrl 
1107 //----------------------------------------------------------------------------- 
1109 IMPLEMENT_CLASS(wxDirFilterListCtrl
, wxChoice
) 
1111 BEGIN_EVENT_TABLE(wxDirFilterListCtrl
, wxChoice
) 
1112     EVT_CHOICE(-1, wxDirFilterListCtrl::OnSelFilter
) 
1115 bool wxDirFilterListCtrl::Create(wxGenericDirCtrl
* parent
, const wxWindowID id
, 
1121     return wxChoice::Create(parent
, id
, pos
, size
, 0, NULL
, style
); 
1124 void wxDirFilterListCtrl::Init() 
1129 void wxDirFilterListCtrl::OnSelFilter(wxCommandEvent
& event
) 
1131     int sel 
= GetSelection(); 
1133     wxString currentPath 
= m_dirCtrl
->GetPath(); 
1135     m_dirCtrl
->SetFilterIndex(sel
); 
1137     // If the filter has changed, the view is out of date, so 
1138     // collapse the tree. 
1139     m_dirCtrl
->GetTreeCtrl()->Collapse(m_dirCtrl
->GetRootId()); 
1140     m_dirCtrl
->GetTreeCtrl()->Expand(m_dirCtrl
->GetRootId()); 
1142     // Try to restore the selection, or at least the directory 
1143     m_dirCtrl
->ExpandPath(currentPath
); 
1146 void wxDirFilterListCtrl::FillFilterList(const wxString
& filter
, int defaultFilter
) 
1149     wxArrayString descriptions
, filters
; 
1150     size_t n 
= (size_t) m_dirCtrl
->ParseFilter(filter
, filters
, descriptions
); 
1152     if (n 
> 0 && defaultFilter 
< (int) n
) 
1155         for (i 
= 0; i 
< n
; i
++) 
1156             Append(descriptions
[i
]); 
1157         SetSelection(defaultFilter
); 
1161 // wxGenericDirDialog implementation 
1162 // This should be moved into dirdlgg.cpp eventually 
1164 BEGIN_EVENT_TABLE(wxGenericDirDialog
, wxDialog
) 
1165     EVT_BUTTON(wxID_OK
,  wxGenericDirDialog::OnOK
) 
1166     EVT_BUTTON(wxID_NEW
,  wxGenericDirDialog::OnNew
) 
1167     EVT_BUTTON               (wxID_NEW
,     wxGenericDirDialog::OnNew
) 
1168     EVT_CLOSE(wxGenericDirDialog::OnCloseWindow
) 
1169     EVT_TREE_KEY_DOWN        (-1,   wxGenericDirDialog::OnTreeKeyDown
) 
1170     EVT_TREE_SEL_CHANGED     (-1,   wxGenericDirDialog::OnTreeSelected
) 
1171     EVT_TEXT_ENTER           (ID_TEXTCTRL
,  wxGenericDirDialog::OnOK
) 
1174 wxGenericDirDialog::wxGenericDirDialog(wxWindow
* parent
, const wxString
& title
, 
1175         const wxString
& defaultPath
, long style
, const wxPoint
& pos
, const wxSize
& sz
, const wxString
& name
): 
1176    wxDialog(parent
, ID_DIRCTRL
, title
, pos
, sz
, style
, name
) 
1179     m_path 
= defaultPath
; 
1181     wxBusyCursor cursor
; 
1183     wxBoxSizer 
*topsizer 
= new wxBoxSizer( wxVERTICAL 
); 
1186     m_dirCtrl 
= new wxGenericDirCtrl(this, ID_DIRCTRL
, 
1187         defaultPath
, wxPoint(5, 5), 
1188         wxSize(300, 200), wxDIRCTRL_DIR_ONLY
|wxSUNKEN_BORDER
); 
1190     topsizer
->Add( m_dirCtrl
, 1, wxTOP
|wxLEFT
|wxRIGHT 
| wxEXPAND
, 10 ); 
1193     m_input 
= new wxTextCtrl( this, ID_TEXTCTRL
, m_path
, wxDefaultPosition 
); 
1194     topsizer
->Add( m_input
, 0, wxTOP
|wxLEFT
|wxRIGHT 
| wxEXPAND
, 10 ); 
1198     topsizer
->Add( new wxStaticLine( this, -1 ), 0, wxEXPAND 
| wxLEFT
|wxRIGHT
|wxTOP
, 10 ); 
1202     wxSizer
* buttonsizer 
= new wxBoxSizer( wxHORIZONTAL 
); 
1203     wxButton
* okButton 
= new wxButton(this, wxID_OK
, _("OK")); 
1204     buttonsizer
->Add( okButton
, 0, wxLEFT
|wxRIGHT
, 10 ); 
1205     wxButton
* cancelButton 
= new wxButton(this, wxID_CANCEL
, _("Cancel")); 
1206     buttonsizer
->Add( cancelButton
, 0, wxLEFT
|wxRIGHT
, 10 ); 
1208     // I'm not convinced we need a New button, and we tend to get annoying 
1209     // accidental-editing with label editing enabled. 
1211     wxButton
* newButton 
= new wxButton( this, wxID_NEW
, _("New...") ); 
1212     buttonsizer
->Add( newButton
, 0, wxLEFT
|wxRIGHT
, 10 ); 
1215     topsizer
->Add( buttonsizer
, 0, wxALL 
| wxCENTER
, 10 ); 
1217     okButton
->SetDefault(); 
1218     m_dirCtrl
->SetFocus(); 
1220     SetAutoLayout( TRUE 
); 
1221     SetSizer( topsizer 
); 
1223     topsizer
->SetSizeHints( this ); 
1224     topsizer
->Fit( this ); 
1229 void wxGenericDirDialog::OnCloseWindow(wxCloseEvent
& event
) 
1231     EndModal(wxID_CANCEL
); 
1234 void wxGenericDirDialog::OnOK(wxCommandEvent
& event
) 
1236     m_path 
= m_input
->GetValue(); 
1237     // Does the path exist? (User may have typed anything in m_input) 
1238     if (wxPathExists(m_path
)) { 
1239         // OK, path exists, we're done. 
1243     // Interact with user, find out if the dir is a typo or to be created 
1244     wxString 
msg( _("The directory ") ); 
1246     msg 
= msg 
+ _("\ndoes not exist\nCreate it now?") ; 
1247     wxMessageDialog 
dialog(this, msg
, _("Directory does not exist"), wxYES_NO 
| wxICON_WARNING 
); 
1248     if ( dialog
.ShowModal() == wxID_YES 
) { 
1249         // Okay, let's make it 
1251         if (wxMkdir(m_path
)) { 
1252             // The new dir was created okay. 
1258             msg 
= _("Failed to create directory ")+m_path
+ 
1259                 _("\n(Do you have the required permissions?)"); 
1260             wxMessageDialog 
errmsg(this, msg
, _("Error creating directory"), wxOK 
| wxICON_ERROR
); 
1262             // We still don't have a valid dir. Back to the main dialog. 
1265     // User has answered NO to create dir. 
1268 void wxGenericDirDialog::SetPath(const wxString
& path
) 
1270     m_dirCtrl
->SetPath(path
); 
1274 wxString 
wxGenericDirDialog::GetPath(void) const 
1279 int wxGenericDirDialog::ShowModal() 
1281     //m_input->SetValue( m_path ); 
1282     return wxDialog::ShowModal(); 
1285 void wxGenericDirDialog::OnTreeSelected( wxTreeEvent 
&event 
) 
1290     wxDirItemDataEx 
*data 
= (wxDirItemDataEx
*)m_dirCtrl
->GetTreeCtrl()->GetItemData(event
.GetItem()); 
1292        m_input
->SetValue( data
->m_path 
); 
1295 void wxGenericDirDialog::OnTreeKeyDown( wxTreeEvent 
&WXUNUSED(event
) ) 
1300     wxDirItemDataEx 
*data 
= (wxDirItemDataEx
*)m_dirCtrl
->GetTreeCtrl()->GetItemData(m_dirCtrl
->GetTreeCtrl()->GetSelection()); 
1302         m_input
->SetValue( data
->m_path 
); 
1305 void wxGenericDirDialog::OnNew( wxCommandEvent
& WXUNUSED(event
) ) 
1307     wxTreeItemId id 
= m_dirCtrl
->GetTreeCtrl()->GetSelection(); 
1308     if ((id 
== m_dirCtrl
->GetTreeCtrl()->GetRootItem()) || 
1309         (m_dirCtrl
->GetTreeCtrl()->GetParent(id
) == m_dirCtrl
->GetTreeCtrl()->GetRootItem())) 
1311         wxMessageDialog 
msg(this, _("You cannot add a new directory to this section."), 
1312                             _("Create directory"), wxOK 
| wxICON_INFORMATION 
); 
1317     wxTreeItemId parent 
= id 
; // m_dirCtrl->GetTreeCtrl()->GetParent( id ); 
1318     wxDirItemDataEx 
*data 
= (wxDirItemDataEx
*)m_dirCtrl
->GetTreeCtrl()->GetItemData( parent 
); 
1321     wxString 
new_name( wxT("NewName") ); 
1322     wxString 
path( data
->m_path 
); 
1323     if (path
.Last() != wxFILE_SEP_PATH
) 
1324         path 
+= wxFILE_SEP_PATH
; 
1326     if (wxFileExists(path
)) 
1328         // try NewName0, NewName1 etc. 
1331             new_name 
= wxT("NewName"); 
1333             num
.Printf( wxT("%d"), i 
); 
1336             path 
= data
->m_path
; 
1337             if (path
.Last() != wxFILE_SEP_PATH
) 
1338                 path 
+= wxFILE_SEP_PATH
; 
1341         } while (wxFileExists(path
)); 
1347         wxMessageDialog 
dialog(this, _("Operation not permitted."), _("Error"), wxOK 
| wxICON_ERROR 
); 
1352     wxDirItemDataEx 
*new_data 
= new wxDirItemDataEx( path
, new_name
, TRUE 
); 
1354     // TODO: THIS CODE DOESN'T WORK YET. We need to avoid duplication of the first child 
1356     wxTreeItemId new_id 
= m_dirCtrl
->GetTreeCtrl()->AppendItem( parent
, new_name
, 0, 0, new_data 
); 
1357     m_dirCtrl
->GetTreeCtrl()->EnsureVisible( new_id 
); 
1358     m_dirCtrl
->GetTreeCtrl()->EditLabel( new_id 
);