home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / generic / dirctrlg.cpp < prev    next >
C/C++ Source or Header  |  2003-01-03  |  34KB  |  1,278 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        dirctrlg.cpp
  3. // Purpose:     wxGenericDirCtrl
  4. // Author:      Harm van der Heijden, Robert Roebling, Julian Smart
  5. // Modified by:
  6. // Created:     12/12/98
  7. // RCS-ID:      $Id: dirctrlg.cpp,v 1.48.2.2 2002/12/29 07:48:17 RL Exp $
  8. // Copyright:   (c) Harm van der Heijden, Robert Roebling and Julian Smart
  9. // Licence:     wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation "dirctrlg.h"
  14. #endif
  15.  
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18.  
  19. #ifdef __BORLANDC__
  20. #pragma hdrstop
  21. #endif
  22.  
  23. #if wxUSE_DIRDLG
  24.  
  25. #include "wx/utils.h"
  26. #include "wx/dialog.h"
  27. #include "wx/button.h"
  28. #include "wx/layout.h"
  29. #include "wx/msgdlg.h"
  30. #include "wx/textctrl.h"
  31. #include "wx/textdlg.h"
  32. #include "wx/filefn.h"
  33. #include "wx/cmndata.h"
  34. #include "wx/gdicmn.h"
  35. #include "wx/intl.h"
  36. #include "wx/imaglist.h"
  37. #include "wx/icon.h"
  38. #include "wx/log.h"
  39. #include "wx/sizer.h"
  40. #include "wx/tokenzr.h"
  41. #include "wx/dir.h"
  42. #include "wx/settings.h"
  43.  
  44. #if wxUSE_STATLINE
  45.     #include "wx/statline.h"
  46. #endif
  47.  
  48. #include "wx/generic/dirctrlg.h"
  49.  
  50. #if defined(__WXMAC__)
  51.   #include  "wx/mac/private.h"  // includes mac headers
  52. #endif
  53.  
  54. #ifdef __WXMSW__
  55. #include <windows.h>
  56.  
  57. // FIXME - Mingw32 1.0 has both _getdrive() and _chdrive(). For now, let's assume
  58. //         older releases don't, but it should be verified and the checks modified
  59. //         accordingly.
  60. #if !defined(__WXWINE__) && (!defined(__GNUWIN32__) || \
  61.     (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1))
  62.   #include <direct.h>
  63.   #include <stdlib.h>
  64.   #include <ctype.h>
  65. #endif
  66.  
  67. #endif
  68.  
  69. #ifdef __WXPM__
  70.  
  71. #define INCL_BASE
  72. #include <os2.h>
  73. #ifndef __EMX__
  74. #include <direct.h>
  75. #endif
  76. #include <stdlib.h>
  77. #include <ctype.h>
  78.  
  79. #endif // __WXPM__
  80.  
  81. #if defined(__WXMAC__)
  82. #  include "MoreFilesExtras.h"
  83. #endif
  84.  
  85. #ifdef __BORLANDC__
  86. #include "dos.h"
  87. #endif
  88.  
  89. // If compiled under Windows, this macro can cause problems
  90. #ifdef GetFirstChild
  91. #undef GetFirstChild
  92. #endif
  93.  
  94. /* Closed folder */
  95. static const char * icon1_xpm[] = {
  96. /* width height ncolors chars_per_pixel */
  97. "16 16 6 1",
  98. /* colors */
  99. "   s None  c None",
  100. ".  c #000000",
  101. "+  c #c0c0c0",
  102. "@  c #808080",
  103. "#  c #ffff00",
  104. "$  c #ffffff",
  105. /* pixels */
  106. "                ",
  107. "   @@@@@        ",
  108. "  @#+#+#@       ",
  109. " @#+#+#+#@@@@@@ ",
  110. " @$$$$$$$$$$$$@.",
  111. " @$#+#+#+#+#+#@.",
  112. " @$+#+#+#+#+#+@.",
  113. " @$#+#+#+#+#+#@.",
  114. " @$+#+#+#+#+#+@.",
  115. " @$#+#+#+#+#+#@.",
  116. " @$+#+#+#+#+#+@.",
  117. " @$#+#+#+#+#+#@.",
  118. " @@@@@@@@@@@@@@.",
  119. "  ..............",
  120. "                ",
  121. "                "};
  122.  
  123. /* Open folder */
  124. static const char * icon2_xpm[] = {
  125. /* width height ncolors chars_per_pixel */
  126. "16 16 6 1",
  127. /* colors */
  128. "   s None  c None",
  129. ".  c #000000",
  130. "+  c #c0c0c0",
  131. "@  c #808080",
  132. "#  c #ffff00",
  133. "$  c #ffffff",
  134. /* pixels */
  135. "                ",
  136. "   @@@@@        ",
  137. "  @$$$$$@       ",
  138. " @$#+#+#$@@@@@@ ",
  139. " @$+#+#+$$$$$$@.",
  140. " @$#+#+#+#+#+#@.",
  141. "@@@@@@@@@@@@@#@.",
  142. "@$$$$$$$$$$@@+@.",
  143. "@$#+#+#+#+##.@@.",
  144. " @$#+#+#+#+#+.@.",
  145. " @$+#+#+#+#+#.@.",
  146. "  @$+#+#+#+##@..",
  147. "  @@@@@@@@@@@@@.",
  148. "   .............",
  149. "                ",
  150. "                "};
  151.  
  152. /* File */
  153. static const char * icon3_xpm[] = {
  154. /* width height ncolors chars_per_pixel */
  155. "16 16 3 1",
  156. /* colors */
  157. "     s None    c None",
  158. ".    c #000000",
  159. "+    c #ffffff",
  160. /* pixels */
  161. "                ",
  162. "  ........      ",
  163. "  .++++++..     ",
  164. "  .+.+.++.+.    ",
  165. "  .++++++....   ",
  166. "  .+.+.+++++.   ",
  167. "  .+++++++++.   ",
  168. "  .+.+.+.+.+.   ",
  169. "  .+++++++++.   ",
  170. "  .+.+.+.+.+.   ",
  171. "  .+++++++++.   ",
  172. "  .+.+.+.+.+.   ",
  173. "  .+++++++++.   ",
  174. "  ...........   ",
  175. "                ",
  176. "                "};
  177.  
  178. /* Computer */
  179. static const char * icon4_xpm[] = {
  180. "16 16 7 1",
  181. "     s None    c None",
  182. ".    c #808080",
  183. "X    c #c0c0c0",
  184. "o    c Black",
  185. "O    c Gray100",
  186. "+    c #008080",
  187. "@    c Blue",
  188. "    ........... ",
  189. "   .XXXXXXXXXX.o",
  190. "   .OOOOOOOOO..o",
  191. "   .OoooooooX..o",
  192. "   .Oo+...@+X..o",
  193. "   .Oo+XXX.+X..o",
  194. "   .Oo+....+X..o",
  195. "   .Oo++++++X..o",
  196. "   .OXXXXXXXX.oo",
  197. "   ..........o.o",
  198. "   ...........Xo",
  199. "   .XXXXXXXXXX.o",
  200. "  .o.o.o.o.o...o",
  201. " .oXoXoXoXoXo.o ",
  202. ".XOXXXXXXXXX.o  ",
  203. "............o   "};
  204.  
  205. /* Drive */
  206. static const char * icon5_xpm[] = {
  207. "16 16 7 1",
  208. "     s None    c None",
  209. ".    c #808080",
  210. "X    c #c0c0c0",
  211. "o    c Black",
  212. "O    c Gray100",
  213. "+    c Green",
  214. "@    c #008000",
  215. "                ",
  216. "                ",
  217. "                ",
  218. "                ",
  219. "  ............. ",
  220. " .XXXXXXXXXXXX.o",
  221. ".OOOOOOOOOOOO..o",
  222. ".XXXXXXXXX+@X..o",
  223. ".XXXXXXXXXXXX..o",
  224. ".X..........X..o",
  225. ".XOOOOOOOOOOX..o",
  226. "..............o ",
  227. " ooooooooooooo  ",
  228. "                ",
  229. "                ",
  230. "                "};
  231.  
  232. /* CD-ROM */
  233. static const char *icon6_xpm[] = {
  234. "16 16 10 1",
  235. "     s None    c None",
  236. ".    c #808080",
  237. "X    c #c0c0c0",
  238. "o    c Yellow",
  239. "O    c Blue",
  240. "+    c Black",
  241. "@    c Gray100",
  242. "#    c #008080",
  243. "$    c Green",
  244. "%    c #008000",
  245. "        ...     ",
  246. "      ..XoX..   ",
  247. "     .O.XoXXX+  ",
  248. "    ...O.oXXXX+ ",
  249. "    .O..X.XXXX+ ",
  250. "   ....X.+..XXX+",
  251. "   .XXX.+@+.XXX+",
  252. "   .X@XX.+.X@@X+",
  253. " .....X...#XX@+ ",
  254. ".@@@...XXo.O@X+ ",
  255. ".@XXX..XXoXOO+  ",
  256. ".@++++..XoX+++  ",
  257. ".@$%@@XX+++X.+  ",
  258. ".............+  ",
  259. " ++++++++++++   ",
  260. "                "};
  261.  
  262. /* Floppy */
  263. static const char * icon7_xpm[] = {
  264. "16 16 7 1",
  265. "     s None    c None",
  266. ".    c #808080",
  267. "X    c Gray100",
  268. "o    c #c0c0c0",
  269. "O    c Black",
  270. "+    c Cyan",
  271. "@    c Red",
  272. "         ......X",
  273. "        .ooooooO",
  274. "        .+++++OO",
  275. "        .++++++O",
  276. "        .++++++O",
  277. "        .ooooooO",
  278. "  .......o....oO",
  279. " .oooooo.o.O.XoO",
  280. ".XXXXXXXXOOOOOO ",
  281. ".ooooooooo@o..O ",
  282. ".ooo....oooo..O ",
  283. ".o..OOOO...o..O ",
  284. ".oooXXXXoooo..O ",
  285. ".............O  ",
  286. " OOOOOOOOOOOO   ",
  287. "                "};
  288.  
  289. /* Removeable */
  290. static const char * icon8_xpm[] = {
  291. "16 16 7 1",
  292. "     s None    c None",
  293. ".    c #808080",
  294. "X    c #c0c0c0",
  295. "o    c Black",
  296. "O    c Gray100",
  297. "+    c Red",
  298. "@    c #800000",
  299. "                ",
  300. "                ",
  301. "                ",
  302. "  ............. ",
  303. " .XXXXXXXXXXXX.o",
  304. ".OOOOOOOOOOOO..o",
  305. ".OXXXXXXXXXXX..o",
  306. ".O+@.oooooo.X..o",
  307. ".OXXOooooooOX..o",
  308. ".OXXXOOOOOOXX..o",
  309. ".OXXXXXXXXXXX..o",
  310. ".O............o ",
  311. " ooooooooooooo  ",
  312. "                ",
  313. "                ",
  314. "                "};
  315.  
  316.  
  317. #if defined(__DOS__)
  318.  
  319. bool wxIsDriveAvailable(const wxString& dirName)
  320. {
  321.     // FIXME_MGL - this method leads to hang up under Watcom for some reason
  322. #ifndef __WATCOMC__
  323.     if ( dirName.Len() == 3 && dirName[1u] == wxT(':') )
  324.     {
  325.         wxString dirNameLower(dirName.Lower());
  326.         // VS: always return TRUE for removable media, since Win95 doesn't
  327.         //     like it when MS-DOS app accesses empty floppy drive
  328.         return (dirNameLower[0u] == wxT('a') ||
  329.                 dirNameLower[0u] == wxT('b') ||
  330.                 wxPathExists(dirNameLower));
  331.     }
  332.     else
  333. #endif
  334.         return TRUE;
  335. }
  336.  
  337. #elif defined(__WINDOWS__) || defined(__WXPM__)
  338.  
  339. int setdrive(int drive)
  340. {
  341. #if defined(__GNUWIN32__) && \
  342.     (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
  343.     return _chdrive(drive);
  344. #else
  345.     wxChar  newdrive[3];
  346.  
  347.     if (drive < 1 || drive > 31)
  348.         return -1;
  349.     newdrive[0] = (wxChar)(wxT('A') + drive - 1);
  350.     newdrive[1] = wxT(':');
  351.     newdrive[2] = wxT('\0');
  352. #if defined(__WXMSW__)
  353. #ifdef __WIN16__
  354.     if (wxSetWorkingDirectory(newdrive))
  355. #else
  356.     if (::SetCurrentDirectory(newdrive))
  357. #endif
  358. #else
  359.     // VA doesn't know what LPSTR is and has its own set
  360.     if (DosSetCurrentDir((PSZ)newdrive))
  361. #endif
  362.         return 0;
  363.     else
  364.         return -1;
  365. #endif // !GNUWIN32
  366. }
  367.  
  368. bool wxIsDriveAvailable(const wxString& dirName)
  369. {
  370. #ifdef __WIN32__
  371.     UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  372. #endif
  373.     bool success = TRUE;
  374.  
  375.     // Check if this is a root directory and if so,
  376.     // whether the drive is avaiable.
  377.     if (dirName.Len() == 3 && dirName[(size_t)1] == wxT(':'))
  378.     {
  379.         wxString dirNameLower(dirName.Lower());
  380. #if defined(__WXWINE__) || (defined(__GNUWIN32__) && \
  381.     !(defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1))
  382.         success = wxPathExists(dirNameLower);
  383. #else
  384.         int currentDrive = _getdrive();
  385.         int thisDrive = (int) (dirNameLower[(size_t)0] - 'a' + 1) ;
  386.         int err = setdrive( thisDrive ) ;
  387.         setdrive( currentDrive );
  388.  
  389.         if (err == -1)
  390.         {
  391.             success = FALSE;
  392.         }
  393. #endif
  394.     }
  395. #ifdef __WIN32__
  396.     (void) SetErrorMode(errorMode);
  397. #endif
  398.  
  399.     return success;
  400. }
  401. #endif // __WINDOWS__ || __WXPM__
  402.  
  403. // Function which is called by quick sort. We want to override the default wxArrayString behaviour,
  404. // and sort regardless of case.
  405. static int LINKAGEMODE wxDirCtrlStringCompareFunction(const void *first, const void *second)
  406. {
  407.     wxString *strFirst = (wxString *)first;
  408.     wxString *strSecond = (wxString *)second;
  409.  
  410.     return strFirst->CmpNoCase(*strSecond);
  411. }
  412.  
  413. //-----------------------------------------------------------------------------
  414. // wxDirItemData
  415. //-----------------------------------------------------------------------------
  416.  
  417. wxDirItemData::wxDirItemData(const wxString& path, const wxString& name,
  418.                              bool isDir)
  419. {
  420.     m_path = path;
  421.     m_name = name;
  422.     /* Insert logic to detect hidden files here
  423.      * In UnixLand we just check whether the first char is a dot
  424.      * For FileNameFromPath read LastDirNameInThisPath ;-) */
  425.     // m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.');
  426.     m_isHidden = FALSE;
  427.     m_isExpanded = FALSE;
  428.     m_isDir = isDir;
  429. }
  430.  
  431. wxDirItemData::~wxDirItemData()
  432. {
  433. }
  434.  
  435. void wxDirItemData::SetNewDirName(const wxString& path)
  436. {
  437.     m_path = path;
  438.     m_name = wxFileNameFromPath(path);
  439. }
  440.  
  441. bool wxDirItemData::HasSubDirs() const
  442. {
  443.     if (m_path.IsEmpty())
  444.         return FALSE;
  445.  
  446.     wxDir dir;
  447.     {
  448.         wxLogNull nolog;
  449.         if ( !dir.Open(m_path) )
  450.             return FALSE;
  451.     }
  452.  
  453.     return dir.HasSubDirs();
  454. }
  455.  
  456. bool wxDirItemData::HasFiles(const wxString& WXUNUSED(spec)) const
  457. {
  458.     if (m_path.IsEmpty())
  459.         return FALSE;
  460.  
  461.     wxDir dir;
  462.     {
  463.         wxLogNull nolog;
  464.         if ( !dir.Open(m_path) )
  465.             return FALSE;
  466.     }
  467.  
  468.     return dir.HasFiles();
  469. }
  470.  
  471. //-----------------------------------------------------------------------------
  472. // wxGenericDirCtrl
  473. //-----------------------------------------------------------------------------
  474.  
  475. IMPLEMENT_DYNAMIC_CLASS(wxGenericDirCtrl, wxControl)
  476.  
  477. BEGIN_EVENT_TABLE(wxGenericDirCtrl, wxControl)
  478.   EVT_TREE_ITEM_EXPANDING     (-1, wxGenericDirCtrl::OnExpandItem)
  479.   EVT_TREE_ITEM_COLLAPSED     (-1, wxGenericDirCtrl::OnCollapseItem)
  480.   EVT_TREE_BEGIN_LABEL_EDIT   (-1, wxGenericDirCtrl::OnBeginEditItem)
  481.   EVT_TREE_END_LABEL_EDIT     (-1, wxGenericDirCtrl::OnEndEditItem)
  482.   EVT_SIZE                    (wxGenericDirCtrl::OnSize)
  483. END_EVENT_TABLE()
  484.  
  485. wxGenericDirCtrl::wxGenericDirCtrl(void)
  486. {
  487.     Init();
  488. }
  489.  
  490. bool wxGenericDirCtrl::Create(wxWindow *parent,
  491.                               const wxWindowID id,
  492.                               const wxString& dir,
  493.                               const wxPoint& pos,
  494.                               const wxSize& size,
  495.                               long style,
  496.                               const wxString& filter,
  497.                               int defaultFilter,
  498.                               const wxString& name)
  499. {
  500.     if (!wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name))
  501.         return FALSE;
  502.  
  503.     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
  504.  
  505.     Init();
  506.  
  507.     long treeStyle = wxTR_HAS_BUTTONS | wxTR_HIDE_ROOT;
  508.  
  509.     if (style & wxDIRCTRL_EDIT_LABELS)
  510.         treeStyle |= wxTR_EDIT_LABELS;
  511.  
  512.     if ((style & wxDIRCTRL_3D_INTERNAL) == 0)
  513.         treeStyle |= wxNO_BORDER;
  514.  
  515.     long filterStyle = 0;
  516.     if ((style & wxDIRCTRL_3D_INTERNAL) == 0)
  517.         filterStyle |= wxNO_BORDER;
  518.  
  519.     m_treeCtrl = new wxTreeCtrl(this, wxID_TREECTRL, pos, size, treeStyle);
  520.  
  521.     if (!filter.IsEmpty() && (style & wxDIRCTRL_SHOW_FILTERS))
  522.         m_filterListCtrl = new wxDirFilterListCtrl(this, wxID_FILTERLISTCTRL, wxDefaultPosition, wxDefaultSize, filterStyle);
  523.  
  524.     m_defaultPath = dir;
  525.     m_filter = filter;
  526.  
  527.     SetFilterIndex(defaultFilter);
  528.  
  529.     if (m_filterListCtrl)
  530.         m_filterListCtrl->FillFilterList(filter, defaultFilter);
  531.  
  532.     m_imageList = new wxImageList(16, 16, TRUE);
  533.     m_imageList->Add(wxIcon(icon1_xpm));
  534.     m_imageList->Add(wxIcon(icon2_xpm));
  535.     m_imageList->Add(wxIcon(icon3_xpm));
  536.     m_imageList->Add(wxIcon(icon4_xpm));
  537.     m_imageList->Add(wxIcon(icon5_xpm));
  538.     m_imageList->Add(wxIcon(icon6_xpm));
  539.     m_imageList->Add(wxIcon(icon7_xpm));
  540.     m_imageList->Add(wxIcon(icon8_xpm));
  541.     m_treeCtrl->AssignImageList(m_imageList);
  542.  
  543.     m_showHidden = FALSE;
  544.     wxDirItemData* rootData = new wxDirItemData(wxT(""), wxT(""), TRUE);
  545.  
  546.     wxString rootName;
  547.  
  548. #if defined(__WINDOWS__) || defined(__WXPM__) || defined(__DOS__)
  549.     rootName = _("Computer");
  550. #else
  551.     rootName = _("Sections");
  552. #endif
  553.  
  554.     m_rootId = m_treeCtrl->AddRoot( rootName, 3, -1, rootData);
  555.     m_treeCtrl->SetItemHasChildren(m_rootId);
  556.     ExpandDir(m_rootId); // automatically expand first level
  557.  
  558.     // Expand and select the default path
  559.     if (!m_defaultPath.IsEmpty())
  560.         ExpandPath(m_defaultPath);
  561.  
  562.     DoResize();
  563.  
  564.     return TRUE;
  565. }
  566.  
  567. wxGenericDirCtrl::~wxGenericDirCtrl()
  568. {
  569. }
  570.  
  571. void wxGenericDirCtrl::Init()
  572. {
  573.     m_showHidden = FALSE;
  574.     m_imageList = NULL;
  575.     m_currentFilter = 0;
  576.     m_currentFilterStr = wxEmptyString; // Default: any file
  577.     m_treeCtrl = NULL;
  578.     m_filterListCtrl = NULL;
  579. }
  580.  
  581. void wxGenericDirCtrl::ShowHidden( bool show )
  582. {
  583.     m_showHidden = show;
  584.  
  585.     wxString path = GetPath();
  586.     ReCreateTree();
  587.     SetPath(path);
  588. }
  589.  
  590. void wxGenericDirCtrl::AddSection(const wxString& path, const wxString& name, int imageId)
  591. {
  592.     wxDirItemData *dir_item = new wxDirItemData(path,name,TRUE);
  593.  
  594.     wxTreeItemId id = m_treeCtrl->AppendItem( m_rootId, name, imageId, -1, dir_item);
  595.  
  596.     m_treeCtrl->SetItemHasChildren(id);
  597. }
  598.  
  599. void wxGenericDirCtrl::SetupSections()
  600. {
  601. #if defined(__WINDOWS__) || defined(__DOS__) || defined(__WXPM__)
  602.  
  603. #ifdef __WIN32__
  604.     wxChar driveBuffer[256];
  605.     size_t n = (size_t) GetLogicalDriveStrings(255, driveBuffer);
  606.     size_t i = 0;
  607.     while (i < n)
  608.     {
  609.         wxString path, name;
  610.         path.Printf(wxT("%c:\\"), driveBuffer[i]);
  611.         name.Printf(wxT("(%c:)"), driveBuffer[i]);
  612.  
  613.         int imageId = 4;
  614.         int driveType = ::GetDriveType(path);
  615.         switch (driveType)
  616.         {
  617.             case DRIVE_REMOVABLE:
  618.                 if (path == wxT("a:\\") || path == wxT("b:\\"))
  619.                     imageId = 6; // Floppy
  620.                 else
  621.                     imageId = 7;
  622.                 break;
  623.             case DRIVE_FIXED:
  624.                 imageId = 4;
  625.                 break;
  626.             case DRIVE_REMOTE:
  627.                 imageId = 4;
  628.                 break;
  629.             case DRIVE_CDROM:
  630.                 imageId = 5;
  631.                 break;
  632.             default:
  633.                 imageId = 4;
  634.                 break;
  635.         }
  636.  
  637.         AddSection(path, name, imageId);
  638.  
  639.         while (driveBuffer[i] != wxT('\0'))
  640.             i ++;
  641.         i ++;
  642.         if (driveBuffer[i] == wxT('\0'))
  643.             break;
  644.     }
  645. #else // !__WIN32__
  646.     int drive;
  647.  
  648.     /* If we can switch to the drive, it exists. */
  649.     for( drive = 1; drive <= 26; drive++ )
  650.     {
  651.         wxString path, name;
  652.         path.Printf(wxT("%c:\\"), (char) (drive + 'a' - 1));
  653.         name.Printf(wxT("(%c:)"), (char) (drive + 'A' - 1));
  654.  
  655.         if (wxIsDriveAvailable(path))
  656.         {
  657.             AddSection(path, name, (drive <= 2) ? 6/*floppy*/ : 4/*disk*/);
  658.         }
  659.     }
  660. #endif // __WIN32__/!__WIN32__
  661.  
  662. #elif defined(__WXMAC__)
  663.     FSSpec volume ;
  664.     short index = 1 ;
  665.     while(1) {
  666.       short actualCount = 0 ;
  667.       if ( OnLine( &volume , 1 , &actualCount , &index ) != noErr || actualCount == 0 )
  668.         break ;
  669.  
  670.       wxString name = wxMacFSSpec2MacFilename( &volume ) ;
  671.       AddSection(name + wxFILE_SEP_PATH, name, 0);
  672.     }
  673. #elif defined(__UNIX__)
  674.     AddSection(wxT("/"), wxT("/"), 3/*computer icon*/);
  675. #else
  676.     #error "Unsupported platform in wxGenericDirCtrl!"
  677. #endif
  678. }
  679.  
  680. void wxGenericDirCtrl::OnBeginEditItem(wxTreeEvent &event)
  681. {
  682.     // don't rename the main entry "Sections"
  683.     if (event.GetItem() == m_rootId)
  684.     {
  685.         event.Veto();
  686.         return;
  687.     }
  688.  
  689.     // don't rename the individual sections
  690.     if (m_treeCtrl->GetItemParent( event.GetItem() ) == m_rootId)
  691.     {
  692.         event.Veto();
  693.         return;
  694.     }
  695. }
  696.  
  697. void wxGenericDirCtrl::OnEndEditItem(wxTreeEvent &event)
  698. {
  699.     if ((event.GetLabel().IsEmpty()) ||
  700.         (event.GetLabel() == _(".")) ||
  701.         (event.GetLabel() == _("..")) ||
  702.         (event.GetLabel().First( wxT("/") ) != wxNOT_FOUND))
  703.     {
  704.         wxMessageDialog dialog(this, _("Illegal directory name."), _("Error"), wxOK | wxICON_ERROR );
  705.         dialog.ShowModal();
  706.         event.Veto();
  707.         return;
  708.     }
  709.  
  710.     wxTreeItemId id = event.GetItem();
  711.     wxDirItemData *data = (wxDirItemData*)m_treeCtrl->GetItemData( id );
  712.     wxASSERT( data );
  713.  
  714.     wxString new_name( wxPathOnly( data->m_path ) );
  715.     new_name += wxString(wxFILE_SEP_PATH);
  716.     new_name += event.GetLabel();
  717.  
  718.     wxLogNull log;
  719.  
  720.     if (wxFileExists(new_name))
  721.     {
  722.         wxMessageDialog dialog(this, _("File name exists already."), _("Error"), wxOK | wxICON_ERROR );
  723.         dialog.ShowModal();
  724.         event.Veto();
  725.     }
  726.  
  727.     if (wxRenameFile(data->m_path,new_name))
  728.     {
  729.         data->SetNewDirName( new_name );
  730.     }
  731.     else
  732.     {
  733.         wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
  734.         dialog.ShowModal();
  735.         event.Veto();
  736.     }
  737. }
  738.  
  739. void wxGenericDirCtrl::OnExpandItem(wxTreeEvent &event)
  740. {
  741.     wxTreeItemId parentId = event.GetItem();
  742.  
  743.     // VS: this is needed because the event handler is called from wxTreeCtrl
  744.     //     ctor when wxTR_HIDE_ROOT was specified
  745.     if (m_rootId == 0)
  746.         m_rootId = m_treeCtrl->GetRootItem();
  747.  
  748.     ExpandDir(parentId);
  749. }
  750.  
  751. void wxGenericDirCtrl::OnCollapseItem(wxTreeEvent &event )
  752. {
  753.     CollapseDir(event.GetItem());
  754. }
  755.  
  756. void wxGenericDirCtrl::CollapseDir(wxTreeItemId parentId)
  757. {
  758.     wxTreeItemId child;
  759.  
  760.     wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(parentId);
  761.     if (!data->m_isExpanded)
  762.         return;
  763.  
  764.     data->m_isExpanded = FALSE;
  765.     long cookie;
  766.     /* Workaround because DeleteChildren has disapeared (why?) and
  767.      * CollapseAndReset doesn't work as advertised (deletes parent too) */
  768.     child = m_treeCtrl->GetFirstChild(parentId, cookie);
  769.     while (child.IsOk())
  770.     {
  771.         m_treeCtrl->Delete(child);
  772.         /* Not GetNextChild below, because the cookie mechanism can't
  773.          * handle disappearing children! */
  774.         child = m_treeCtrl->GetFirstChild(parentId, cookie);
  775.     }
  776. }
  777.  
  778. void wxGenericDirCtrl::ExpandDir(wxTreeItemId parentId)
  779. {
  780.     wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(parentId);
  781.  
  782.     if (data->m_isExpanded)
  783.         return;
  784.  
  785.     data->m_isExpanded = TRUE;
  786.  
  787.     if (parentId == m_treeCtrl->GetRootItem())
  788.     {
  789.         SetupSections();
  790.         return;
  791.     }
  792.  
  793.     wxASSERT(data);
  794.  
  795.     wxString search,path,filename;
  796.  
  797.     wxString dirName(data->m_path);
  798.  
  799. #if defined(__WINDOWS__) || defined(__DOS__) || defined(__WXPM__)
  800.     // Check if this is a root directory and if so,
  801.     // whether the drive is avaiable.
  802.     if (!wxIsDriveAvailable(dirName))
  803.     {
  804.         data->m_isExpanded = FALSE;
  805.         //wxMessageBox(wxT("Sorry, this drive is not available."));
  806.         return;
  807.     }
  808. #endif
  809.  
  810.     // This may take a longish time. Go to busy cursor
  811.     wxBusyCursor busy;
  812.  
  813. #if defined(__WINDOWS__) || defined(__DOS__) || defined(__WXPM__)
  814.     if (dirName.Last() == ':')
  815.         dirName += wxString(wxFILE_SEP_PATH);
  816. #endif
  817.  
  818.     wxArrayString dirs;
  819.     wxArrayString filenames;
  820.  
  821.     wxDir d;
  822.     wxString eachFilename;
  823.  
  824.     wxLogNull log;
  825.     d.Open(dirName);
  826.  
  827.     if (d.IsOpened())
  828.     {
  829.         int style = wxDIR_DIRS;
  830.         if (m_showHidden) style |= wxDIR_HIDDEN;
  831.         if (d.GetFirst(& eachFilename, wxEmptyString, style))
  832.         {
  833.             do
  834.             {
  835.                 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
  836.                 {
  837.                     dirs.Add(eachFilename);
  838.                 }
  839.             }
  840.             while (d.GetNext(& eachFilename));
  841.         }
  842.     }
  843.     dirs.Sort((wxArrayString::CompareFunction) wxDirCtrlStringCompareFunction);
  844.  
  845.     // Now do the filenames -- but only if we're allowed to
  846.     if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0)
  847.     {
  848.         wxLogNull log;
  849.  
  850.         d.Open(dirName);
  851.  
  852.         if (d.IsOpened())
  853.         {
  854.             if (d.GetFirst(& eachFilename, m_currentFilterStr, wxDIR_FILES))
  855.             {
  856.                 do
  857.                 {
  858.                     if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
  859.                     {
  860.                         filenames.Add(eachFilename);
  861.                     }
  862.                 }
  863.                 while (d.GetNext(& eachFilename));
  864.             }
  865.         }
  866.         filenames.Sort((wxArrayString::CompareFunction) wxDirCtrlStringCompareFunction);
  867.     }
  868.  
  869.     // Add the sorted dirs
  870.     size_t i;
  871.     for (i = 0; i < dirs.Count(); i++)
  872.     {
  873.         wxString eachFilename(dirs[i]);
  874.         path = dirName;
  875.         if (path.Last() != wxFILE_SEP_PATH)
  876.             path += wxString(wxFILE_SEP_PATH);
  877.         path += eachFilename;
  878.  
  879.         wxDirItemData *dir_item = new wxDirItemData(path,eachFilename,TRUE);
  880.         wxTreeItemId id = m_treeCtrl->AppendItem( parentId, eachFilename, 0, -1, dir_item);
  881.         m_treeCtrl->SetItemImage( id, 1, wxTreeItemIcon_Expanded );
  882.  
  883.         // Has this got any children? If so, make it expandable.
  884.         // (There are two situations when a dir has children: either it
  885.         // has subdirectories or it contains files that weren't filtered
  886.         // out. The latter only applies to dirctrl with files.)
  887.         if ( dir_item->HasSubDirs() ||
  888.              (((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0) &&
  889.                dir_item->HasFiles(m_currentFilterStr)) )
  890.         {
  891.             m_treeCtrl->SetItemHasChildren(id);
  892.         }
  893.     }
  894.  
  895.     // Add the sorted filenames
  896.     if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0)
  897.     {
  898.         for (i = 0; i < filenames.Count(); i++)
  899.         {
  900.             wxString eachFilename(filenames[i]);
  901.             path = dirName;
  902.             if (path.Last() != wxFILE_SEP_PATH)
  903.                 path += wxString(wxFILE_SEP_PATH);
  904.             path += eachFilename;
  905.             //path = dirName + wxString(wxT("/")) + eachFilename;
  906.             wxDirItemData *dir_item = new wxDirItemData(path,eachFilename,FALSE);
  907.             (void)m_treeCtrl->AppendItem( parentId, eachFilename, 2, -1, dir_item);
  908.         }
  909.     }
  910. }
  911.  
  912. void wxGenericDirCtrl::ReCreateTree()
  913. {
  914.     CollapseDir(m_treeCtrl->GetRootItem());
  915.     ExpandDir(m_treeCtrl->GetRootItem());
  916. }
  917.  
  918. // Find the child that matches the first part of 'path'.
  919. // E.g. if a child path is "/usr" and 'path' is "/usr/include"
  920. // then the child for /usr is returned.
  921. wxTreeItemId wxGenericDirCtrl::FindChild(wxTreeItemId parentId, const wxString& path, bool& done)
  922. {
  923.     wxString path2(path);
  924.  
  925.     // Make sure all separators are as per the current platform
  926.     path2.Replace(wxT("\\"), wxString(wxFILE_SEP_PATH));
  927.     path2.Replace(wxT("/"), wxString(wxFILE_SEP_PATH));
  928.  
  929.     // Append a separator to foil bogus substring matching
  930.     path2 += wxString(wxFILE_SEP_PATH);
  931.  
  932.     // In MSW or PM, case is not significant
  933. #if defined(__WINDOWS__) || defined(__DOS__) || defined(__WXPM__)
  934.     path2.MakeLower();
  935. #endif
  936.  
  937.     long cookie;
  938.     wxTreeItemId childId = m_treeCtrl->GetFirstChild(parentId, cookie);
  939.     while (childId.IsOk())
  940.     {
  941.         wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(childId);
  942.  
  943.         if (data && !data->m_path.IsEmpty())
  944.         {
  945.             wxString childPath(data->m_path);
  946.             if (childPath.Last() != wxFILE_SEP_PATH)
  947.                 childPath += wxString(wxFILE_SEP_PATH);
  948.  
  949.             // In MSW and PM, case is not significant
  950. #if defined(__WINDOWS__) || defined(__DOS__) || defined(__WXPM__)
  951.             childPath.MakeLower();
  952. #endif
  953.  
  954.             if (childPath.Len() <= path2.Len())
  955.             {
  956.                 wxString path3 = path2.Mid(0, childPath.Len());
  957.                 if (childPath == path3)
  958.                 {
  959.                     if (path3.Len() == path2.Len())
  960.                         done = TRUE;
  961.                     else
  962.                         done = FALSE;
  963.                     return childId;
  964.                 }
  965.             }
  966.         }
  967.  
  968.         childId = m_treeCtrl->GetNextChild(parentId, cookie);
  969.     }
  970.     wxTreeItemId invalid;
  971.     return invalid;
  972. }
  973.  
  974. // Try to expand as much of the given path as possible,
  975. // and select the given tree item.
  976. bool wxGenericDirCtrl::ExpandPath(const wxString& path)
  977. {
  978.     bool done = FALSE;
  979.     wxTreeItemId id = FindChild(m_rootId, path, done);
  980.     wxTreeItemId lastId = id; // The last non-zero id
  981.     while (id.IsOk() && !done)
  982.     {
  983.         ExpandDir(id);
  984.  
  985.         id = FindChild(id, path, done);
  986.         if (id.IsOk())
  987.             lastId = id;
  988.     }
  989.     if (lastId.IsOk())
  990.     {
  991.         wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(lastId);
  992.         if (data->m_isDir)
  993.         {
  994.             m_treeCtrl->Expand(lastId);
  995.         }
  996.         if ((GetWindowStyle() & wxDIRCTRL_SELECT_FIRST) && data->m_isDir)
  997.         {
  998.             // Find the first file in this directory
  999.             long cookie;
  1000.             wxTreeItemId childId = m_treeCtrl->GetFirstChild(lastId, cookie);
  1001.             bool selectedChild = FALSE;
  1002.             while (childId.IsOk())
  1003.             {
  1004.                 wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(childId);
  1005.  
  1006.                 if (data && data->m_path != wxT("") && !data->m_isDir)
  1007.                 {
  1008.                     m_treeCtrl->SelectItem(childId);
  1009.                     m_treeCtrl->EnsureVisible(childId);
  1010.                     selectedChild = TRUE;
  1011.                     break;
  1012.                 }
  1013.                 childId = m_treeCtrl->GetNextChild(lastId, cookie);
  1014.             }
  1015.             if (!selectedChild)
  1016.             {
  1017.                 m_treeCtrl->SelectItem(lastId);
  1018.                 m_treeCtrl->EnsureVisible(lastId);
  1019.             }
  1020.         }
  1021.         else
  1022.         {
  1023.             m_treeCtrl->SelectItem(lastId);
  1024.             m_treeCtrl->EnsureVisible(lastId);
  1025.         }
  1026.  
  1027.         return TRUE;
  1028.     }
  1029.     else
  1030.         return FALSE;
  1031. }
  1032.  
  1033. wxString wxGenericDirCtrl::GetPath() const
  1034. {
  1035.     wxTreeItemId id = m_treeCtrl->GetSelection();
  1036.     if (id)
  1037.     {
  1038.         wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(id);
  1039.         return data->m_path;
  1040.     }
  1041.     else
  1042.         return wxEmptyString;
  1043. }
  1044.  
  1045. wxString wxGenericDirCtrl::GetFilePath() const
  1046. {
  1047.     wxTreeItemId id = m_treeCtrl->GetSelection();
  1048.     if (id)
  1049.     {
  1050.         wxDirItemData* data = (wxDirItemData*) m_treeCtrl->GetItemData(id);
  1051.         if (data->m_isDir)
  1052.             return wxEmptyString;
  1053.         else
  1054.             return data->m_path;
  1055.     }
  1056.     else
  1057.         return wxEmptyString;
  1058. }
  1059.  
  1060. void wxGenericDirCtrl::SetPath(const wxString& path)
  1061. {
  1062.     m_defaultPath = path;
  1063.     if (m_rootId)
  1064.         ExpandPath(path);
  1065. }
  1066.  
  1067. // Not used
  1068. #if 0
  1069. void wxGenericDirCtrl::FindChildFiles(wxTreeItemId id, int dirFlags, wxArrayString& filenames)
  1070. {
  1071.     wxDirItemData *data = (wxDirItemData *) m_treeCtrl->GetItemData(id);
  1072.  
  1073.     // This may take a longish time. Go to busy cursor
  1074.     wxBusyCursor busy;
  1075.  
  1076.     wxASSERT(data);
  1077.  
  1078.     wxString search,path,filename;
  1079.  
  1080.     wxString dirName(data->m_path);
  1081.  
  1082. #if defined(__WXMSW__) || defined(__WXPM__)
  1083.     if (dirName.Last() == ':')
  1084.         dirName += wxString(wxFILE_SEP_PATH);
  1085. #endif
  1086.  
  1087.     wxDir d;
  1088.     wxString eachFilename;
  1089.  
  1090.     wxLogNull log;
  1091.     d.Open(dirName);
  1092.  
  1093.     if (d.IsOpened())
  1094.     {
  1095.         if (d.GetFirst(& eachFilename, m_currentFilterStr, dirFlags))
  1096.         {
  1097.             do
  1098.             {
  1099.                 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
  1100.                 {
  1101.                     filenames.Add(eachFilename);
  1102.                 }
  1103.             }
  1104.             while (d.GetNext(& eachFilename)) ;
  1105.         }
  1106.     }
  1107. }
  1108. #endif
  1109.  
  1110. void wxGenericDirCtrl::SetFilterIndex(int n)
  1111. {
  1112.     m_currentFilter = n;
  1113.  
  1114.     wxString f, d;
  1115.     if (ExtractWildcard(m_filter, n, f, d))
  1116.         m_currentFilterStr = f;
  1117.     else
  1118.         m_currentFilterStr = wxT("*.*");
  1119. }
  1120.  
  1121. void wxGenericDirCtrl::SetFilter(const wxString& filter)
  1122. {
  1123.     m_filter = filter;
  1124.  
  1125.     wxString f, d;
  1126.     if (ExtractWildcard(m_filter, m_currentFilter, f, d))
  1127.         m_currentFilterStr = f;
  1128.     else
  1129.         m_currentFilterStr = wxT("*.*");
  1130. }
  1131.  
  1132. // Extract description and actual filter from overall filter string
  1133. bool wxGenericDirCtrl::ExtractWildcard(const wxString& filterStr, int n, wxString& filter, wxString& description)
  1134. {
  1135.     wxArrayString filters, descriptions;
  1136.     int count = ParseFilter(filterStr, filters, descriptions);
  1137.     if (count > 0 && n < count)
  1138.     {
  1139.         filter = filters[n];
  1140.         description = descriptions[n];
  1141.         return TRUE;
  1142.     }
  1143.  
  1144.     return FALSE;
  1145. }
  1146.  
  1147. // Parses the global filter, returning the number of filters.
  1148. // Returns 0 if none or if there's a problem.
  1149. // filterStr is in the form:
  1150. //
  1151. // "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpg"
  1152.  
  1153. int wxGenericDirCtrl::ParseFilter(const wxString& filterStr, wxArrayString& filters, wxArrayString& descriptions)
  1154. {
  1155.     wxString str(filterStr);
  1156.  
  1157.     wxString description, filter;
  1158.     int pos;
  1159.     bool finished = FALSE;
  1160.     do
  1161.     {
  1162.         pos = str.Find(wxT('|'));
  1163.         if (pos == -1)
  1164.             return 0; // Problem
  1165.         description = str.Left(pos);
  1166.         str = str.Mid(pos+1);
  1167.         pos = str.Find(wxT('|'));
  1168.         if (pos == -1)
  1169.         {
  1170.             filter = str;
  1171.             finished = TRUE;
  1172.         }
  1173.         else
  1174.         {
  1175.             filter = str.Left(pos);
  1176.             str = str.Mid(pos+1);
  1177.         }
  1178.         descriptions.Add(description);
  1179.         filters.Add(filter);
  1180.     }
  1181.     while (!finished) ;
  1182.  
  1183.     return filters.Count();
  1184. }
  1185.  
  1186. void wxGenericDirCtrl::DoResize()
  1187. {
  1188.     wxSize sz = GetClientSize();
  1189.     int verticalSpacing = 3;
  1190.     if (m_treeCtrl)
  1191.     {
  1192.         wxSize filterSz ;
  1193.         if (m_filterListCtrl)
  1194.         {
  1195. #ifdef __WXMSW__
  1196.             // For some reason, this is required in order for the
  1197.             // correct control height to always be returned, rather
  1198.             // than the drop-down list height which is sometimes returned.
  1199.             wxSize oldSize = m_filterListCtrl->GetSize();
  1200.             m_filterListCtrl->SetSize(-1, -1, oldSize.x+10, -1, wxSIZE_USE_EXISTING);
  1201.             m_filterListCtrl->SetSize(-1, -1, oldSize.x, -1, wxSIZE_USE_EXISTING);
  1202. #endif
  1203.             filterSz = m_filterListCtrl->GetSize();
  1204.             sz.y -= (filterSz.y + verticalSpacing);
  1205.         }
  1206.         m_treeCtrl->SetSize(0, 0, sz.x, sz.y);
  1207.         if (m_filterListCtrl)
  1208.         {
  1209.             m_filterListCtrl->SetSize(0, sz.y + verticalSpacing, sz.x, filterSz.y);
  1210.             // Don't know why, but this needs refreshing after a resize (wxMSW)
  1211.             m_filterListCtrl->Refresh();
  1212.         }
  1213.     }
  1214. }
  1215.  
  1216.  
  1217. void wxGenericDirCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
  1218. {
  1219.     DoResize();
  1220. }
  1221.  
  1222. //-----------------------------------------------------------------------------
  1223. // wxDirFilterListCtrl
  1224. //-----------------------------------------------------------------------------
  1225.  
  1226. IMPLEMENT_CLASS(wxDirFilterListCtrl, wxChoice)
  1227.  
  1228. BEGIN_EVENT_TABLE(wxDirFilterListCtrl, wxChoice)
  1229.     EVT_CHOICE(-1, wxDirFilterListCtrl::OnSelFilter)
  1230. END_EVENT_TABLE()
  1231.  
  1232. bool wxDirFilterListCtrl::Create(wxGenericDirCtrl* parent, const wxWindowID id,
  1233.               const wxPoint& pos,
  1234.               const wxSize& size,
  1235.               long style)
  1236. {
  1237.     m_dirCtrl = parent;
  1238.     return wxChoice::Create(parent, id, pos, size, 0, NULL, style);
  1239. }
  1240.  
  1241. void wxDirFilterListCtrl::Init()
  1242. {
  1243.     m_dirCtrl = NULL;
  1244. }
  1245.  
  1246. void wxDirFilterListCtrl::OnSelFilter(wxCommandEvent& WXUNUSED(event))
  1247. {
  1248.     int sel = GetSelection();
  1249.  
  1250.     wxString currentPath = m_dirCtrl->GetPath();
  1251.  
  1252.     m_dirCtrl->SetFilterIndex(sel);
  1253.  
  1254.     // If the filter has changed, the view is out of date, so
  1255.     // collapse the tree.
  1256.     m_dirCtrl->ReCreateTree();
  1257.  
  1258.     // Try to restore the selection, or at least the directory
  1259.     m_dirCtrl->ExpandPath(currentPath);
  1260. }
  1261.  
  1262. void wxDirFilterListCtrl::FillFilterList(const wxString& filter, int defaultFilter)
  1263. {
  1264.     Clear();
  1265.     wxArrayString descriptions, filters;
  1266.     size_t n = (size_t) m_dirCtrl->ParseFilter(filter, filters, descriptions);
  1267.  
  1268.     if (n > 0 && defaultFilter < (int) n)
  1269.     {
  1270.         size_t i = 0;
  1271.         for (i = 0; i < n; i++)
  1272.             Append(descriptions[i]);
  1273.         SetSelection(defaultFilter);
  1274.     }
  1275. }
  1276.  
  1277. #endif // wxUSE_DIRDLG
  1278.