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