1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/generic/filectrlg.cpp 
   3 // Purpose:     wxGenericFileCtrl Implementation 
   4 // Author:      Diaa M. Sami 
   7 // Copyright:   (c) Diaa M. Sami 
   8 // Licence:     wxWindows licence 
   9 /////////////////////////////////////////////////////////////////////////////// 
  11 #include "wx/wxprec.h" 
  19 #include "wx/generic/filectrlg.h" 
  22     #include "wx/settings.h" 
  24     #include "wx/stattext.h" 
  25     #include "wx/checkbox.h" 
  26     #include "wx/msgdlg.h" 
  28     #include "wx/filedlg.h" 
  31 #include "wx/clntdata.h" 
  32 #include "wx/file.h"        // for wxS_IXXX constants only 
  33 #include "wx/generic/dirctrlg.h" // for wxFileIconsTable 
  35 #include "wx/tokenzr.h" 
  36 #include "wx/imaglist.h" 
  39     #include "wx/msw/wrapwin.h" 
  42 #if defined(__WXWINCE__) 
  43 #define IsTopMostDir(dir) (dir == wxT("\\") || dir == wxT("/")) 
  44 #elif (defined(__DOS__) || defined(__WINDOWS__) || defined (__OS2__)) 
  45 #define IsTopMostDir(dir)   (dir.empty()) 
  47 #define IsTopMostDir(dir)   (dir == wxT("/")) 
  51 // ---------------------------------------------------------------------------- 
  53 // ---------------------------------------------------------------------------- 
  56 int wxCALLBACK 
wxFileDataNameCompare( long data1
, long data2
, wxIntPtr sortOrder
) 
  58      wxFileData 
*fd1 
= (wxFileData 
*)wxUIntToPtr(data1
); 
  59      wxFileData 
*fd2 
= (wxFileData 
*)wxUIntToPtr(data2
); 
  61      if (fd1
->GetFileName() == wxT("..")) 
  63      if (fd2
->GetFileName() == wxT("..")) 
  65      if (fd1
->IsDir() && !fd2
->IsDir()) 
  67      if (fd2
->IsDir() && !fd1
->IsDir()) 
  70      return sortOrder
*wxStrcmp( fd1
->GetFileName(), fd2
->GetFileName() ); 
  74 int wxCALLBACK 
wxFileDataSizeCompare(long data1
, long data2
, wxIntPtr sortOrder
) 
  76      wxFileData 
*fd1 
= (wxFileData 
*)wxUIntToPtr(data1
); 
  77      wxFileData 
*fd2 
= (wxFileData 
*)wxUIntToPtr(data2
); 
  79      if (fd1
->GetFileName() == wxT("..")) 
  81      if (fd2
->GetFileName() == wxT("..")) 
  83      if (fd1
->IsDir() && !fd2
->IsDir()) 
  85      if (fd2
->IsDir() && !fd1
->IsDir()) 
  87      if (fd1
->IsLink() && !fd2
->IsLink()) 
  89      if (fd2
->IsLink() && !fd1
->IsLink()) 
  92      return fd1
->GetSize() > fd2
->GetSize() ? sortOrder 
: -sortOrder
; 
  96 int wxCALLBACK 
wxFileDataTypeCompare(long data1
, long data2
, wxIntPtr sortOrder
) 
  98      wxFileData 
*fd1 
= (wxFileData 
*)wxUIntToPtr(data1
); 
  99      wxFileData 
*fd2 
= (wxFileData 
*)wxUIntToPtr(data2
); 
 101      if (fd1
->GetFileName() == wxT("..")) 
 103      if (fd2
->GetFileName() == wxT("..")) 
 105      if (fd1
->IsDir() && !fd2
->IsDir()) 
 107      if (fd2
->IsDir() && !fd1
->IsDir()) 
 109      if (fd1
->IsLink() && !fd2
->IsLink()) 
 111      if (fd2
->IsLink() && !fd1
->IsLink()) 
 114      return sortOrder
*wxStrcmp( fd1
->GetFileType(), fd2
->GetFileType() ); 
 118 int wxCALLBACK 
wxFileDataTimeCompare(long data1
, long data2
, wxIntPtr sortOrder
) 
 120      wxFileData 
*fd1 
= (wxFileData 
*)wxUIntToPtr(data1
); 
 121      wxFileData 
*fd2 
= (wxFileData 
*)wxUIntToPtr(data2
); 
 123      if (fd1
->GetFileName() == wxT("..")) 
 125      if (fd2
->GetFileName() == wxT("..")) 
 127      if (fd1
->IsDir() && !fd2
->IsDir()) 
 129      if (fd2
->IsDir() && !fd1
->IsDir()) 
 132      return fd1
->GetDateTime().IsLaterThan(fd2
->GetDateTime()) ? sortOrder 
: -sortOrder
; 
 135 // defined in src/generic/dirctrlg.cpp 
 136 extern size_t wxGetAvailableDrives(wxArrayString 
&paths
, wxArrayString 
&names
, wxArrayInt 
&icon_ids
); 
 138 //----------------------------------------------------------------------------- 
 140 //----------------------------------------------------------------------------- 
 142 wxFileData::wxFileData( const wxString 
&filePath
, const wxString 
&fileName
, fileType type
, int image_id 
) 
 145     m_fileName 
= fileName
; 
 146     m_filePath 
= filePath
; 
 153 void wxFileData::Init() 
 156     m_type 
= wxFileData::is_file
; 
 157     m_image 
= wxFileIconsTable::file
; 
 160 void wxFileData::Copy( const wxFileData
& fileData 
) 
 162     m_fileName 
= fileData
.GetFileName(); 
 163     m_filePath 
= fileData
.GetFilePath(); 
 164     m_size 
= fileData
.GetSize(); 
 165     m_dateTime 
= fileData
.GetDateTime(); 
 166     m_permissions 
= fileData
.GetPermissions(); 
 167     m_type 
= fileData
.GetType(); 
 168     m_image 
= fileData
.GetImageId(); 
 171 void wxFileData::ReadData() 
 179 #if defined(__DOS__) || (defined(__WINDOWS__) && !defined(__WXWINCE__)) || defined(__OS2__) 
 180     // c:\.. is a drive don't stat it 
 181     if ((m_fileName 
== wxT("..")) && (m_filePath
.length() <= 5)) 
 187 #endif // __DOS__ || __WINDOWS__ 
 193     DWORD fileAttribs 
= GetFileAttributes(m_filePath
.fn_str()); 
 194     m_type 
|= (fileAttribs 
& FILE_ATTRIBUTE_DIRECTORY
) != 0 ? is_dir 
: 0; 
 197     wxFileName::SplitPath(m_filePath
, & p
, & f
, & ext
); 
 198     if (wxStricmp(ext
, wxT("exe")) == 0) 
 203     HANDLE fileHandle 
= CreateFile(m_filePath
.fn_str(), 
 208             FILE_ATTRIBUTE_NORMAL
, 
 211     if (fileHandle 
!= INVALID_HANDLE_VALUE
) 
 213         m_size 
= GetFileSize(fileHandle
, 0); 
 214         CloseHandle(fileHandle
); 
 217     m_dateTime 
= wxFileModificationTime(m_filePath
); 
 225 #if defined(__UNIX__) && (!defined( __OS2__ ) && !defined(__VMS)) 
 226     lstat( m_filePath
.fn_str(), &buff 
); 
 227     m_type 
|= S_ISLNK(buff
.st_mode
) ? is_link 
: 0; 
 229     // only translate to file charset if we don't go by our 
 230     // wxStat implementation 
 231 #ifndef wxNEED_WX_UNISTD_H 
 232     wxStat( m_filePath
.fn_str() , &buff 
); 
 234     wxStat( m_filePath
, &buff 
); 
 238     m_type 
|= (buff
.st_mode 
& S_IFDIR
) != 0 ? is_dir 
: 0; 
 239     m_type 
|= (buff
.st_mode 
& wxS_IXUSR
) != 0 ? is_exe 
: 0; 
 241     m_size 
= buff
.st_size
; 
 243     m_dateTime 
= buff
.st_mtime
; 
 247 #if defined(__UNIX__) 
 248     m_permissions
.Printf(wxT("%c%c%c%c%c%c%c%c%c"), 
 249                          buff
.st_mode 
& wxS_IRUSR 
? wxT('r') : wxT('-'), 
 250                          buff
.st_mode 
& wxS_IWUSR 
? wxT('w') : wxT('-'), 
 251                          buff
.st_mode 
& wxS_IXUSR 
? wxT('x') : wxT('-'), 
 252                          buff
.st_mode 
& wxS_IRGRP 
? wxT('r') : wxT('-'), 
 253                          buff
.st_mode 
& wxS_IWGRP 
? wxT('w') : wxT('-'), 
 254                          buff
.st_mode 
& wxS_IXGRP 
? wxT('x') : wxT('-'), 
 255                          buff
.st_mode 
& wxS_IROTH 
? wxT('r') : wxT('-'), 
 256                          buff
.st_mode 
& wxS_IWOTH 
? wxT('w') : wxT('-'), 
 257                          buff
.st_mode 
& wxS_IXOTH 
? wxT('x') : wxT('-')); 
 258 #elif defined(__WIN32__) 
 259     DWORD attribs 
= ::GetFileAttributes(m_filePath
.c_str()); 
 260     if (attribs 
!= (DWORD
)-1) 
 262         m_permissions
.Printf(wxT("%c%c%c%c"), 
 263                              attribs 
& FILE_ATTRIBUTE_ARCHIVE  
? wxT('A') : wxT(' '), 
 264                              attribs 
& FILE_ATTRIBUTE_READONLY 
? wxT('R') : wxT(' '), 
 265                              attribs 
& FILE_ATTRIBUTE_HIDDEN   
? wxT('H') : wxT(' '), 
 266                              attribs 
& FILE_ATTRIBUTE_SYSTEM   
? wxT('S') : wxT(' ')); 
 270     // try to get a better icon 
 271     if (m_image 
== wxFileIconsTable::file
) 
 273         if (m_fileName
.Find(wxT('.'), true) != wxNOT_FOUND
) 
 275             m_image 
= wxTheFileIconsTable
->GetIconID( m_fileName
.AfterLast(wxT('.'))); 
 278             m_image 
= wxFileIconsTable::executable
; 
 283 wxString 
wxFileData::GetFileType() const 
 291     else if (m_fileName
.Find(wxT('.'), true) != wxNOT_FOUND
) 
 292         return m_fileName
.AfterLast(wxT('.')); 
 294     return wxEmptyString
; 
 297 wxString 
wxFileData::GetModificationTime() const 
 299     // want time as 01:02 so they line up nicely, no %r in WIN32 
 300     return m_dateTime
.FormatDate() + wxT(" ") + m_dateTime
.Format(wxT("%I:%M:%S %p")); 
 303 wxString 
wxFileData::GetHint() const 
 305     wxString s 
= m_filePath
; 
 315         s 
+= wxString::Format(wxPLURAL("%ld byte", "%ld bytes", m_size
), 
 316                               wxLongLong(m_size
).ToString().c_str()); 
 322         s 
<< GetModificationTime() 
 330 wxString 
wxFileData::GetEntry( fileListFieldType num 
) const 
 340             if (!IsDir() && !IsLink() && !IsDrive()) 
 341                 s 
= wxLongLong(m_size
).ToString(); 
 350                 s 
= GetModificationTime(); 
 353 #if defined(__UNIX__) || defined(__WIN32__) 
 357 #endif // defined(__UNIX__) || defined(__WIN32__) 
 360             wxFAIL_MSG( wxT("unexpected field in wxFileData::GetEntry()") ); 
 366 void wxFileData::SetNewName( const wxString 
&filePath
, const wxString 
&fileName 
) 
 368     m_fileName 
= fileName
; 
 369     m_filePath 
= filePath
; 
 372 void wxFileData::MakeItem( wxListItem 
&item 
) 
 374     item
.m_text 
= m_fileName
; 
 375     item
.ClearAttributes(); 
 377         item
.SetTextColour(*wxRED
); 
 379         item
.SetTextColour(*wxBLUE
); 
 381     item
.m_image 
= m_image
; 
 385         wxColour dg 
= wxTheColourDatabase
->Find( wxT("MEDIUM GREY") ); 
 387             item
.SetTextColour(dg
); 
 389     item
.m_data 
= wxPtrToUInt(this); 
 392 //----------------------------------------------------------------------------- 
 394 //----------------------------------------------------------------------------- 
 396 IMPLEMENT_DYNAMIC_CLASS(wxFileListCtrl
,wxListCtrl
) 
 398 BEGIN_EVENT_TABLE(wxFileListCtrl
,wxListCtrl
) 
 399     EVT_LIST_DELETE_ITEM(wxID_ANY
, wxFileListCtrl::OnListDeleteItem
) 
 400     EVT_LIST_DELETE_ALL_ITEMS(wxID_ANY
, wxFileListCtrl::OnListDeleteAllItems
) 
 401     EVT_LIST_END_LABEL_EDIT(wxID_ANY
, wxFileListCtrl::OnListEndLabelEdit
) 
 402     EVT_LIST_COL_CLICK(wxID_ANY
, wxFileListCtrl::OnListColClick
) 
 406 wxFileListCtrl::wxFileListCtrl() 
 408     m_showHidden 
= false; 
 409     m_sort_forward 
= true; 
 410     m_sort_field 
= wxFileData::FileList_Name
; 
 413 wxFileListCtrl::wxFileListCtrl(wxWindow 
*win
, 
 415                        const wxString
& wild
, 
 420                        const wxValidator 
&validator
, 
 421                        const wxString 
&name
) 
 422           : wxListCtrl(win
, id
, pos
, size
, style
, validator
, name
), 
 425     wxImageList 
*imageList 
= wxTheFileIconsTable
->GetSmallImageList(); 
 427     SetImageList( imageList
, wxIMAGE_LIST_SMALL 
); 
 429     m_showHidden 
= showHidden
; 
 431     m_sort_forward 
= true; 
 432     m_sort_field 
= wxFileData::FileList_Name
; 
 434     m_dirName 
= wxT("*"); 
 436     if (style 
& wxLC_REPORT
) 
 437         ChangeToReportMode(); 
 440 void wxFileListCtrl::ChangeToListMode() 
 443     SetSingleStyle( wxLC_LIST 
); 
 447 void wxFileListCtrl::ChangeToReportMode() 
 450     SetSingleStyle( wxLC_REPORT 
); 
 452     // do this since WIN32 does mm/dd/yy UNIX does mm/dd/yyyy 
 453     // don't hardcode since mm/dd is dd/mm elsewhere 
 455     wxDateTime 
dt(22, wxDateTime::Dec
, 2002, 22, 22, 22); 
 456     wxString txt 
= dt
.FormatDate() + wxT("22") + dt
.Format(wxT("%I:%M:%S %p")); 
 457     GetTextExtent(txt
, &w
, &h
); 
 459     InsertColumn( 0, _("Name"), wxLIST_FORMAT_LEFT
, w 
); 
 460     InsertColumn( 1, _("Size"), wxLIST_FORMAT_LEFT
, w
/2 ); 
 461     InsertColumn( 2, _("Type"), wxLIST_FORMAT_LEFT
, w
/2 ); 
 462     InsertColumn( 3, _("Modified"), wxLIST_FORMAT_LEFT
, w 
); 
 463 #if defined(__UNIX__) 
 464     GetTextExtent(wxT("Permissions 2"), &w
, &h
); 
 465     InsertColumn( 4, _("Permissions"), wxLIST_FORMAT_LEFT
, w 
); 
 466 #elif defined(__WIN32__) 
 467     GetTextExtent(wxT("Attributes 2"), &w
, &h
); 
 468     InsertColumn( 4, _("Attributes"), wxLIST_FORMAT_LEFT
, w 
); 
 474 void wxFileListCtrl::ChangeToSmallIconMode() 
 477     SetSingleStyle( wxLC_SMALL_ICON 
); 
 481 void wxFileListCtrl::ShowHidden( bool show 
) 
 487 long wxFileListCtrl::Add( wxFileData 
*fd
, wxListItem 
&item 
) 
 490     item
.m_mask 
= wxLIST_MASK_TEXT 
+ wxLIST_MASK_DATA 
+ wxLIST_MASK_IMAGE
; 
 491     fd
->MakeItem( item 
); 
 492     long my_style 
= GetWindowStyleFlag(); 
 493     if (my_style 
& wxLC_REPORT
) 
 495         ret 
= InsertItem( item 
); 
 496         for (int i 
= 1; i 
< wxFileData::FileList_Max
; i
++) 
 497             SetItem( item
.m_itemId
, i
, fd
->GetEntry((wxFileData::fileListFieldType
)i
) ); 
 499     else if ((my_style 
& wxLC_LIST
) || (my_style 
& wxLC_SMALL_ICON
)) 
 501         ret 
= InsertItem( item 
); 
 506 void wxFileListCtrl::UpdateItem(const wxListItem 
&item
) 
 508     wxFileData 
*fd 
= (wxFileData
*)GetItemData(item
); 
 509     wxCHECK_RET(fd
, wxT("invalid filedata")); 
 513     SetItemText(item
, fd
->GetFileName()); 
 514     SetItemImage(item
, fd
->GetImageId()); 
 516     if (GetWindowStyleFlag() & wxLC_REPORT
) 
 518         for (int i 
= 1; i 
< wxFileData::FileList_Max
; i
++) 
 519             SetItem( item
.m_itemId
, i
, fd
->GetEntry((wxFileData::fileListFieldType
)i
) ); 
 523 void wxFileListCtrl::UpdateFiles() 
 525     // don't do anything before ShowModal() call which sets m_dirName 
 526     if ( m_dirName 
== wxT("*") ) 
 529     wxBusyCursor bcur
; // this may take a while... 
 537 #if (defined(__WINDOWS__) || defined(__DOS__) || defined(__WXMAC__) || defined(__OS2__)) && !defined(__WXWINCE__) 
 538     if ( IsTopMostDir(m_dirName
) ) 
 540         wxArrayString names
, paths
; 
 542         const size_t count 
= wxGetAvailableDrives(paths
, names
, icons
); 
 544         for ( size_t n 
= 0; n 
< count
; n
++ ) 
 546             // use paths[n] as the drive name too as our HandleAction() can't 
 547             // deal with the drive names (of the form "System (C:)") currently 
 548             // as it mistakenly treats them as file names 
 550             // it would be preferable to show names, and not paths, in the 
 551             // dialog just as the native dialog does but for this we must: 
 552             //  a) store the item type as item data and modify HandleAction() 
 553             //     to use it instead of wxDirExists() to check whether the item 
 555             //  b) store the drives by their drive letters and not their 
 556             //     descriptions as otherwise it's pretty confusing to the user 
 557             wxFileData 
*fd 
= new wxFileData(paths
[n
], paths
[n
], 
 558                                             wxFileData::is_drive
, icons
[n
]); 
 559             if (Add(fd
, item
) != -1) 
 566 #endif // defined(__DOS__) || defined(__WINDOWS__) 
 569         if ( !IsTopMostDir(m_dirName
) && !m_dirName
.empty() ) 
 571             wxString 
p(wxPathOnly(m_dirName
)); 
 572 #if (defined(__UNIX__) || defined(__WXWINCE__)) && !defined(__OS2__) 
 573             if (p
.empty()) p 
= wxT("/"); 
 575             wxFileData 
*fd 
= new wxFileData(p
, wxT(".."), wxFileData::is_dir
, wxFileIconsTable::folder
); 
 576             if (Add(fd
, item
) != -1) 
 582         wxString 
dirname(m_dirName
); 
 583 #if defined(__DOS__) || defined(__WINDOWS__) || defined(__OS2__) 
 584         if (dirname
.length() == 2 && dirname
[1u] == wxT(':')) 
 585             dirname 
<< wxT('\\'); 
 586 #endif // defined(__DOS__) || defined(__WINDOWS__) || defined(__OS2__) 
 589             dirname 
= wxFILE_SEP_PATH
; 
 594         if ( dir
.IsOpened() ) 
 596             wxString 
dirPrefix(dirname
); 
 597             if (dirPrefix
.Last() != wxFILE_SEP_PATH
) 
 598                 dirPrefix 
+= wxFILE_SEP_PATH
; 
 600             int hiddenFlag 
= m_showHidden 
? wxDIR_HIDDEN 
: 0; 
 605             // Get the directories first (not matched against wildcards): 
 606             cont 
= dir
.GetFirst(&f
, wxEmptyString
, wxDIR_DIRS 
| hiddenFlag
); 
 609                 wxFileData 
*fd 
= new wxFileData(dirPrefix 
+ f
, f
, wxFileData::is_dir
, wxFileIconsTable::folder
); 
 610                 if (Add(fd
, item
) != -1) 
 615                 cont 
= dir
.GetNext(&f
); 
 618             // Tokenize the wildcard string, so we can handle more than 1 
 619             // search pattern in a wildcard. 
 620             wxStringTokenizer 
tokenWild(m_wild
, wxT(";")); 
 621             while ( tokenWild
.HasMoreTokens() ) 
 623                 cont 
= dir
.GetFirst(&f
, tokenWild
.GetNextToken(), 
 624                                         wxDIR_FILES 
| hiddenFlag
); 
 627                     wxFileData 
*fd 
= new wxFileData(dirPrefix 
+ f
, f
, wxFileData::is_file
, wxFileIconsTable::file
); 
 628                     if (Add(fd
, item
) != -1) 
 633                     cont 
= dir
.GetNext(&f
); 
 639     SortItems(m_sort_field
, m_sort_forward
); 
 642 void wxFileListCtrl::SetWild( const wxString 
&wild 
) 
 644     if (wild
.Find(wxT('|')) != wxNOT_FOUND
) 
 651 void wxFileListCtrl::MakeDir() 
 653     wxString 
new_name( _("NewName") ); 
 654     wxString 
path( m_dirName 
); 
 655     path 
+= wxFILE_SEP_PATH
; 
 657     if (wxFileExists(path
)) 
 659         // try NewName0, NewName1 etc. 
 662             new_name 
= _("NewName"); 
 664             num
.Printf( wxT("%d"), i 
); 
 668             path 
+= wxFILE_SEP_PATH
; 
 671         } while (wxFileExists(path
)); 
 677         wxMessageDialog 
dialog(this, _("Operation not permitted."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 682     wxFileData 
*fd 
= new wxFileData( path
, new_name
, wxFileData::is_dir
, wxFileIconsTable::folder 
); 
 686     long id 
= Add( fd
, item 
); 
 690         SortItems(m_sort_field
, m_sort_forward
); 
 691         id 
= FindItem( 0, wxPtrToUInt(fd
) ); 
 699 void wxFileListCtrl::GoToParentDir() 
 701     if (!IsTopMostDir(m_dirName
)) 
 703         size_t len 
= m_dirName
.length(); 
 704         if (wxEndsWithPathSeparator(m_dirName
)) 
 705             m_dirName
.Remove( len
-1, 1 ); 
 706         wxString 
fname( wxFileNameFromPath(m_dirName
) ); 
 707         m_dirName 
= wxPathOnly( m_dirName 
); 
 708 #if defined(__DOS__) || defined(__WINDOWS__) || defined(__OS2__) 
 709         if (!m_dirName
.empty()) 
 711             if (m_dirName
.Last() == wxT('.')) 
 712                 m_dirName 
= wxEmptyString
; 
 714 #elif defined(__UNIX__) 
 715         if (m_dirName
.empty()) 
 716             m_dirName 
= wxT("/"); 
 719         long id 
= FindItem( 0, fname 
); 
 720         if (id 
!= wxNOT_FOUND
) 
 722             SetItemState( id
, wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED 
); 
 728 void wxFileListCtrl::GoToHomeDir() 
 730     wxString s 
= wxGetUserHome( wxString() ); 
 734 void wxFileListCtrl::GoToDir( const wxString 
&dir 
) 
 736     if (!wxDirExists(dir
)) return; 
 741     SetItemState( 0, wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED 
); 
 746 void wxFileListCtrl::FreeItemData(wxListItem
& item
) 
 750         wxFileData 
*fd 
= (wxFileData
*)item
.m_data
; 
 757 void wxFileListCtrl::OnListDeleteItem( wxListEvent 
&event 
) 
 759     FreeItemData(event
.m_item
); 
 762 void wxFileListCtrl::OnListDeleteAllItems( wxListEvent 
& WXUNUSED(event
) ) 
 767 void wxFileListCtrl::FreeAllItemsData() 
 770     item
.m_mask 
= wxLIST_MASK_DATA
; 
 772     item
.m_itemId 
= GetNextItem( -1, wxLIST_NEXT_ALL 
); 
 773     while ( item
.m_itemId 
!= -1 ) 
 777         item
.m_itemId 
= GetNextItem( item
.m_itemId
, wxLIST_NEXT_ALL 
); 
 781 void wxFileListCtrl::OnListEndLabelEdit( wxListEvent 
&event 
) 
 783     wxFileData 
*fd 
= (wxFileData
*)event
.m_item
.m_data
; 
 786     if ((event
.GetLabel().empty()) || 
 787         (event
.GetLabel() == wxT(".")) || 
 788         (event
.GetLabel() == wxT("..")) || 
 789         (event
.GetLabel().First( wxFILE_SEP_PATH 
) != wxNOT_FOUND
)) 
 791         wxMessageDialog 
dialog(this, _("Illegal directory name."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 797     wxString 
new_name( wxPathOnly( fd
->GetFilePath() ) ); 
 798     new_name 
+= wxFILE_SEP_PATH
; 
 799     new_name 
+= event
.GetLabel(); 
 803     if (wxFileExists(new_name
)) 
 805         wxMessageDialog 
dialog(this, _("File name exists already."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 810     if (wxRenameFile(fd
->GetFilePath(),new_name
)) 
 812         fd
->SetNewName( new_name
, event
.GetLabel() ); 
 814         SetItemState( event
.GetItem(), wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED 
); 
 816         UpdateItem( event
.GetItem() ); 
 817         EnsureVisible( event
.GetItem() ); 
 821         wxMessageDialog 
dialog(this, _("Operation not permitted."), _("Error"), wxOK 
| wxICON_ERROR 
); 
 827 void wxFileListCtrl::OnListColClick( wxListEvent 
&event 
) 
 829     int col 
= event
.GetColumn(); 
 833         case wxFileData::FileList_Name 
: 
 834         case wxFileData::FileList_Size 
: 
 835         case wxFileData::FileList_Type 
: 
 836         case wxFileData::FileList_Time 
: break; 
 840     if ((wxFileData::fileListFieldType
)col 
== m_sort_field
) 
 841         m_sort_forward 
= !m_sort_forward
; 
 843         m_sort_field 
= (wxFileData::fileListFieldType
)col
; 
 845     SortItems(m_sort_field
, m_sort_forward
); 
 848 void wxFileListCtrl::SortItems(wxFileData::fileListFieldType field
, bool forward
) 
 850     m_sort_field 
= field
; 
 851     m_sort_forward 
= forward
; 
 852     const long sort_dir 
= forward 
? 1 : -1; 
 854     switch (m_sort_field
) 
 856         case wxFileData::FileList_Size 
: 
 857             wxListCtrl::SortItems(wxFileDataSizeCompare
, sort_dir
); 
 860         case wxFileData::FileList_Type 
: 
 861             wxListCtrl::SortItems(wxFileDataTypeCompare
, sort_dir
); 
 864         case wxFileData::FileList_Time 
: 
 865             wxListCtrl::SortItems(wxFileDataTimeCompare
, sort_dir
); 
 868         case wxFileData::FileList_Name 
: 
 870             wxListCtrl::SortItems(wxFileDataNameCompare
, sort_dir
); 
 875 wxFileListCtrl::~wxFileListCtrl() 
 877     // Normally the data are freed via an EVT_LIST_DELETE_ALL_ITEMS event and 
 878     // wxFileListCtrl::OnListDeleteAllItems. But if the event is generated after 
 879     // the destruction of the wxFileListCtrl we need to free any data here: 
 883 #define  ID_CHOICE        (wxID_FILECTRL + 1) 
 884 #define  ID_TEXT          (wxID_FILECTRL + 2) 
 885 #define  ID_FILELIST_CTRL (wxID_FILECTRL + 3) 
 886 #define  ID_CHECK         (wxID_FILECTRL + 4) 
 888 /////////////////////////////////////////////////////////////////////////////// 
 889 // wxGenericFileCtrl implementation 
 890 /////////////////////////////////////////////////////////////////////////////// 
 892 IMPLEMENT_DYNAMIC_CLASS( wxGenericFileCtrl
, wxPanel 
) 
 894 BEGIN_EVENT_TABLE( wxGenericFileCtrl
, wxPanel 
) 
 895     EVT_LIST_ITEM_SELECTED( ID_FILELIST_CTRL
, wxGenericFileCtrl::OnSelected 
) 
 896     EVT_LIST_ITEM_ACTIVATED( ID_FILELIST_CTRL
, wxGenericFileCtrl::OnActivated 
) 
 897     EVT_CHOICE( ID_CHOICE
, wxGenericFileCtrl::OnChoiceFilter 
) 
 898     EVT_TEXT_ENTER( ID_TEXT
, wxGenericFileCtrl::OnTextEnter 
) 
 899     EVT_TEXT( ID_TEXT
, wxGenericFileCtrl::OnTextChange 
) 
 900     EVT_CHECKBOX( ID_CHECK
, wxGenericFileCtrl::OnCheck 
) 
 903 bool wxGenericFileCtrl::Create( wxWindow 
*parent
, 
 905                                 const wxString
& defaultDirectory
, 
 906                                 const wxString
& defaultFileName
, 
 907                                 const wxString
& wildCard
, 
 911                                 const wxString
& name 
) 
 913     this->m_style 
= style
; 
 914     m_inSelected 
= false; 
 915     m_noSelChgEvent 
= false; 
 918     // check that the styles are not contradictory 
 919     wxASSERT_MSG( !( ( m_style 
& wxFC_SAVE 
) && ( m_style 
& wxFC_OPEN 
) ), 
 920                   wxT( "can't specify both wxFC_SAVE and wxFC_OPEN at once" ) ); 
 922     wxASSERT_MSG( !( ( m_style 
& wxFC_SAVE 
) && ( m_style 
& wxFC_MULTIPLE 
) ), 
 923                   wxT( "wxFC_MULTIPLE can't be used with wxFC_SAVE" ) ); 
 925     wxPanel::Create( parent
, id
, pos
, size
, wxTAB_TRAVERSAL
, name 
); 
 927     m_dir 
= defaultDirectory
; 
 929     m_ignoreChanges 
= true; 
 931     if ( ( m_dir
.empty() ) || ( m_dir 
== wxT( "." ) ) ) 
 935             m_dir 
= wxFILE_SEP_PATH
; 
 938     const size_t len 
= m_dir
.length(); 
 939     if ( ( len 
> 1 ) && ( wxEndsWithPathSeparator( m_dir 
) ) ) 
 940         m_dir
.Remove( len 
- 1, 1 ); 
 942     m_filterExtension 
= wxEmptyString
; 
 946     const bool is_pda 
= ( wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA 
); 
 948     wxBoxSizer 
*mainsizer 
= new wxBoxSizer( wxVERTICAL 
); 
 950     wxBoxSizer 
*staticsizer 
= new wxBoxSizer( wxHORIZONTAL 
); 
 952         staticsizer
->Add( new wxStaticText( this, wxID_ANY
, _( "Current directory:" ) ), 
 953                           wxSizerFlags().DoubleBorder(wxRIGHT
) ); 
 954     m_static 
= new wxStaticText( this, wxID_ANY
, m_dir 
); 
 955     staticsizer
->Add( m_static
, 1 ); 
 956     mainsizer
->Add( staticsizer
, wxSizerFlags().Expand().Border()); 
 958     long style2 
= wxLC_LIST
; 
 959     if ( !( m_style 
& wxFC_MULTIPLE 
) ) 
 960         style2 
|= wxLC_SINGLE_SEL
; 
 963     style2 
|= wxSIMPLE_BORDER
; 
 965     style2 
|= wxSUNKEN_BORDER
; 
 968     m_list 
= new wxFileListCtrl( this, ID_FILELIST_CTRL
, 
 969                                  wxEmptyString
, false, 
 970                                  wxDefaultPosition
, wxSize( 400, 140 ), 
 973     m_text 
= new wxTextCtrl( this, ID_TEXT
, wxEmptyString
, 
 974                              wxDefaultPosition
, wxDefaultSize
, 
 975                              wxTE_PROCESS_ENTER 
); 
 976     m_choice 
= new wxChoice( this, ID_CHOICE 
); 
 980         // PDAs have a different screen layout 
 981         mainsizer
->Add( m_list
, wxSizerFlags( 1 ).Expand().HorzBorder() ); 
 983         wxBoxSizer 
*textsizer 
= new wxBoxSizer( wxHORIZONTAL 
); 
 984         textsizer
->Add( m_text
, wxSizerFlags( 1 ).Centre().Border() ); 
 985         textsizer
->Add( m_choice
, wxSizerFlags( 1 ).Centre().Border() ); 
 986         mainsizer
->Add( textsizer
, wxSizerFlags().Expand() ); 
 991         mainsizer
->Add( m_list
, wxSizerFlags( 1 ).Expand().Border() ); 
 992         mainsizer
->Add( m_text
, wxSizerFlags().Expand().Border() ); 
 994         wxBoxSizer 
*choicesizer 
= new wxBoxSizer( wxHORIZONTAL 
); 
 995         choicesizer
->Add( m_choice
, wxSizerFlags( 1 ).Centre() ); 
 997         if ( !( m_style 
& wxFC_NOSHOWHIDDEN 
) ) 
 999             m_check 
= new wxCheckBox( this, ID_CHECK
, _( "Show &hidden files" ) ); 
1000             choicesizer
->Add( m_check
, wxSizerFlags().Centre().DoubleBorder(wxLEFT
) ); 
1003         mainsizer
->Add( choicesizer
, wxSizerFlags().Expand().Border() ); 
1006     SetWildcard( wildCard 
); 
1008     SetAutoLayout( true ); 
1009     SetSizer( mainsizer 
); 
1013         mainsizer
->Fit( this ); 
1016     m_list
->GoToDir( m_dir 
); 
1018     m_text
->SetValue( m_fileName 
); 
1020     m_ignoreChanges 
= false; 
1022     // must be after m_ignoreChanges = false 
1023     SetFilename( defaultFileName 
); 
1028 // NB: there is an unfortunate mismatch between wxFileName and wxFileDialog 
1029 //     method names but our GetDirectory() does correspond to wxFileName:: 
1030 //     GetPath() while our GetPath() is wxFileName::GetFullPath() 
1031 wxString 
wxGenericFileCtrl::GetPath() const 
1033     wxASSERT_MSG ( !(m_style 
& wxFC_MULTIPLE
), "use GetPaths() instead" ); 
1035     return DoGetFileName().GetFullPath(); 
1038 wxString 
wxGenericFileCtrl::GetFilename() const 
1040     wxASSERT_MSG ( !(m_style 
& wxFC_MULTIPLE
), "use GetFilenames() instead" ); 
1042     return DoGetFileName().GetFullName(); 
1045 wxString 
wxGenericFileCtrl::GetDirectory() const 
1047     // don't check for wxFC_MULTIPLE here, this one is probably safe to call in 
1048     // any case as it can be always taken to mean "current directory" 
1049     return DoGetFileName().GetPath(); 
1052 wxFileName 
wxGenericFileCtrl::DoGetFileName() const 
1056     wxString value 
= m_text
->GetValue(); 
1057     if ( value
.empty() ) 
1059         // nothing in the text control, get the selected file from the list 
1061         item
.m_itemId 
= m_list
->GetNextItem(-1, wxLIST_NEXT_ALL
, 
1062                                             wxLIST_STATE_SELECTED
); 
1063         m_list
->GetItem(item
); 
1065         fn
.Assign(m_list
->GetDir(), item
.m_text
); 
1067     else // user entered the value 
1069         // the path can be either absolute or relative 
1071         if ( fn
.IsRelative() ) 
1072             fn
.MakeAbsolute(m_list
->GetDir()); 
1078 // helper used in DoGetFilenames() and needed because Borland can't compile 
1079 // operator?: inline 
1080 static inline wxString 
GetFileNameOrPath(const wxFileName
& fn
, bool fullPath
) 
1082     return fullPath 
? fn
.GetFullPath() : fn
.GetFullName(); 
1086 wxGenericFileCtrl::DoGetFilenames(wxArrayString
& filenames
, bool fullPath
) const 
1090     const wxString dir 
= m_list
->GetDir(); 
1092     const wxString value 
= m_text
->GetValue(); 
1093     if ( !value
.empty() ) 
1095         wxFileName 
fn(value
); 
1096         if ( fn
.IsRelative() ) 
1097             fn
.MakeAbsolute(dir
); 
1099         filenames
.push_back(GetFileNameOrPath(fn
, fullPath
)); 
1103     const int numSel 
= m_list
->GetSelectedItemCount(); 
1107     filenames
.reserve(numSel
); 
1110     item
.m_mask 
= wxLIST_MASK_TEXT
; 
1114         item
.m_itemId 
= m_list
->GetNextItem(item
.m_itemId
, wxLIST_NEXT_ALL
, 
1115                                             wxLIST_STATE_SELECTED
); 
1117         if ( item
.m_itemId 
== -1 ) 
1120         m_list
->GetItem(item
); 
1122         const wxFileName 
fn(dir
, item
.m_text
); 
1123         filenames
.push_back(GetFileNameOrPath(fn
, fullPath
)); 
1127 bool wxGenericFileCtrl::SetDirectory( const wxString
& dir 
) 
1129     m_ignoreChanges 
= true; 
1130     m_list
->GoToDir( dir 
); 
1132     m_ignoreChanges 
= false; 
1134     return wxFileName( dir 
).SameAs( m_list
->GetDir() ); 
1137 bool wxGenericFileCtrl::SetFilename( const wxString
& name 
) 
1139     const long item 
= m_list
->FindItem( -1, name 
); 
1141     if ( item 
== -1 ) // file not found either because it doesn't exist or the 
1142         // current filter doesn't show it. 
1145     m_noSelChgEvent 
= true; 
1147     // Deselect selected items 
1149         const int numSelectedItems 
= m_list
->GetSelectedItemCount(); 
1151         if ( numSelectedItems 
> 0 ) 
1153             long itemIndex 
= -1; 
1157                 itemIndex 
= m_list
->GetNextItem( itemIndex
, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED 
); 
1158                 if ( itemIndex 
== -1 ) 
1161                 m_list
->SetItemState( itemIndex
, 0, wxLIST_STATE_SELECTED 
); 
1166     m_list
->SetItemState( item
, wxLIST_STATE_SELECTED
, wxLIST_STATE_SELECTED 
); 
1167     m_list
->EnsureVisible( item 
); 
1169     m_noSelChgEvent 
= false; 
1174 void wxGenericFileCtrl::DoSetFilterIndex( int filterindex 
) 
1176     wxClientData 
*pcd 
= m_choice
->GetClientObject( filterindex 
); 
1180     const wxString
& str 
= ((static_cast<wxStringClientData 
*>(pcd
))->GetData()); 
1181     m_list
->SetWild( str 
); 
1182     m_filterIndex 
= filterindex
; 
1183     if ( str
.Left( 2 ) == wxT( "*." ) ) 
1185         m_filterExtension 
= str
.Mid( 1 ); 
1186         if ( m_filterExtension 
== wxT( ".*" ) ) 
1187             m_filterExtension
.clear(); 
1191         m_filterExtension
.clear(); 
1195 void wxGenericFileCtrl::SetWildcard( const wxString
& wildCard 
) 
1197     if ( wildCard
.empty() || wildCard 
== wxFileSelectorDefaultWildcardStr 
) 
1199         m_wildCard 
= wxString::Format( _( "All files (%s)|%s" ), 
1200                                        wxFileSelectorDefaultWildcardStr
, 
1201                                        wxFileSelectorDefaultWildcardStr 
); 
1204         m_wildCard 
= wildCard
; 
1206     wxArrayString wildDescriptions
, wildFilters
; 
1207     const size_t count 
= wxParseCommonDialogsFilter( m_wildCard
, 
1210     wxCHECK_RET( count
, wxT( "wxFileDialog: bad wildcard string" ) ); 
1214     for ( size_t n 
= 0; n 
< count
; n
++ ) 
1216         m_choice
->Append(wildDescriptions
[n
], new wxStringClientData(wildFilters
[n
])); 
1219     SetFilterIndex( 0 ); 
1222 void wxGenericFileCtrl::SetFilterIndex( int filterindex 
) 
1224     m_choice
->SetSelection( filterindex 
); 
1226     DoSetFilterIndex( filterindex 
); 
1229 void wxGenericFileCtrl::OnChoiceFilter( wxCommandEvent 
&event 
) 
1231     DoSetFilterIndex( ( int )event
.GetInt() ); 
1234 void wxGenericFileCtrl::OnCheck( wxCommandEvent 
&event 
) 
1236     m_list
->ShowHidden( event
.GetInt() != 0 ); 
1239 void wxGenericFileCtrl::OnActivated( wxListEvent 
&event 
) 
1241     HandleAction( event
.m_item
.m_text 
); 
1244 void wxGenericFileCtrl::OnTextEnter( wxCommandEvent 
&WXUNUSED( event 
) ) 
1246     HandleAction( m_text
->GetValue() ); 
1249 void wxGenericFileCtrl::OnTextChange( wxCommandEvent 
&WXUNUSED( event 
) ) 
1251     if ( !m_ignoreChanges 
) 
1253         // Clear selections.  Otherwise when the user types in a value they may 
1254         // not get the file whose name they typed. 
1255         if ( m_list
->GetSelectedItemCount() > 0 ) 
1257             long item 
= m_list
->GetNextItem( -1, wxLIST_NEXT_ALL
, 
1258                                              wxLIST_STATE_SELECTED 
); 
1259             while ( item 
!= -1 ) 
1261                 m_list
->SetItemState( item
, 0, wxLIST_STATE_SELECTED 
); 
1262                 item 
= m_list
->GetNextItem( item
, wxLIST_NEXT_ALL
, wxLIST_STATE_SELECTED 
); 
1268 void wxGenericFileCtrl::OnSelected( wxListEvent 
&event 
) 
1270     if ( m_ignoreChanges 
) 
1276     m_inSelected 
= true; 
1277     const wxString 
filename( event
.m_item
.m_text 
); 
1280     // No double-click on most WinCE devices, so do action immediately. 
1281     HandleAction( filename 
); 
1283     if ( filename 
== wxT( ".." ) ) 
1285         m_inSelected 
= false; 
1289     wxString dir 
= m_list
->GetDir(); 
1290     if ( !IsTopMostDir( dir 
) ) 
1291         dir 
+= wxFILE_SEP_PATH
; 
1293     if ( wxDirExists( dir 
) ) 
1295         m_inSelected 
= false; 
1301     m_ignoreChanges 
= true; 
1302     m_text
->SetValue( filename 
); 
1304     if ( m_list
->GetSelectedItemCount() > 1 ) 
1309     if ( !m_noSelChgEvent 
) 
1310         GenerateSelectionChangedEvent( this, this ); 
1312     m_ignoreChanges 
= false; 
1314     m_inSelected 
= false; 
1317 void wxGenericFileCtrl::HandleAction( const wxString 
&fn 
) 
1319     if ( m_ignoreChanges 
) 
1322     wxString 
filename( fn 
); 
1323     if ( filename
.empty() ) 
1327     if ( filename 
== wxT( "." ) ) return; 
1329     wxString dir 
= m_list
->GetDir(); 
1331     // "some/place/" means they want to chdir not try to load "place" 
1332     const bool want_dir 
= filename
.Last() == wxFILE_SEP_PATH
; 
1334         filename 
= filename
.RemoveLast(); 
1336     if ( filename 
== wxT( ".." ) ) 
1338         m_ignoreChanges 
= true; 
1339         m_list
->GoToParentDir(); 
1341         GenerateFolderChangedEvent( this, this ); 
1344         m_ignoreChanges 
= false; 
1349     if ( filename 
== wxT( "~" ) ) 
1351         m_ignoreChanges 
= true; 
1352         m_list
->GoToHomeDir(); 
1354         GenerateFolderChangedEvent( this, this ); 
1357         m_ignoreChanges 
= false; 
1361     if ( filename
.BeforeFirst( wxT( '/' ) ) == wxT( "~" ) ) 
1363         filename 
= wxString( wxGetUserHome() ) + filename
.Remove( 0, 1 ); 
1367     if ( !( m_style 
& wxFC_SAVE 
) ) 
1369         if ( ( filename
.Find( wxT( '*' ) ) != wxNOT_FOUND 
) || 
1370                 ( filename
.Find( wxT( '?' ) ) != wxNOT_FOUND 
) ) 
1372             if ( filename
.Find( wxFILE_SEP_PATH 
) != wxNOT_FOUND 
) 
1374                 wxMessageBox( _( "Illegal file specification." ), 
1375                               _( "Error" ), wxOK 
| wxICON_ERROR
, this ); 
1378             m_list
->SetWild( filename 
); 
1383     if ( !IsTopMostDir( dir 
) ) 
1384         dir 
+= wxFILE_SEP_PATH
; 
1385     if ( !wxIsAbsolutePath( filename 
) ) 
1391     if ( wxDirExists( filename 
) ) 
1393         m_ignoreChanges 
= true; 
1394         m_list
->GoToDir( filename 
); 
1397         GenerateFolderChangedEvent( this, this ); 
1399         m_ignoreChanges 
= false; 
1403     // they really wanted a dir, but it doesn't exist 
1406         wxMessageBox( _( "Directory doesn't exist." ), _( "Error" ), 
1407                       wxOK 
| wxICON_ERROR
, this ); 
1411     // append the default extension to the filename if it doesn't have any 
1413     // VZ: the logic of testing for !wxFileExists() only for the open file 
1414     //     dialog is not entirely clear to me, why don't we allow saving to a 
1415     //     file without extension as well? 
1416     if ( !( m_style 
& wxFC_OPEN 
) || !wxFileExists( filename 
) ) 
1418         filename 
= wxFileDialogBase::AppendExtension( filename
, m_filterExtension 
); 
1419         GenerateFileActivatedEvent( this, this, wxFileName( filename 
).GetFullName() ); 
1423     GenerateFileActivatedEvent( this, this ); 
1426 bool wxGenericFileCtrl::SetPath( const wxString
& path 
) 
1428     if ( !wxFileName::FileExists( ( path 
) ) ) 
1432     wxFileName::SplitPath( path
, &m_dir
, &m_fileName
, &ext 
); 
1435         m_fileName 
+= wxT( "." ); 
1439     SetDirectory( m_dir 
); 
1440     SetFilename( m_fileName 
); 
1445 void wxGenericFileCtrl::GetPaths( wxArrayString
& paths 
) const 
1447     DoGetFilenames( paths
, true ); 
1450 void wxGenericFileCtrl::GetFilenames( wxArrayString
& files 
) const 
1452     DoGetFilenames( files
, false ); 
1455 void wxGenericFileCtrl::UpdateControls() 
1457     const wxString dir 
= m_list
->GetDir(); 
1458     m_static
->SetLabel( dir 
); 
1461 void wxGenericFileCtrl::GoToParentDir() 
1463     m_list
->GoToParentDir(); 
1467 void wxGenericFileCtrl::GoToHomeDir() 
1469     m_list
->GoToHomeDir(); 
1473 #endif // wxUSE_FILECTRL