]> git.saurik.com Git - wxWidgets.git/blame - src/generic/dirdlgg.cpp
Fixed core dump for when there is no image list on the TreeCtrl
[wxWidgets.git] / src / generic / dirdlgg.cpp
CommitLineData
d7a15103
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: dirdlg.cpp
3// Purpose: wxDirDialog
4// Author: Harm van der Heijden and Robert Roebling
5// Modified by:
6// Created: 12/12/98
7// Copyright: (c) Harm van der Heijden and Robert Roebling
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11#ifdef __GNUG__
12#pragma implementation "dirdlgg.h"
13#endif
14
1e6d9499
JS
15// For compilers that support precompilation, includes "wx.h".
16#include "wx/wxprec.h"
17
18#ifdef __BORLANDC__
19#pragma hdrstop
20#endif
21
d7a15103 22#include "wx/defs.h"
ce4169a4
RR
23
24#if wxUSE_DIRDLG
25
d7a15103
JS
26#include "wx/utils.h"
27#include "wx/dialog.h"
28#include "wx/button.h"
29#include "wx/layout.h"
30#include "wx/msgdlg.h"
31#include "wx/textdlg.h"
32#include "wx/filefn.h"
33#include "wx/cmndata.h"
34#include "wx/gdicmn.h"
35#include "wx/intl.h"
36#include "wx/imaglist.h"
25889d3c 37#include "wx/icon.h"
d7a15103
JS
38
39#include "wx/generic/dirdlgg.h"
40
4bf78aae
JS
41// If compiled under Windows, this macro can cause problems
42#ifdef GetFirstChild
43#undef GetFirstChild
44#endif
45
d7a15103
JS
46/* XPM */
47static char * icon1_xpm[] = {
48/* width height ncolors chars_per_pixel */
49"16 16 6 1",
50/* colors */
51" s None c None",
52". c #000000",
53"+ c #c0c0c0",
54"@ c #808080",
55"# c #ffff00",
56"$ c #ffffff",
57/* pixels */
58" ",
59" @@@@@ ",
60" @#+#+#@ ",
61" @#+#+#+#@@@@@@ ",
62" @$$$$$$$$$$$$@.",
63" @$#+#+#+#+#+#@.",
64" @$+#+#+#+#+#+@.",
65" @$#+#+#+#+#+#@.",
66" @$+#+#+#+#+#+@.",
67" @$#+#+#+#+#+#@.",
68" @$+#+#+#+#+#+@.",
69" @$#+#+#+#+#+#@.",
70" @@@@@@@@@@@@@@.",
71" ..............",
72" ",
73" "};
74
0659e7ee
RR
75/* XPM */
76static char * icon2_xpm[] = {
77/* width height ncolors chars_per_pixel */
78"16 16 6 1",
79/* colors */
80" s None c None",
81". c #000000",
82"+ c #c0c0c0",
83"@ c #808080",
84"# c #ffff00",
85"$ c #ffffff",
86/* pixels */
87" ",
88" @@@@@ ",
89" @$$$$$@ ",
90" @$#+#+#$@@@@@@ ",
91" @$+#+#+$$$$$$@.",
92" @$#+#+#+#+#+#@.",
93"@@@@@@@@@@@@@#@.",
94"@$$$$$$$$$$@@+@.",
95"@$#+#+#+#+##.@@.",
96" @$#+#+#+#+#+.@.",
97" @$+#+#+#+#+#.@.",
98" @$+#+#+#+##@..",
99" @@@@@@@@@@@@@.",
100" .............",
101" ",
102" "};
d7a15103
JS
103
104static const int ID_DIRCTRL = 1000;
105static const int ID_TEXTCTRL = 1001;
106static const int ID_OK = 1002;
107static const int ID_CANCEL = 1003;
108static const int ID_NEW = 1004;
109//static const int ID_CHECK = 1005;
110
111//-----------------------------------------------------------------------------
112// wxDirItemData
113//-----------------------------------------------------------------------------
114
0659e7ee
RR
115class wxDirItemData : public wxTreeItemData
116{
117public:
118 wxDirItemData(wxString& path, wxString& name);
119 ~wxDirItemData();
120 bool HasSubDirs();
121 wxString *m_path, *m_name;
122 bool m_isHidden;
123 bool m_hasSubDirs;
124};
125
126//-----------------------------------------------------------------------------
127// wxDirCtrl
128//-----------------------------------------------------------------------------
129
130class wxDirCtrl: public wxTreeCtrl
131{
132 DECLARE_DYNAMIC_CLASS(wxDirCtrl)
133
134 public:
135 bool m_showHidden;
136 wxTreeItemId m_rootId;
137
138 wxDirCtrl(void);
139 wxDirCtrl(wxWindow *parent, const wxWindowID id = -1,
140 const wxString &dir = "/",
141 const wxPoint& pos = wxDefaultPosition,
142 const wxSize& size = wxDefaultSize,
143 const long style = wxTR_HAS_BUTTONS,
144 const wxString& name = "wxTreeCtrl" );
1e6d9499
JS
145 void OnExpandItem(wxTreeEvent &event );
146 void OnCollapseItem(wxTreeEvent &event );
0659e7ee
RR
147 void ShowHidden( const bool yesno );
148 DECLARE_EVENT_TABLE()
149 protected:
150 void CreateItems(const wxTreeItemId &parent);
151 void SetupSections(void);
152 wxArrayString m_paths, m_names;
153};
154
155//-----------------------------------------------------------------------------
156// wxDirItemData
157//-----------------------------------------------------------------------------
158
d7a15103
JS
159wxDirItemData::wxDirItemData(wxString& path, wxString& name)
160{
161 m_path = new wxString(path);
162 m_name = new wxString(name);
163 /* Insert logic to detect hidden files here
164 * In UnixLand we just check whether the first char is a dot
165 * For FileNameFromPath read LastDirNameInThisPath ;-) */
166 // m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.');
167 m_isHidden = FALSE;
168 m_hasSubDirs = HasSubDirs();
169}
170
171wxDirItemData:: ~wxDirItemData()
172{
173 delete m_path;
174 delete m_name;
175}
176
177bool wxDirItemData::HasSubDirs()
178{
179 wxString search = *m_path + "/*";
180 wxString path = wxFindFirstFile( search, wxDIR );
181 return (bool)(!path.IsNull());
182}
183
184//-----------------------------------------------------------------------------
185// wxDirCtrl
186//-----------------------------------------------------------------------------
187
188IMPLEMENT_DYNAMIC_CLASS(wxDirCtrl,wxTreeCtrl)
189
190BEGIN_EVENT_TABLE(wxDirCtrl,wxTreeCtrl)
191 EVT_TREE_ITEM_EXPANDING (-1, wxDirCtrl::OnExpandItem)
192 EVT_TREE_ITEM_COLLAPSED (-1, wxDirCtrl::OnCollapseItem)
193END_EVENT_TABLE()
194
195wxDirCtrl::wxDirCtrl(void)
196{
197 m_showHidden = FALSE;
198};
199
200wxDirCtrl::wxDirCtrl(wxWindow *parent, const wxWindowID id, const wxString &WXUNUSED(dir),
201 const wxPoint& pos, const wxSize& size,
202 const long style, const wxString& name )
203 :
204 wxTreeCtrl( parent, id, pos, size, style, wxDefaultValidator, name )
205{
206 m_imageListNormal = new wxImageList(16, 16, TRUE);
207 m_imageListNormal->Add(wxICON(icon1));
0659e7ee 208 m_imageListNormal->Add(wxICON(icon2));
d7a15103
JS
209 SetImageList(m_imageListNormal);
210
211 m_showHidden = FALSE;
212 m_rootId = AddRoot("Sections");
213 SetItemHasChildren(m_rootId);
214 Expand(m_rootId); // automatically expand first level
215};
216
217/* Quick macro. Don't worry, I'll #undef it later */
218#define ADD_SECTION(a,b) \
219 if (wxPathExists((a))) { m_paths.Add( (a) ); m_names.Add( (b) ); };
220
221void wxDirCtrl::SetupSections()
222{
223 wxString home;
224
225 m_paths.Clear();
226 m_names.Clear();
87138c52 227 ADD_SECTION(_T("/"), _("The Computer") )
d7a15103
JS
228 wxGetHomeDir(&home);
229 ADD_SECTION(home, _("My Home") )
87138c52
OK
230 ADD_SECTION(_T("/mnt"), _("Mounted Devices") )
231 ADD_SECTION(_T("/usr"), _("User") )
232 ADD_SECTION(_T("/usr/local"), _("User Local") )
233 ADD_SECTION(_T("/var"), _("Variables") )
234 ADD_SECTION(_T("/etc"), _("Etcetera") )
235 ADD_SECTION(_T("/tmp"), _("Temporary") )
d7a15103
JS
236}
237#undef ADD_SECTION
238
239void wxDirCtrl::CreateItems(const wxTreeItemId &parent)
240{
241 wxTreeItemId id;
242 wxDirItemData *dir_item;
243
244// wxASSERT(m_paths.Count() == m_names.Count()); ?
245
246 for (unsigned int i=0; i<m_paths.Count(); i++)
247 {
248 dir_item = new wxDirItemData(m_paths[i],m_names[i]);
0659e7ee 249 id = AppendItem( parent, m_names[i], 0, 1, dir_item);
d7a15103
JS
250 if (dir_item->m_hasSubDirs) SetItemHasChildren(id);
251 }
252}
253
1e6d9499 254void wxDirCtrl::OnExpandItem(wxTreeEvent &event )
d7a15103
JS
255{
256 if (event.GetItem() == m_rootId)
257 {
258 SetupSections();
259 CreateItems(m_rootId);
260 return;
261 };
262
263 // This may take a longish time. Go to busy cursor
264 wxBeginBusyCursor();
265
266 wxDirItemData *data = (wxDirItemData *)GetItemData(event.GetItem());
267 wxASSERT(data);
268
269 wxString search,path,filename;
270
271 m_paths.Clear();
272 m_names.Clear();
273 search = *(data->m_path) + "/*";
274 for (path = wxFindFirstFile( search, wxDIR ); !path.IsNull();
275 path=wxFindNextFile() ) {
276 filename = wxFileNameFromPath( path );
277 /* Don't add "." and ".." to the tree. I think wxFindNextFile
278 * also checks this, but I don't quite understand what happens
279 * there. Also wxFindNextFile seems to swallow hidden dirs */
280 if ((filename != ".") && (filename != "..")) {
281 m_paths.Add(path);
282 m_names.Add(filename);
283 }
284 }
285 CreateItems(event.GetItem());
286 wxEndBusyCursor();
63852e78
RR
287
288 SortChildren( event.GetItem() );
d7a15103
JS
289};
290
291
1e6d9499 292void wxDirCtrl::OnCollapseItem(wxTreeEvent &event )
d7a15103
JS
293{
294 wxTreeItemId child, parent = event.GetItem();
295 long cookie;
296 /* Workaround because DeleteChildren has disapeared (why?) and
297 * CollapseAndReset doesn't work as advertised (deletes parent too) */
298 child = GetFirstChild(parent, cookie);
299 while (child.IsOk()) {
300 Delete(child);
301 /* Not GetNextChild below, because the cookie mechanism can't
302 * handle disappearing children! */
303 child = GetFirstChild(parent, cookie);
304 }
305};
306
307//-----------------------------------------------------------------------------
308// wxDirDialog
309//-----------------------------------------------------------------------------
310
311
312#if !USE_SHARED_LIBRARY
313IMPLEMENT_CLASS(wxDirDialog, wxDialog)
314#else
315IMPLEMENT_DYNAMIC_CLASS( wxDirDialog, wxDialog )
316#endif
317
318BEGIN_EVENT_TABLE( wxDirDialog, wxDialog )
319 EVT_TREE_KEY_DOWN (ID_DIRCTRL, wxDirDialog::OnTreeKeyDown)
320 EVT_TREE_SEL_CHANGED (ID_DIRCTRL, wxDirDialog::OnTreeSelected)
321 EVT_SIZE ( wxDirDialog::OnSize)
322 EVT_BUTTON (ID_OK, wxDirDialog::OnOK)
323 EVT_BUTTON (ID_CANCEL, wxDirDialog::OnCancel)
324 EVT_BUTTON (ID_NEW, wxDirDialog::OnNew)
325 EVT_TEXT_ENTER (ID_TEXTCTRL, wxDirDialog::OnOK)
326 // EVT_CHECKBOX (ID_CHECK, wxDirDialog::OnCheck)
327END_EVENT_TABLE()
328
329wxDirDialog::wxDirDialog(wxWindow *parent, const wxString& message,
330 const wxString& defaultPath, long style,
331 const wxPoint& pos) :
332 wxDialog(parent, -1, message, pos, wxSize(300,300),
333 wxDEFAULT_DIALOG_STYLE|wxDIALOG_MODAL)
334{
335 m_message = message;
336 m_dialogStyle = style;
337 m_parent = parent;
338
339 m_path = defaultPath;
340
341 m_dir = new wxDirCtrl( this, ID_DIRCTRL, "/", wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS | wxSUNKEN_BORDER );
342 m_input = new wxTextCtrl( this, ID_TEXTCTRL, m_path, wxDefaultPosition );
343 // m_check = new wxCheckBox( this, ID_CHECK, _("Show hidden") );
344 m_ok = new wxButton( this, ID_OK, _("OK") );
3502e687 345 m_cancel = new wxButton( this, ID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize(75,-1) );
d7a15103
JS
346 m_new = new wxButton( this, ID_NEW, _("New...") );
347
348 // m_check->SetValue(TRUE);
349 m_ok->SetDefault();
350 m_dir->SetFocus();
351
352 doSize();
353}
354
355void wxDirDialog::OnSize(wxSizeEvent& WXUNUSED(event))
356{
357 doSize();
358}
359
360void wxDirDialog::doSize()
361{
362 /* Figure out height of DirCtrl, which is what is left over by
363 * the textctrl and the buttons. Manually, because I can't seem
364 * to get the constraints stuff to do this */
365 int w,h,h2;
366
367 GetClientSize(&w, &h);
368 m_input->GetSize(&w,&h2); h -= h2;
369 m_ok->GetSize(&w, &h2); h -= h2;
370 //m_check->GetSize(&w, &h2); h -= h2;
3502e687 371 h -= 30;
d7a15103
JS
372
373 wxLayoutConstraints *c = new wxLayoutConstraints;
374 c->left.SameAs (this, wxLeft,5);
375 c->right.SameAs (this, wxRight,5);
376 c->height.Absolute (h);
377 c->top.SameAs (this, wxTop,5);
378 m_dir->SetConstraints(c);
379
380 c = new wxLayoutConstraints;
381 c->left.SameAs (this, wxLeft,5);
382 c->right.SameAs (this, wxRight,5);
383 c->height.AsIs ();
384 c->top.Below (m_dir,5);
385 m_input->SetConstraints(c);
386
387 /* c = new wxLayoutConstraints;
388 c->left.SameAs (this, wxLeft,5);
389 c->right.SameAs (this, wxRight,5);
390 c->height.AsIs ();
391 c->top.Below (m_input,5);
392 m_check->SetConstraints(c); */
393
394 c = new wxLayoutConstraints;
395 c->width.SameAs (m_cancel, wxWidth);
396 c->height.AsIs ();
3502e687
RR
397 c->top.Below (m_input,10);
398 c->centreX.PercentOf (this, wxWidth, 20);
d7a15103
JS
399 m_ok->SetConstraints(c);
400
401 c = new wxLayoutConstraints;
402 c->width.SameAs (m_cancel, wxWidth);
403 c->height.AsIs ();
3502e687 404 c->top.Below (m_input,10);
d7a15103
JS
405 c->bottom.SameAs (this, wxBottom, 5);
406 c->centreX.PercentOf (this, wxWidth, 50);
407 m_new->SetConstraints(c);
408
409 c = new wxLayoutConstraints;
410 c->width.AsIs ();
411 c->height.AsIs ();
3502e687
RR
412 c->top.Below (m_input,10);
413 c->centreX.PercentOf (this, wxWidth, 80);
d7a15103
JS
414 m_cancel->SetConstraints(c);
415
416 Layout();
417}
418
419int wxDirDialog::ShowModal()
420{
421 m_input->SetValue( m_path );
422 return wxDialog::ShowModal();
423}
424
425void wxDirDialog::OnTreeSelected( wxTreeEvent &event )
426{
427 wxDirItemData *data =
428 (wxDirItemData*)m_dir->GetItemData(event.GetItem());
429 if (data)
430 m_input->SetValue( *(data->m_path) );
431};
432
1e6d9499 433void wxDirDialog::OnTreeKeyDown( wxTreeEvent &WXUNUSED(event) )
d7a15103
JS
434{
435 wxDirItemData *data =
436 (wxDirItemData*)m_dir->GetItemData(m_dir->GetSelection());
437 if (data)
438 m_input->SetValue( *(data->m_path) );
439};
440
441void wxDirDialog::OnOK( wxCommandEvent& WXUNUSED(event) )
442{
443 m_path = m_input->GetValue();
444 // Does the path exist? (User may have typed anything in m_input)
445 if (wxPathExists(m_path)) {
446 // OK, path exists, we're done.
447 EndModal(wxID_OK);
448 return;
449 }
450 // Interact with user, find out if the dir is a typo or to be created
451 wxString msg( _("The directory ") );
452 msg = msg + m_path;
453 msg = msg + _("\ndoes not exist\nCreate it now?") ;
454 wxMessageDialog dialog(this, msg, _("Directory does not exist"), wxYES_NO);
455 if ( dialog.ShowModal() == wxID_YES ) {
456 // Okay, let's make it
457 if (wxMkdir(m_path)) {
458 // The new dir was created okay.
459 EndModal(wxID_OK);
460 return;
461 }
462 else {
463 // Trouble...
464 msg = _("Failed to create directory ")+m_path+
465 _("\n(Do you have the required permissions?)");
466 wxMessageDialog errmsg(this, msg, _("Error creating directory"), wxOK);
467 errmsg.ShowModal();
468 // We still don't have a valid dir. Back to the main dialog.
469 }
470 }
471 // User has answered NO to create dir.
472}
473
474void wxDirDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
475{
476 EndModal(wxID_CANCEL);
477}
478
479void wxDirDialog::OnNew( wxCommandEvent& WXUNUSED(event) )
480{
481 wxTextEntryDialog dialog(this, _("Enter the name of the directory to create"),
482 _("Create New Directory"), m_input->GetValue(), wxOK|wxCANCEL);
483
484 while (dialog.ShowModal() == wxID_OK)
485 {
486 // Okay, let's make it
487 if (wxMkdir(dialog.GetValue())) {
488 // The new dir was created okay.
489 m_path = dialog.GetValue();
490 return;
491 }
492 wxString msg = _("Failed to create directory ")+dialog.GetValue()+
493 _("\n(Do you have the required permissions?)") ;
494 wxMessageDialog errmsg(this, msg, _("Error creating directory"), wxOK);
495 errmsg.ShowModal();
496 // Show the create dialog again, until user clicks cancel or enters
497 // a valid dir.
498 }
499}
500
501/*
502void wxDirDialog::OnCheck( wxCommandEvent& WXUNUSED(event) )
503{
504 printf("Checkbox clicked: %s\n", ( m_check->GetValue() ? "on" : "off" ) );
505}
506*/
ce4169a4
RR
507
508#endif