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