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