]> git.saurik.com Git - wxWidgets.git/blob - src/generic/dirctrlg.cpp
use better check for drives even with Mingw32 (and, later, MSDOS)
[wxWidgets.git] / src / generic / dirctrlg.cpp
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$
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 #ifdef __WXMSW__
51 #include <windows.h>
52
53 // FIXME - Mingw32 1.0 has both _getdrive() and _chdrive(). For now, let's assume
54 // older releases don't, but it should be verified and the checks modified
55 // accordingly.
56 #if !defined(__GNUWIN32__) || \
57 (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
58 #include <direct.h>
59 #include <stdlib.h>
60 #include <ctype.h>
61 #endif
62
63 #endif
64
65 #ifdef __WXPM__
66
67 #define INCL_BASE
68 #include <os2.h>
69 #include <direct.h>
70 #include <stdlib.h>
71 #include <ctype.h>
72
73 #endif // __WXPM__
74
75 #if defined(__WXMAC__)
76 # include "MoreFilesExtras.h"
77 #endif
78
79 #ifdef __BORLANDC__
80 #include "dos.h"
81 #endif
82
83 // If compiled under Windows, this macro can cause problems
84 #ifdef GetFirstChild
85 #undef GetFirstChild
86 #endif
87
88 /* Closed folder */
89 static char * icon1_xpm[] = {
90 /* width height ncolors chars_per_pixel */
91 "16 16 6 1",
92 /* colors */
93 " s None c None",
94 ". c #000000",
95 "+ c #c0c0c0",
96 "@ c #808080",
97 "# c #ffff00",
98 "$ c #ffffff",
99 /* pixels */
100 " ",
101 " @@@@@ ",
102 " @#+#+#@ ",
103 " @#+#+#+#@@@@@@ ",
104 " @$$$$$$$$$$$$@.",
105 " @$#+#+#+#+#+#@.",
106 " @$+#+#+#+#+#+@.",
107 " @$#+#+#+#+#+#@.",
108 " @$+#+#+#+#+#+@.",
109 " @$#+#+#+#+#+#@.",
110 " @$+#+#+#+#+#+@.",
111 " @$#+#+#+#+#+#@.",
112 " @@@@@@@@@@@@@@.",
113 " ..............",
114 " ",
115 " "};
116
117 /* Open folder */
118 static char * icon2_xpm[] = {
119 /* width height ncolors chars_per_pixel */
120 "16 16 6 1",
121 /* colors */
122 " s None c None",
123 ". c #000000",
124 "+ c #c0c0c0",
125 "@ c #808080",
126 "# c #ffff00",
127 "$ c #ffffff",
128 /* pixels */
129 " ",
130 " @@@@@ ",
131 " @$$$$$@ ",
132 " @$#+#+#$@@@@@@ ",
133 " @$+#+#+$$$$$$@.",
134 " @$#+#+#+#+#+#@.",
135 "@@@@@@@@@@@@@#@.",
136 "@$$$$$$$$$$@@+@.",
137 "@$#+#+#+#+##.@@.",
138 " @$#+#+#+#+#+.@.",
139 " @$+#+#+#+#+#.@.",
140 " @$+#+#+#+##@..",
141 " @@@@@@@@@@@@@.",
142 " .............",
143 " ",
144 " "};
145
146 /* File */
147 static char * icon3_xpm[] = {
148 /* width height ncolors chars_per_pixel */
149 "16 16 3 1",
150 /* colors */
151 " s None c None",
152 ". c #000000",
153 "+ c #ffffff",
154 /* pixels */
155 " ",
156 " ........ ",
157 " .++++++.. ",
158 " .+.+.++.+. ",
159 " .++++++.... ",
160 " .+.+.+++++. ",
161 " .+++++++++. ",
162 " .+.+.+.+.+. ",
163 " .+++++++++. ",
164 " .+.+.+.+.+. ",
165 " .+++++++++. ",
166 " .+.+.+.+.+. ",
167 " .+++++++++. ",
168 " ........... ",
169 " ",
170 " "};
171
172 /* Computer */
173 static char * icon4_xpm[] = {
174 "16 16 7 1",
175 " s None c None",
176 ". c #808080",
177 "X c #c0c0c0",
178 "o c Black",
179 "O c Gray100",
180 "+ c #008080",
181 "@ c Blue",
182 " ........... ",
183 " .XXXXXXXXXX.o",
184 " .OOOOOOOOO..o",
185 " .OoooooooX..o",
186 " .Oo+...@+X..o",
187 " .Oo+XXX.+X..o",
188 " .Oo+....+X..o",
189 " .Oo++++++X..o",
190 " .OXXXXXXXX.oo",
191 " ..........o.o",
192 " ...........Xo",
193 " .XXXXXXXXXX.o",
194 " .o.o.o.o.o...o",
195 " .oXoXoXoXoXo.o ",
196 ".XOXXXXXXXXX.o ",
197 "............o "};
198
199 /* Drive */
200 static char * icon5_xpm[] = {
201 "16 16 7 1",
202 " s None c None",
203 ". c #808080",
204 "X c #c0c0c0",
205 "o c Black",
206 "O c Gray100",
207 "+ c Green",
208 "@ c #008000",
209 " ",
210 " ",
211 " ",
212 " ",
213 " ............. ",
214 " .XXXXXXXXXXXX.o",
215 ".OOOOOOOOOOOO..o",
216 ".XXXXXXXXX+@X..o",
217 ".XXXXXXXXXXXX..o",
218 ".X..........X..o",
219 ".XOOOOOOOOOOX..o",
220 "..............o ",
221 " ooooooooooooo ",
222 " ",
223 " ",
224 " "};
225
226 /* CD-ROM */
227 static char *icon6_xpm[] = {
228 "16 16 10 1",
229 " s None c None",
230 ". c #808080",
231 "X c #c0c0c0",
232 "o c Yellow",
233 "O c Blue",
234 "+ c Black",
235 "@ c Gray100",
236 "# c #008080",
237 "$ c Green",
238 "% c #008000",
239 " ... ",
240 " ..XoX.. ",
241 " .O.XoXXX+ ",
242 " ...O.oXXXX+ ",
243 " .O..X.XXXX+ ",
244 " ....X.+..XXX+",
245 " .XXX.+@+.XXX+",
246 " .X@XX.+.X@@X+",
247 " .....X...#XX@+ ",
248 ".@@@...XXo.O@X+ ",
249 ".@XXX..XXoXOO+ ",
250 ".@++++..XoX+++ ",
251 ".@$%@@XX+++X.+ ",
252 ".............+ ",
253 " ++++++++++++ ",
254 " "};
255
256 /* Floppy */
257 static char * icon7_xpm[] = {
258 "16 16 7 1",
259 " s None c None",
260 ". c #808080",
261 "X c Gray100",
262 "o c #c0c0c0",
263 "O c Black",
264 "+ c Cyan",
265 "@ c Red",
266 " ......X",
267 " .ooooooO",
268 " .+++++OO",
269 " .++++++O",
270 " .++++++O",
271 " .ooooooO",
272 " .......o....oO",
273 " .oooooo.o.O.XoO",
274 ".XXXXXXXXOOOOOO ",
275 ".ooooooooo@o..O ",
276 ".ooo....oooo..O ",
277 ".o..OOOO...o..O ",
278 ".oooXXXXoooo..O ",
279 ".............O ",
280 " OOOOOOOOOOOO ",
281 " "};
282
283 /* Removeable */
284 static char * icon8_xpm[] = {
285 "16 16 7 1",
286 " s None c None",
287 ". c #808080",
288 "X c #c0c0c0",
289 "o c Black",
290 "O c Gray100",
291 "+ c Red",
292 "@ c #800000",
293 " ",
294 " ",
295 " ",
296 " ............. ",
297 " .XXXXXXXXXXXX.o",
298 ".OOOOOOOOOOOO..o",
299 ".OXXXXXXXXXXX..o",
300 ".O+@.oooooo.X..o",
301 ".OXXOooooooOX..o",
302 ".OXXXOOOOOOXX..o",
303 ".OXXXXXXXXXXX..o",
304 ".O............o ",
305 " ooooooooooooo ",
306 " ",
307 " ",
308 " "};
309
310 static const int ID_DIRCTRL = 1000;
311 static const int ID_TEXTCTRL = 1001;
312 static const int ID_OK = 1002;
313 static const int ID_CANCEL = 1003;
314 static const int ID_NEW = 1004;
315 //static const int ID_CHECK = 1005;
316
317 #if defined(__WXMSW__) || defined(__WXPM__) || defined(__DOS__)
318 int setdrive(int drive)
319 {
320 #if defined(__GNUWIN32__) && \
321 (defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
322 return _chdrive(drive);
323 #else
324 wxChar newdrive[3];
325
326 if (drive < 1 || drive > 31)
327 return -1;
328 newdrive[0] = (wxChar)(wxT('A') + drive - 1);
329 newdrive[1] = wxT(':');
330 newdrive[2] = wxT('\0');
331 #if defined(__WXMSW__)
332 #ifdef __WIN16__
333 if (wxSetWorkingDirectory(newdrive))
334 #else
335 if (::SetCurrentDirectory(newdrive))
336 #endif
337 #else
338 // VA doesn't know what LPSTR is and has its own set
339 if (DosSetCurrentDir((PSZ)newdrive))
340 #endif
341 return 0;
342 else
343 return -1;
344 #endif // !GNUWIN32
345 }
346
347 static bool wxIsDriveAvailable(const wxString dirName)
348 {
349 #ifdef __WIN32__
350 UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
351 #endif
352 bool success = TRUE;
353
354 // Check if this is a root directory and if so,
355 // whether the drive is avaiable.
356 if (dirName.Len() == 3 && dirName[(size_t)1] == wxT(':'))
357 {
358 wxString dirNameLower(dirName.Lower());
359 #if defined(__GNUWIN32__) && \
360 !(defined(__MINGW32_MAJOR_VERSION) && __MINGW32_MAJOR_VERSION >= 1)
361 success = wxPathExists(dirNameLower);
362 #else
363 int currentDrive = _getdrive();
364 int thisDrive = (int) (dirNameLower[(size_t)0] - 'a' + 1) ;
365 int err = setdrive( thisDrive ) ;
366 setdrive( currentDrive );
367
368 if (err == -1)
369 {
370 success = FALSE;
371 }
372 #endif
373 }
374 #ifdef __WIN32__
375 (void) SetErrorMode(errorMode);
376 #endif
377
378 return success;
379 }
380 #endif
381
382 // Function which is called by quick sort. We want to override the default wxArrayString behaviour,
383 // and sort regardless of case.
384 static int LINKAGEMODE wxDirCtrlStringCompareFunction(const void *first, const void *second)
385 {
386 wxString *strFirst = (wxString *)first;
387 wxString *strSecond = (wxString *)second;
388
389 return strFirst->CmpNoCase(*strSecond);
390 }
391
392 //-----------------------------------------------------------------------------
393 // wxDirItemDataEx
394 //-----------------------------------------------------------------------------
395
396 wxDirItemDataEx::wxDirItemDataEx(const wxString& path, const wxString& name,
397 bool isDir)
398 {
399 m_path = path;
400 m_name = name;
401 /* Insert logic to detect hidden files here
402 * In UnixLand we just check whether the first char is a dot
403 * For FileNameFromPath read LastDirNameInThisPath ;-) */
404 // m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.');
405 m_isHidden = FALSE;
406 // m_hasSubDirs is no longer needed
407 m_hasSubDirs = TRUE; // HasSubDirs();
408 m_isExpanded = FALSE;
409 m_isDir = isDir;
410 }
411
412 wxDirItemDataEx::~wxDirItemDataEx()
413 {
414 }
415
416 void wxDirItemDataEx::SetNewDirName( wxString path )
417 {
418 m_path = path;
419 m_name = wxFileNameFromPath( path );
420 }
421
422 //-----------------------------------------------------------------------------
423 // wxGenericDirCtrl
424 //-----------------------------------------------------------------------------
425
426 IMPLEMENT_DYNAMIC_CLASS(wxGenericDirCtrl, wxControl)
427
428 BEGIN_EVENT_TABLE(wxGenericDirCtrl, wxControl)
429 EVT_TREE_ITEM_EXPANDING (-1, wxGenericDirCtrl::OnExpandItem)
430 EVT_TREE_ITEM_COLLAPSED (-1, wxGenericDirCtrl::OnCollapseItem)
431 EVT_TREE_BEGIN_LABEL_EDIT (-1, wxGenericDirCtrl::OnBeginEditItem)
432 EVT_TREE_END_LABEL_EDIT (-1, wxGenericDirCtrl::OnEndEditItem)
433 EVT_SIZE (wxGenericDirCtrl::OnSize)
434 END_EVENT_TABLE()
435
436 wxGenericDirCtrl::wxGenericDirCtrl(void)
437 {
438 Init();
439 }
440
441 bool wxGenericDirCtrl::Create(wxWindow *parent,
442 const wxWindowID id,
443 const wxString& dir,
444 const wxPoint& pos,
445 const wxSize& size,
446 long style,
447 const wxString& filter,
448 int defaultFilter,
449 const wxString& name )
450 {
451 if (!wxControl::Create(parent, id, pos, size, style, wxDefaultValidator, name))
452 return FALSE;
453
454 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));
455
456 Init();
457
458 long treeStyle = wxTR_HAS_BUTTONS ; // | wxTR_EDIT_LABELS;
459 if ((style & wxDIRCTRL_3D_INTERNAL) == 0)
460 treeStyle |= wxNO_BORDER;
461
462 long filterStyle = 0;
463 if ((style & wxDIRCTRL_3D_INTERNAL) == 0)
464 filterStyle |= wxNO_BORDER;
465
466 m_treeCtrl = new wxTreeCtrl(this, wxID_TREECTRL, pos, size, treeStyle);
467
468 if (!filter.IsEmpty() && (style & wxDIRCTRL_SHOW_FILTERS))
469 m_filterListCtrl = new wxDirFilterListCtrl(this, wxID_FILTERLISTCTRL, wxDefaultPosition, wxDefaultSize, filterStyle);
470
471 m_defaultPath = dir;
472 m_filter = filter;
473
474 SetFilterIndex(defaultFilter);
475
476 if (m_filterListCtrl)
477 m_filterListCtrl->FillFilterList(filter, defaultFilter);
478
479 m_imageList = new wxImageList(16, 16, TRUE);
480 m_imageList->Add(wxIcon(icon1_xpm));
481 m_imageList->Add(wxIcon(icon2_xpm));
482 m_imageList->Add(wxIcon(icon3_xpm));
483 m_imageList->Add(wxIcon(icon4_xpm));
484 m_imageList->Add(wxIcon(icon5_xpm));
485 m_imageList->Add(wxIcon(icon6_xpm));
486 m_imageList->Add(wxIcon(icon7_xpm));
487 m_imageList->Add(wxIcon(icon8_xpm));
488 m_treeCtrl->SetImageList(m_imageList);
489
490 m_showHidden = FALSE;
491 wxDirItemDataEx* rootData = new wxDirItemDataEx(wxT(""), wxT(""), TRUE);
492
493 wxString rootName;
494
495 #if defined(__WXMSW__) || defined(__WXPM__)
496 rootName = _("Computer");
497 #else
498 rootName = _("Sections");
499 #endif
500
501 m_rootId = m_treeCtrl->AddRoot( rootName, 3, -1, rootData);
502 m_treeCtrl->SetItemHasChildren(m_rootId);
503 m_treeCtrl->Expand(m_rootId); // automatically expand first level
504
505 // Expand and select the default path
506 if (!m_defaultPath.IsEmpty())
507 ExpandPath(m_defaultPath);
508
509 DoResize();
510
511 return TRUE;
512 }
513
514 wxGenericDirCtrl::~wxGenericDirCtrl()
515 {
516 m_treeCtrl->SetImageList(NULL);
517 delete m_imageList;
518 }
519
520 void wxGenericDirCtrl::Init()
521 {
522 m_showHidden = FALSE;
523 m_imageList = NULL;
524 m_currentFilter = 0;
525 m_currentFilterStr = wxEmptyString; // Default: any file
526 m_treeCtrl = NULL;
527 m_filterListCtrl = NULL;
528 }
529
530 void wxGenericDirCtrl::AddSection(const wxString& path, const wxString& name, int imageId)
531 {
532 wxDirItemDataEx *dir_item = new wxDirItemDataEx(path,name,TRUE);
533
534 #if defined(__WXMSW__) || defined(__WXPM__)
535 // Windows and OS/2: sections are displayed as drives
536 wxTreeItemId id = m_treeCtrl->AppendItem( m_rootId, name, imageId, -1, dir_item);
537 #else
538 // Unix: sections are displayed as folders
539 wxTreeItemId id = m_treeCtrl->AppendItem( m_rootId, name, 0, -1, dir_item);
540 m_treeCtrl->SetItemImage( id, 1, wxTreeItemIcon_Expanded );
541 #endif
542 // TODO: other operating systems.
543
544 m_treeCtrl->SetItemHasChildren(id);
545 }
546
547 void wxGenericDirCtrl::SetupSections()
548 {
549 #if defined(__WXMSW__) || defined(__WXPM__)
550
551 # ifdef __WIN32__
552 wxChar driveBuffer[256];
553 size_t n = (size_t) GetLogicalDriveStrings(255, driveBuffer);
554 size_t i = 0;
555 while (i < n)
556 {
557 wxString path, name;
558 path.Printf(wxT("%c:\\"), driveBuffer[i]);
559 name.Printf(wxT("(%c:)"), driveBuffer[i]);
560
561 int imageId = 4;
562 int driveType = ::GetDriveType(path);
563 switch (driveType)
564 {
565 case DRIVE_REMOVABLE:
566 if (path == wxT("a:\\") || path == wxT("b:\\"))
567 imageId = 6; // Floppy
568 else
569 imageId = 7;
570 break;
571 case DRIVE_FIXED:
572 imageId = 4;
573 break;
574 case DRIVE_REMOTE:
575 imageId = 4;
576 break;
577 case DRIVE_CDROM:
578 imageId = 5;
579 break;
580 default:
581 imageId = 4;
582 break;
583 }
584
585 AddSection(path, name, imageId);
586
587 while (driveBuffer[i] != wxT('\0'))
588 i ++;
589 i ++;
590 if (driveBuffer[i] == wxT('\0'))
591 break;
592 }
593 # else
594 int drive;
595 int currentDrive;
596
597 /* If we can switch to the drive, it exists. */
598 for( drive = 1; drive <= 26; drive++ )
599 {
600 wxString path, name;
601 path.Printf(wxT("%c:\\"), (char) (drive + 'a' - 1));
602 name.Printf(wxT("(%c:)"), (char) (drive + 'a' - 1));
603
604 if (wxIsDriveAvailable(path))
605 {
606
607 AddSection(path, name);
608 }
609 }
610 # endif
611 #elif defined(__WXMAC__)
612 FSSpec volume ;
613 short index = 1 ;
614 while(1) {
615 short actualCount = 0 ;
616 if ( OnLine( &volume , 1 , &actualCount , &index ) != noErr || actualCount == 0 )
617 break ;
618
619 wxString name = wxMacFSSpec2MacFilename( &volume ) ;
620 AddSection(name + wxFILE_SEP_PATH, name, 0);
621 }
622 #else
623 AddSection(wxT("/"), _("The Computer"), 0);
624 AddSection(wxGetHomeDir(), _("My Home"), 0 );
625 AddSection(wxT("/mnt"), _("Mounted Devices"), 0 );
626 AddSection(wxT("/usr/local"), _("User Local"), 0 );
627 AddSection(wxT("/usr"), _("User"), 0 );
628 AddSection(wxT("/var"), _("Variables"), 0 );
629 AddSection(wxT("/etc"), _("Etcetera"), 0 );
630 AddSection(wxT("/tmp"), _("Temporary"), 0 );
631 #endif
632 }
633
634 void wxGenericDirCtrl::OnBeginEditItem(wxTreeEvent &event)
635 {
636 // don't rename the main entry "Sections"
637 if (event.GetItem() == m_rootId)
638 {
639 event.Veto();
640 return;
641 }
642
643 // don't rename the individual sections
644 if (m_treeCtrl->GetParent( event.GetItem() ) == m_rootId)
645 {
646 event.Veto();
647 return;
648 }
649 }
650
651 void wxGenericDirCtrl::OnEndEditItem(wxTreeEvent &event)
652 {
653 if ((event.GetLabel().IsEmpty()) ||
654 (event.GetLabel() == _(".")) ||
655 (event.GetLabel() == _("..")) ||
656 (event.GetLabel().First( wxT("/") ) != wxNOT_FOUND))
657 {
658 wxMessageDialog dialog(this, _("Illegal directory name."), _("Error"), wxOK | wxICON_ERROR );
659 dialog.ShowModal();
660 event.Veto();
661 return;
662 }
663
664 wxTreeItemId id = event.GetItem();
665 wxDirItemDataEx *data = (wxDirItemDataEx*)m_treeCtrl->GetItemData( id );
666 wxASSERT( data );
667
668 wxString new_name( wxPathOnly( data->m_path ) );
669 new_name += wxString(wxFILE_SEP_PATH);
670 new_name += event.GetLabel();
671
672 wxLogNull log;
673
674 if (wxFileExists(new_name))
675 {
676 wxMessageDialog dialog(this, _("File name exists already."), _("Error"), wxOK | wxICON_ERROR );
677 dialog.ShowModal();
678 event.Veto();
679 }
680
681 if (wxRenameFile(data->m_path,new_name))
682 {
683 data->SetNewDirName( new_name );
684 }
685 else
686 {
687 wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
688 dialog.ShowModal();
689 event.Veto();
690 }
691 }
692
693 void wxGenericDirCtrl::OnExpandItem(wxTreeEvent &event)
694 {
695 wxTreeItemId parentId = event.GetItem();
696
697 ExpandDir(parentId);
698 }
699
700 void wxGenericDirCtrl::OnCollapseItem(wxTreeEvent &event )
701 {
702 wxTreeItemId child, parent = event.GetItem();
703
704 wxDirItemDataEx *data = (wxDirItemDataEx *) m_treeCtrl->GetItemData(event.GetItem());
705 if (!data->m_isExpanded)
706 return;
707
708 data->m_isExpanded = FALSE;
709 long cookie;
710 /* Workaround because DeleteChildren has disapeared (why?) and
711 * CollapseAndReset doesn't work as advertised (deletes parent too) */
712 child = m_treeCtrl->GetFirstChild(parent, cookie);
713 while (child.IsOk())
714 {
715 m_treeCtrl->Delete(child);
716 /* Not GetNextChild below, because the cookie mechanism can't
717 * handle disappearing children! */
718 child = m_treeCtrl->GetFirstChild(parent, cookie);
719 }
720 }
721
722 void wxGenericDirCtrl::ExpandDir(wxTreeItemId parentId)
723 {
724 wxDirItemDataEx *data = (wxDirItemDataEx *) m_treeCtrl->GetItemData(parentId);
725
726 if (data->m_isExpanded)
727 return;
728
729 data->m_isExpanded = TRUE;
730
731 if (parentId == m_rootId)
732 {
733 SetupSections();
734 return;
735 }
736
737 wxASSERT(data);
738
739 wxString search,path,filename;
740
741 wxString dirName(data->m_path);
742
743 #if defined(__WXMSW__) || defined(__WXPM__)
744 // Check if this is a root directory and if so,
745 // whether the drive is avaiable.
746 if (!wxIsDriveAvailable(dirName))
747 {
748 data->m_isExpanded = FALSE;
749 //wxMessageBox(wxT("Sorry, this drive is not available."));
750 return;
751 }
752 #endif
753
754 // This may take a longish time. Go to busy cursor
755 wxBusyCursor busy;
756
757 #if defined(__WXMSW__) || defined(__WXPM__)
758 if (dirName.Last() == ':')
759 dirName += wxString(wxFILE_SEP_PATH);
760 #endif
761
762 wxArrayString dirs;
763 wxArrayString filenames;
764
765 wxDir d;
766 wxString eachFilename;
767
768 wxLogNull log;
769 d.Open(dirName);
770
771 if (d.IsOpened())
772 {
773 if (d.GetFirst(& eachFilename, wxEmptyString, wxDIR_DIRS))
774 {
775 do
776 {
777 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
778 {
779 dirs.Add(eachFilename);
780 }
781 }
782 while (d.GetNext(& eachFilename)) ;
783 }
784 }
785 dirs.Sort((wxArrayString::CompareFunction) wxDirCtrlStringCompareFunction);
786
787 // Now do the filenames -- but only if we're allowed to
788 if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0)
789 {
790 wxLogNull log;
791
792 d.Open(dirName);
793
794 if (d.IsOpened())
795 {
796 if (d.GetFirst(& eachFilename, m_currentFilterStr, wxDIR_FILES))
797 {
798 do
799 {
800 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
801 {
802 filenames.Add(eachFilename);
803 }
804 }
805 while (d.GetNext(& eachFilename)) ;
806 }
807 }
808 filenames.Sort((wxArrayString::CompareFunction) wxDirCtrlStringCompareFunction);
809 }
810
811 // Add the sorted dirs
812 size_t i;
813 for (i = 0; i < dirs.Count(); i++)
814 {
815 wxString eachFilename(dirs[i]);
816 path = dirName;
817 if (path.Last() != wxFILE_SEP_PATH)
818 path += wxString(wxFILE_SEP_PATH);
819 path += eachFilename;
820
821 wxDirItemDataEx *dir_item = new wxDirItemDataEx(path,eachFilename,TRUE);
822 wxTreeItemId id = m_treeCtrl->AppendItem( parentId, eachFilename, 0, -1, dir_item);
823 m_treeCtrl->SetItemImage( id, 1, wxTreeItemIcon_Expanded );
824
825 // Has this got any children? If so, make it expandable.
826 int options = wxDIR_DEFAULT;
827 if (GetWindowStyle() & wxDIRCTRL_DIR_ONLY) // If only showing dirs, then we specify dirs only here
828 {
829 options = wxDIR_DIRS;
830 }
831
832 wxLogNull log;
833 wxDir dir2;
834 if (dir2.Open(path))
835 {
836 wxString str;
837 // Have to test for wxDIR_DIRS separately in case m_currentFilterStr is non-empty and
838 // and filters out any directories
839 if (dir2.GetFirst(& str, m_currentFilterStr, options) || dir2.GetFirst(& str, wxEmptyString, wxDIR_DIRS))
840 {
841 m_treeCtrl->SetItemHasChildren(id);
842 }
843 }
844 }
845
846 // Add the sorted filenames
847 if ((GetWindowStyle() & wxDIRCTRL_DIR_ONLY) == 0)
848 {
849 for (i = 0; i < filenames.Count(); i++)
850 {
851 wxString eachFilename(filenames[i]);
852 path = dirName;
853 if (path.Last() != wxFILE_SEP_PATH)
854 path += wxString(wxFILE_SEP_PATH);
855 path += eachFilename;
856 //path = dirName + wxString(wxT("/")) + eachFilename;
857 wxDirItemDataEx *dir_item = new wxDirItemDataEx(path,eachFilename,FALSE);
858 (void)m_treeCtrl->AppendItem( parentId, eachFilename, 2, -1, dir_item);
859 }
860 }
861 }
862
863 // Find the child that matches the first part of 'path'.
864 // E.g. if a child path is "/usr" and 'path' is "/usr/include"
865 // then the child for /usr is returned.
866 wxTreeItemId wxGenericDirCtrl::FindChild(wxTreeItemId parentId, const wxString& path, bool& done)
867 {
868 wxString path2(path);
869
870 // Make sure all separators are as per the current platform
871 path2.Replace(wxT("\\"), wxString(wxFILE_SEP_PATH));
872 path2.Replace(wxT("/"), wxString(wxFILE_SEP_PATH));
873
874 // Append a separator to foil bogus substring matching
875 path2 += wxString(wxFILE_SEP_PATH);
876
877 // In MSW or PM, case is not significant
878 #if defined(__WXMSW__) || defined(__WXPM__)
879 path2.MakeLower();
880 #endif
881
882 long cookie;
883 wxTreeItemId childId = m_treeCtrl->GetFirstChild(parentId, cookie);
884 while (childId.IsOk())
885 {
886 wxDirItemDataEx* data = (wxDirItemDataEx*) m_treeCtrl->GetItemData(childId);
887
888 if (data && data->m_path != "")
889 {
890 wxString childPath(data->m_path);
891 if (childPath.Last() != wxFILE_SEP_PATH)
892 childPath += wxString(wxFILE_SEP_PATH);
893
894 // In MSW and PM, case is not significant
895 #if defined(__WXMSW__) || defined(__WXPM__)
896 childPath.MakeLower();
897 #endif
898
899 if (childPath.Len() <= path2.Len())
900 {
901 wxString path3 = path2.Mid(0, childPath.Len());
902 if (childPath == path3)
903 {
904 if (path3.Len() == path2.Len())
905 done = TRUE;
906 else
907 done = FALSE;
908 return childId;
909 }
910 }
911 }
912
913 childId = m_treeCtrl->GetNextChild(childId, cookie);
914 }
915 wxTreeItemId invalid;
916 return invalid;
917 }
918
919 // Try to expand as much of the given path as possible,
920 // and select the given tree item.
921 bool wxGenericDirCtrl::ExpandPath(const wxString& path)
922 {
923 bool done = FALSE;
924 wxTreeItemId id = FindChild(m_rootId, path, done);
925 wxTreeItemId lastId = id; // The last non-zero id
926 while (id.IsOk() && !done)
927 {
928 ExpandDir(id);
929
930 id = FindChild(id, path, done);
931 if (id.IsOk())
932 lastId = id;
933 }
934 if (lastId.IsOk())
935 {
936 wxDirItemDataEx *data = (wxDirItemDataEx *) m_treeCtrl->GetItemData(lastId);
937 if (data->m_isDir)
938 {
939 m_treeCtrl->Expand(lastId);
940 }
941 if ((GetWindowStyle() & wxDIRCTRL_SELECT_FIRST) && data->m_isDir)
942 {
943 // Find the first file in this directory
944 long cookie;
945 wxTreeItemId childId = m_treeCtrl->GetFirstChild(lastId, cookie);
946 bool selectedChild = FALSE;
947 while (childId.IsOk())
948 {
949 wxDirItemDataEx* data = (wxDirItemDataEx*) m_treeCtrl->GetItemData(childId);
950
951 if (data && data->m_path != "" && !data->m_isDir)
952 {
953 m_treeCtrl->SelectItem(childId);
954 m_treeCtrl->EnsureVisible(childId);
955 selectedChild = TRUE;
956 break;
957 }
958 childId = m_treeCtrl->GetNextChild(lastId, cookie);
959 }
960 if (!selectedChild)
961 {
962 m_treeCtrl->SelectItem(lastId);
963 m_treeCtrl->EnsureVisible(lastId);
964 }
965 }
966 else
967 {
968 m_treeCtrl->SelectItem(lastId);
969 m_treeCtrl->EnsureVisible(lastId);
970 }
971
972 return TRUE;
973 }
974 else
975 return FALSE;
976 }
977
978 wxString wxGenericDirCtrl::GetPath() const
979 {
980 wxTreeItemId id = m_treeCtrl->GetSelection();
981 if (id)
982 {
983 wxDirItemDataEx* data = (wxDirItemDataEx*) m_treeCtrl->GetItemData(id);
984 return data->m_path;
985 }
986 else
987 return wxEmptyString;
988 }
989
990 wxString wxGenericDirCtrl::GetFilePath() const
991 {
992 wxTreeItemId id = m_treeCtrl->GetSelection();
993 if (id)
994 {
995 wxDirItemDataEx* data = (wxDirItemDataEx*) m_treeCtrl->GetItemData(id);
996 if (data->m_isDir)
997 return wxEmptyString;
998 else
999 return data->m_path;
1000 }
1001 else
1002 return wxEmptyString;
1003 }
1004
1005 void wxGenericDirCtrl::SetPath(const wxString& path)
1006 {
1007 m_defaultPath = path;
1008 if (m_rootId)
1009 ExpandPath(path);
1010 }
1011
1012 // Not used
1013 #if 0
1014 void wxGenericDirCtrl::FindChildFiles(wxTreeItemId id, int dirFlags, wxArrayString& filenames)
1015 {
1016 wxDirItemDataEx *data = (wxDirItemDataEx *) m_treeCtrl->GetItemData(id);
1017
1018 // This may take a longish time. Go to busy cursor
1019 wxBusyCursor busy;
1020
1021 wxASSERT(data);
1022
1023 wxString search,path,filename;
1024
1025 wxString dirName(data->m_path);
1026
1027 #if defined(__WXMSW__) || defined(__WXPM__)
1028 if (dirName.Last() == ':')
1029 dirName += wxString(wxFILE_SEP_PATH);
1030 #endif
1031
1032 wxDir d;
1033 wxString eachFilename;
1034
1035 wxLogNull log;
1036 d.Open(dirName);
1037
1038 if (d.IsOpened())
1039 {
1040 if (d.GetFirst(& eachFilename, m_currentFilterStr, dirFlags))
1041 {
1042 do
1043 {
1044 if ((eachFilename != wxT(".")) && (eachFilename != wxT("..")))
1045 {
1046 filenames.Add(eachFilename);
1047 }
1048 }
1049 while (d.GetNext(& eachFilename)) ;
1050 }
1051 }
1052 }
1053 #endif
1054
1055 void wxGenericDirCtrl::SetFilterIndex(int n)
1056 {
1057 m_currentFilter = n;
1058
1059 wxString f, d;
1060 if (ExtractWildcard(m_filter, n, f, d))
1061 m_currentFilterStr = f;
1062 else
1063 m_currentFilterStr = wxT("*.*");
1064 }
1065
1066 void wxGenericDirCtrl::SetFilter(const wxString& filter)
1067 {
1068 m_filter = filter;
1069
1070 wxString f, d;
1071 if (ExtractWildcard(m_filter, m_currentFilter, f, d))
1072 m_currentFilterStr = f;
1073 else
1074 m_currentFilterStr = wxT("*.*");
1075 }
1076
1077 // Extract description and actual filter from overall filter string
1078 bool wxGenericDirCtrl::ExtractWildcard(const wxString& filterStr, int n, wxString& filter, wxString& description)
1079 {
1080 wxArrayString filters, descriptions;
1081 int count = ParseFilter(filterStr, filters, descriptions);
1082 if (count > 0 && n < count)
1083 {
1084 filter = filters[n];
1085 description = descriptions[n];
1086 return TRUE;
1087 }
1088
1089 return FALSE;
1090 }
1091
1092 // Parses the global filter, returning the number of filters.
1093 // Returns 0 if none or if there's a problem.
1094 // filterStr is in the form:
1095 //
1096 // "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpg"
1097
1098 int wxGenericDirCtrl::ParseFilter(const wxString& filterStr, wxArrayString& filters, wxArrayString& descriptions)
1099 {
1100 wxString str(filterStr);
1101
1102 wxString description, filter;
1103 int pos;
1104 bool finished = FALSE;
1105 do
1106 {
1107 pos = str.Find(wxT('|'));
1108 if (pos == -1)
1109 return 0; // Problem
1110 description = str.Left(pos);
1111 str = str.Mid(pos+1);
1112 pos = str.Find(wxT('|'));
1113 if (pos == -1)
1114 {
1115 filter = str;
1116 finished = TRUE;
1117 }
1118 else
1119 {
1120 filter = str.Left(pos);
1121 str = str.Mid(pos+1);
1122 }
1123 descriptions.Add(description);
1124 filters.Add(filter);
1125 }
1126 while (!finished) ;
1127
1128 return filters.Count();
1129 }
1130
1131 void wxGenericDirCtrl::DoResize()
1132 {
1133 wxSize sz = GetClientSize();
1134 int verticalSpacing = 3;
1135 if (m_treeCtrl)
1136 {
1137 wxSize filterSz ;
1138 if (m_filterListCtrl)
1139 {
1140 filterSz = m_filterListCtrl->GetSize();
1141 sz.y -= (filterSz.y + verticalSpacing);
1142 }
1143 m_treeCtrl->SetSize(0, 0, sz.x, sz.y);
1144 if (m_filterListCtrl)
1145 {
1146 m_filterListCtrl->SetSize(0, sz.y + verticalSpacing, sz.x, filterSz.y);
1147 // Don't know why, but this needs refreshing after a resize (wxMSW)
1148 m_filterListCtrl->Refresh();
1149 }
1150 }
1151 }
1152
1153
1154 void wxGenericDirCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
1155 {
1156 DoResize();
1157 }
1158
1159 //-----------------------------------------------------------------------------
1160 // wxDirFilterListCtrl
1161 //-----------------------------------------------------------------------------
1162
1163 IMPLEMENT_CLASS(wxDirFilterListCtrl, wxChoice)
1164
1165 BEGIN_EVENT_TABLE(wxDirFilterListCtrl, wxChoice)
1166 EVT_CHOICE(-1, wxDirFilterListCtrl::OnSelFilter)
1167 END_EVENT_TABLE()
1168
1169 bool wxDirFilterListCtrl::Create(wxGenericDirCtrl* parent, const wxWindowID id,
1170 const wxPoint& pos,
1171 const wxSize& size,
1172 long style)
1173 {
1174 m_dirCtrl = parent;
1175 return wxChoice::Create(parent, id, pos, size, 0, NULL, style);
1176 }
1177
1178 void wxDirFilterListCtrl::Init()
1179 {
1180 m_dirCtrl = NULL;
1181 }
1182
1183 void wxDirFilterListCtrl::OnSelFilter(wxCommandEvent& WXUNUSED(event))
1184 {
1185 int sel = GetSelection();
1186
1187 wxString currentPath = m_dirCtrl->GetPath();
1188
1189 m_dirCtrl->SetFilterIndex(sel);
1190
1191 // If the filter has changed, the view is out of date, so
1192 // collapse the tree.
1193 m_dirCtrl->GetTreeCtrl()->Collapse(m_dirCtrl->GetRootId());
1194 m_dirCtrl->GetTreeCtrl()->Expand(m_dirCtrl->GetRootId());
1195
1196 // Try to restore the selection, or at least the directory
1197 m_dirCtrl->ExpandPath(currentPath);
1198 }
1199
1200 void wxDirFilterListCtrl::FillFilterList(const wxString& filter, int defaultFilter)
1201 {
1202 Clear();
1203 wxArrayString descriptions, filters;
1204 size_t n = (size_t) m_dirCtrl->ParseFilter(filter, filters, descriptions);
1205
1206 if (n > 0 && defaultFilter < (int) n)
1207 {
1208 size_t i = 0;
1209 for (i = 0; i < n; i++)
1210 Append(descriptions[i]);
1211 SetSelection(defaultFilter);
1212 }
1213 }
1214
1215 // wxGenericDirDialog implementation
1216 // This should be moved into dirdlgg.cpp eventually
1217
1218 BEGIN_EVENT_TABLE(wxGenericDirDialog, wxDialog)
1219 EVT_BUTTON(wxID_OK, wxGenericDirDialog::OnOK)
1220 EVT_BUTTON(wxID_NEW, wxGenericDirDialog::OnNew)
1221 EVT_BUTTON (wxID_NEW, wxGenericDirDialog::OnNew)
1222 EVT_CLOSE(wxGenericDirDialog::OnCloseWindow)
1223 EVT_TREE_KEY_DOWN (-1, wxGenericDirDialog::OnTreeKeyDown)
1224 EVT_TREE_SEL_CHANGED (-1, wxGenericDirDialog::OnTreeSelected)
1225 EVT_TEXT_ENTER (ID_TEXTCTRL, wxGenericDirDialog::OnOK)
1226 END_EVENT_TABLE()
1227
1228 wxGenericDirDialog::wxGenericDirDialog(wxWindow* parent, const wxString& title,
1229 const wxString& defaultPath, long style, const wxPoint& pos, const wxSize& sz, const wxString& name):
1230 wxDialog(parent, ID_DIRCTRL, title, pos, sz, style, name)
1231 {
1232 m_dirCtrl = NULL;
1233 m_path = defaultPath;
1234
1235 wxBusyCursor cursor;
1236
1237 wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
1238
1239 // 1) dir ctrl
1240 m_dirCtrl = new wxGenericDirCtrl(this, ID_DIRCTRL,
1241 defaultPath, wxPoint(5, 5),
1242 wxSize(300, 200), wxDIRCTRL_DIR_ONLY|wxSUNKEN_BORDER);
1243
1244 topsizer->Add( m_dirCtrl, 1, wxTOP|wxLEFT|wxRIGHT | wxEXPAND, 10 );
1245
1246 // 2) text ctrl
1247 m_input = new wxTextCtrl( this, ID_TEXTCTRL, m_path, wxDefaultPosition );
1248 topsizer->Add( m_input, 0, wxTOP|wxLEFT|wxRIGHT | wxEXPAND, 10 );
1249
1250 #if wxUSE_STATLINE
1251 // 3) Static line
1252 topsizer->Add( new wxStaticLine( this, -1 ), 0, wxEXPAND | wxLEFT|wxRIGHT|wxTOP, 10 );
1253 #endif
1254
1255 // 4) Buttons
1256 wxSizer* buttonsizer = new wxBoxSizer( wxHORIZONTAL );
1257 wxButton* okButton = new wxButton(this, wxID_OK, _("OK"));
1258 buttonsizer->Add( okButton, 0, wxLEFT|wxRIGHT, 10 );
1259 wxButton* cancelButton = new wxButton(this, wxID_CANCEL, _("Cancel"));
1260 buttonsizer->Add( cancelButton, 0, wxLEFT|wxRIGHT, 10 );
1261
1262 // I'm not convinced we need a New button, and we tend to get annoying
1263 // accidental-editing with label editing enabled.
1264 #if 0
1265 wxButton* newButton = new wxButton( this, wxID_NEW, _("New...") );
1266 buttonsizer->Add( newButton, 0, wxLEFT|wxRIGHT, 10 );
1267 #endif
1268
1269 topsizer->Add( buttonsizer, 0, wxALL | wxCENTER, 10 );
1270
1271 okButton->SetDefault();
1272 m_dirCtrl->SetFocus();
1273
1274 SetAutoLayout( TRUE );
1275 SetSizer( topsizer );
1276
1277 topsizer->SetSizeHints( this );
1278 topsizer->Fit( this );
1279
1280 Centre( wxBOTH );
1281 }
1282
1283 void wxGenericDirDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
1284 {
1285 EndModal(wxID_CANCEL);
1286 }
1287
1288 void wxGenericDirDialog::OnOK(wxCommandEvent& WXUNUSED(event))
1289 {
1290 m_path = m_input->GetValue();
1291 // Does the path exist? (User may have typed anything in m_input)
1292 if (wxPathExists(m_path)) {
1293 // OK, path exists, we're done.
1294 EndModal(wxID_OK);
1295 return;
1296 }
1297 // Interact with user, find out if the dir is a typo or to be created
1298 wxString msg( _("The directory ") );
1299 msg = msg + m_path;
1300 msg = msg + _("\ndoes not exist\nCreate it now?") ;
1301 wxMessageDialog dialog(this, msg, _("Directory does not exist"), wxYES_NO | wxICON_WARNING );
1302 if ( dialog.ShowModal() == wxID_YES ) {
1303 // Okay, let's make it
1304 wxLogNull log;
1305 if (wxMkdir(m_path)) {
1306 // The new dir was created okay.
1307 EndModal(wxID_OK);
1308 return;
1309 }
1310 else {
1311 // Trouble...
1312 msg = _("Failed to create directory ")+m_path+
1313 _("\n(Do you have the required permissions?)");
1314 wxMessageDialog errmsg(this, msg, _("Error creating directory"), wxOK | wxICON_ERROR);
1315 errmsg.ShowModal();
1316 // We still don't have a valid dir. Back to the main dialog.
1317 }
1318 }
1319 // User has answered NO to create dir.
1320 }
1321
1322 void wxGenericDirDialog::SetPath(const wxString& path)
1323 {
1324 m_dirCtrl->SetPath(path);
1325 m_path = path;
1326 }
1327
1328 wxString wxGenericDirDialog::GetPath(void) const
1329 {
1330 return m_path;
1331 }
1332
1333 int wxGenericDirDialog::ShowModal()
1334 {
1335 //m_input->SetValue( m_path );
1336 return wxDialog::ShowModal();
1337 }
1338
1339 void wxGenericDirDialog::OnTreeSelected( wxTreeEvent &event )
1340 {
1341 if (!m_dirCtrl)
1342 return;
1343
1344 wxDirItemDataEx *data = (wxDirItemDataEx*)m_dirCtrl->GetTreeCtrl()->GetItemData(event.GetItem());
1345 if (data)
1346 m_input->SetValue( data->m_path );
1347 };
1348
1349 void wxGenericDirDialog::OnTreeKeyDown( wxTreeEvent &WXUNUSED(event) )
1350 {
1351 if (!m_dirCtrl)
1352 return;
1353
1354 wxDirItemDataEx *data = (wxDirItemDataEx*)m_dirCtrl->GetTreeCtrl()->GetItemData(m_dirCtrl->GetTreeCtrl()->GetSelection());
1355 if (data)
1356 m_input->SetValue( data->m_path );
1357 };
1358
1359 void wxGenericDirDialog::OnNew( wxCommandEvent& WXUNUSED(event) )
1360 {
1361 wxTreeItemId id = m_dirCtrl->GetTreeCtrl()->GetSelection();
1362 if ((id == m_dirCtrl->GetTreeCtrl()->GetRootItem()) ||
1363 (m_dirCtrl->GetTreeCtrl()->GetParent(id) == m_dirCtrl->GetTreeCtrl()->GetRootItem()))
1364 {
1365 wxMessageDialog msg(this, _("You cannot add a new directory to this section."),
1366 _("Create directory"), wxOK | wxICON_INFORMATION );
1367 msg.ShowModal();
1368 return;
1369 }
1370
1371 wxTreeItemId parent = id ; // m_dirCtrl->GetTreeCtrl()->GetParent( id );
1372 wxDirItemDataEx *data = (wxDirItemDataEx*)m_dirCtrl->GetTreeCtrl()->GetItemData( parent );
1373 wxASSERT( data );
1374
1375 wxString new_name( wxT("NewName") );
1376 wxString path( data->m_path );
1377 if (path.Last() != wxFILE_SEP_PATH)
1378 path += wxFILE_SEP_PATH;
1379 path += new_name;
1380 if (wxFileExists(path))
1381 {
1382 // try NewName0, NewName1 etc.
1383 int i = 0;
1384 do {
1385 new_name = wxT("NewName");
1386 wxString num;
1387 num.Printf( wxT("%d"), i );
1388 new_name += num;
1389
1390 path = data->m_path;
1391 if (path.Last() != wxFILE_SEP_PATH)
1392 path += wxFILE_SEP_PATH;
1393 path += new_name;
1394 i++;
1395 } while (wxFileExists(path));
1396 }
1397
1398 wxLogNull log;
1399 if (!wxMkdir(path))
1400 {
1401 wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
1402 dialog.ShowModal();
1403 return;
1404 }
1405
1406 wxDirItemDataEx *new_data = new wxDirItemDataEx( path, new_name, TRUE );
1407
1408 // TODO: THIS CODE DOESN'T WORK YET. We need to avoid duplication of the first child
1409 // of the parent.
1410 wxTreeItemId new_id = m_dirCtrl->GetTreeCtrl()->AppendItem( parent, new_name, 0, 0, new_data );
1411 m_dirCtrl->GetTreeCtrl()->EnsureVisible( new_id );
1412 m_dirCtrl->GetTreeCtrl()->EditLabel( new_id );
1413 }
1414
1415 #endif // wxUSE_DIRDLG