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