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