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