]> git.saurik.com Git - wxWidgets.git/blame - src/generic/dirdlgg.cpp
wxClipboard now serves the primary selection as well
[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
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 */
31static 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 */
60static 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
88static const int ID_DIRCTRL = 1000;
89static const int ID_TEXTCTRL = 1001;
90static const int ID_OK = 1002;
91static const int ID_CANCEL = 1003;
92static const int ID_NEW = 1004;
93//static const int ID_CHECK = 1005;
94
95//-----------------------------------------------------------------------------
96// wxDirItemData
97//-----------------------------------------------------------------------------
98
0659e7ee
RR
99class wxDirItemData : public wxTreeItemData
100{
101public:
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
114class 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
143wxDirItemData::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
155wxDirItemData:: ~wxDirItemData()
156{
157 delete m_path;
158 delete m_name;
159}
160
161bool 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
172IMPLEMENT_DYNAMIC_CLASS(wxDirCtrl,wxTreeCtrl)
173
174BEGIN_EVENT_TABLE(wxDirCtrl,wxTreeCtrl)
175 EVT_TREE_ITEM_EXPANDING (-1, wxDirCtrl::OnExpandItem)
176 EVT_TREE_ITEM_COLLAPSED (-1, wxDirCtrl::OnCollapseItem)
177END_EVENT_TABLE()
178
179wxDirCtrl::wxDirCtrl(void)
180{
181 m_showHidden = FALSE;
182};
183
184wxDirCtrl::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
205void 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
223void 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
238void 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
274void 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
295IMPLEMENT_CLASS(wxDirDialog, wxDialog)
296#else
297IMPLEMENT_DYNAMIC_CLASS( wxDirDialog, wxDialog )
298#endif
299
300BEGIN_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)
309END_EVENT_TABLE()
310
311wxDirDialog::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
337void wxDirDialog::OnSize(wxSizeEvent& WXUNUSED(event))
338{
339 doSize();
340}
341
342void 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
401int wxDirDialog::ShowModal()
402{
403 m_input->SetValue( m_path );
404 return wxDialog::ShowModal();
405}
406
407void 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
415void 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
423void 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
456void wxDirDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
457{
458 EndModal(wxID_CANCEL);
459}
460
461void 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/*
484void wxDirDialog::OnCheck( wxCommandEvent& WXUNUSED(event) )
485{
486 printf("Checkbox clicked: %s\n", ( m_check->GetValue() ? "on" : "off" ) );
487}
488*/