Added and corrected a few more html makefiles,
[wxWidgets.git] / src / generic / dirdlgg.cpp
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 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 #include "wx/defs.h"
23
24 #if wxUSE_DIRDLG
25
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"
37 #include "wx/icon.h"
38 #include "wx/log.h"
39 #include "wx/sizer.h"
40
41 #if wxUSE_STATLINE
42 #include "wx/statline.h"
43 #endif
44
45 #include "wx/generic/dirdlgg.h"
46
47 // If compiled under Windows, this macro can cause problems
48 #ifdef GetFirstChild
49 #undef GetFirstChild
50 #endif
51
52 /* XPM */
53 static char * icon1_xpm[] = {
54 /* width height ncolors chars_per_pixel */
55 "16 16 6 1",
56 /* colors */
57 " s None c None",
58 ". c #000000",
59 "+ c #c0c0c0",
60 "@ c #808080",
61 "# c #ffff00",
62 "$ c #ffffff",
63 /* pixels */
64 " ",
65 " @@@@@ ",
66 " @#+#+#@ ",
67 " @#+#+#+#@@@@@@ ",
68 " @$$$$$$$$$$$$@.",
69 " @$#+#+#+#+#+#@.",
70 " @$+#+#+#+#+#+@.",
71 " @$#+#+#+#+#+#@.",
72 " @$+#+#+#+#+#+@.",
73 " @$#+#+#+#+#+#@.",
74 " @$+#+#+#+#+#+@.",
75 " @$#+#+#+#+#+#@.",
76 " @@@@@@@@@@@@@@.",
77 " ..............",
78 " ",
79 " "};
80
81 /* XPM */
82 static char * icon2_xpm[] = {
83 /* width height ncolors chars_per_pixel */
84 "16 16 6 1",
85 /* colors */
86 " s None c None",
87 ". c #000000",
88 "+ c #c0c0c0",
89 "@ c #808080",
90 "# c #ffff00",
91 "$ c #ffffff",
92 /* pixels */
93 " ",
94 " @@@@@ ",
95 " @$$$$$@ ",
96 " @$#+#+#$@@@@@@ ",
97 " @$+#+#+$$$$$$@.",
98 " @$#+#+#+#+#+#@.",
99 "@@@@@@@@@@@@@#@.",
100 "@$$$$$$$$$$@@+@.",
101 "@$#+#+#+#+##.@@.",
102 " @$#+#+#+#+#+.@.",
103 " @$+#+#+#+#+#.@.",
104 " @$+#+#+#+##@..",
105 " @@@@@@@@@@@@@.",
106 " .............",
107 " ",
108 " "};
109
110 static const int ID_DIRCTRL = 1000;
111 static const int ID_TEXTCTRL = 1001;
112 static const int ID_OK = 1002;
113 static const int ID_CANCEL = 1003;
114 static const int ID_NEW = 1004;
115 //static const int ID_CHECK = 1005;
116
117 //-----------------------------------------------------------------------------
118 // wxDirItemData
119 //-----------------------------------------------------------------------------
120
121 wxDirItemData::wxDirItemData(wxString& path, wxString& name)
122 {
123 m_path = path;
124 m_name = name;
125 /* Insert logic to detect hidden files here
126 * In UnixLand we just check whether the first char is a dot
127 * For FileNameFromPath read LastDirNameInThisPath ;-) */
128 // m_isHidden = (bool)(wxFileNameFromPath(*m_path)[0] == '.');
129 m_isHidden = FALSE;
130 m_hasSubDirs = HasSubDirs();
131 }
132
133 wxDirItemData::~wxDirItemData()
134 {
135 }
136
137 void wxDirItemData::SetNewDirName( wxString path )
138 {
139 m_path = path;
140 m_name = wxFileNameFromPath( path );
141 }
142
143 bool wxDirItemData::HasSubDirs()
144 {
145 wxString search = m_path + "/*";
146 wxLogNull log;
147 wxString path = wxFindFirstFile( search, wxDIR );
148 return (bool)(!path.IsNull());
149 }
150
151 //-----------------------------------------------------------------------------
152 // wxDirCtrl
153 //-----------------------------------------------------------------------------
154
155 IMPLEMENT_DYNAMIC_CLASS(wxDirCtrl,wxTreeCtrl)
156
157 BEGIN_EVENT_TABLE(wxDirCtrl,wxTreeCtrl)
158 EVT_TREE_ITEM_EXPANDING (-1, wxDirCtrl::OnExpandItem)
159 EVT_TREE_ITEM_COLLAPSED (-1, wxDirCtrl::OnCollapseItem)
160 EVT_TREE_BEGIN_LABEL_EDIT (-1, wxDirCtrl::OnBeginEditItem)
161 EVT_TREE_END_LABEL_EDIT (-1, wxDirCtrl::OnEndEditItem)
162 END_EVENT_TABLE()
163
164 wxDirCtrl::wxDirCtrl(void)
165 {
166 m_showHidden = FALSE;
167 }
168
169 wxDirCtrl::wxDirCtrl(wxWindow *parent, const wxWindowID id, const wxString &WXUNUSED(dir),
170 const wxPoint& pos, const wxSize& size,
171 const long style, const wxString& name )
172 :
173 wxTreeCtrl( parent, id, pos, size, style, wxDefaultValidator, name )
174 {
175 m_imageListNormal = new wxImageList(16, 16, TRUE);
176 m_imageListNormal->Add(wxICON(icon1));
177 m_imageListNormal->Add(wxICON(icon2));
178 SetImageList(m_imageListNormal);
179
180 m_showHidden = FALSE;
181 m_rootId = AddRoot( _("Sections") );
182 SetItemHasChildren(m_rootId);
183 Expand(m_rootId); // automatically expand first level
184 }
185
186 /* Quick macro. Don't worry, I'll #undef it later */
187 #define ADD_SECTION(a,b) \
188 if (wxPathExists((a))) { m_paths.Add( (a) ); m_names.Add( (b) ); };
189
190 void wxDirCtrl::SetupSections()
191 {
192 wxString home;
193
194 m_paths.Clear();
195 m_names.Clear();
196 ADD_SECTION(_T("/"), _("The Computer") )
197 wxGetHomeDir(&home);
198 ADD_SECTION(home, _("My Home") )
199 ADD_SECTION(_T("/mnt"), _("Mounted Devices") )
200 ADD_SECTION(_T("/usr"), _("User") )
201 ADD_SECTION(_T("/usr/local"), _("User Local") )
202 ADD_SECTION(_T("/var"), _("Variables") )
203 ADD_SECTION(_T("/etc"), _("Etcetera") )
204 ADD_SECTION(_T("/tmp"), _("Temporary") )
205 }
206 #undef ADD_SECTION
207
208 void wxDirCtrl::CreateItems(const wxTreeItemId &parent)
209 {
210 wxTreeItemId id;
211 wxDirItemData *dir_item;
212
213 // wxASSERT(m_paths.Count() == m_names.Count()); ?
214
215 for (unsigned int i=0; i<m_paths.Count(); i++)
216 {
217 dir_item = new wxDirItemData(m_paths[i],m_names[i]);
218 id = AppendItem( parent, m_names[i], 0, 1, dir_item);
219 if (dir_item->m_hasSubDirs) SetItemHasChildren(id);
220 }
221 }
222
223 void wxDirCtrl::OnBeginEditItem(wxTreeEvent &event)
224 {
225 // don't rename the main entry "Sections"
226 if (event.GetItem() == m_rootId)
227 {
228 event.Veto();
229 return;
230 }
231
232 // don't rename the individual sections
233 if (GetParent( event.GetItem() ) == m_rootId)
234 {
235 event.Veto();
236 return;
237 }
238 }
239
240 void wxDirCtrl::OnEndEditItem(wxTreeEvent &event)
241 {
242 if ((event.GetLabel().IsEmpty()) ||
243 (event.GetLabel() == _(".")) ||
244 (event.GetLabel() == _("..")) ||
245 (event.GetLabel().First( _T("/") ) != wxNOT_FOUND))
246 {
247 wxMessageDialog dialog(this, _("Illegal directory name."), _("Error"), wxOK | wxICON_ERROR );
248 dialog.ShowModal();
249 event.Veto();
250 return;
251 }
252
253 wxTreeItemId id = event.GetItem();
254 wxDirItemData *data = (wxDirItemData*)GetItemData( id );
255 wxASSERT( data );
256
257 wxString new_name( wxPathOnly( data->m_path ) );
258 new_name += _T("/");
259 new_name += event.GetLabel();
260
261 wxLogNull log;
262
263 if (wxFileExists(new_name))
264 {
265 wxMessageDialog dialog(this, _("File name exists already."), _("Error"), wxOK | wxICON_ERROR );
266 dialog.ShowModal();
267 event.Veto();
268 }
269
270 if (wxRenameFile(data->m_path,new_name))
271 {
272 data->SetNewDirName( new_name );
273 }
274 else
275 {
276 wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
277 dialog.ShowModal();
278 event.Veto();
279 }
280 }
281
282 void wxDirCtrl::OnExpandItem(wxTreeEvent &event)
283 {
284 if (event.GetItem() == m_rootId)
285 {
286 SetupSections();
287 CreateItems(m_rootId);
288 return;
289 }
290
291 // This may take a longish time. Go to busy cursor
292 wxBeginBusyCursor();
293
294 wxDirItemData *data = (wxDirItemData *)GetItemData(event.GetItem());
295 wxASSERT(data);
296
297 wxString search,path,filename;
298
299 m_paths.Clear();
300 m_names.Clear();
301 search = data->m_path + "/*";
302 for (path = wxFindFirstFile( search, wxDIR ); !path.IsNull();
303 path=wxFindNextFile() )
304 {
305 filename = wxFileNameFromPath( path );
306 /* Don't add "." and ".." to the tree. I think wxFindNextFile
307 * also checks this, but I don't quite understand what happens
308 * there. Also wxFindNextFile seems to swallow hidden dirs */
309 if ((filename != ".") && (filename != ".."))
310 {
311 m_paths.Add(path);
312 m_names.Add(filename);
313 }
314 }
315
316 CreateItems( event.GetItem() );
317 SortChildren( event.GetItem() );
318
319 wxEndBusyCursor();
320 }
321
322 void wxDirCtrl::OnCollapseItem(wxTreeEvent &event )
323 {
324 wxTreeItemId child, parent = event.GetItem();
325 long cookie;
326 /* Workaround because DeleteChildren has disapeared (why?) and
327 * CollapseAndReset doesn't work as advertised (deletes parent too) */
328 child = GetFirstChild(parent, cookie);
329 while (child.IsOk())
330 {
331 Delete(child);
332 /* Not GetNextChild below, because the cookie mechanism can't
333 * handle disappearing children! */
334 child = GetFirstChild(parent, cookie);
335 }
336 }
337
338 //-----------------------------------------------------------------------------
339 // wxDirDialog
340 //-----------------------------------------------------------------------------
341
342
343 #if !USE_SHARED_LIBRARY
344 IMPLEMENT_CLASS(wxDirDialog, wxDialog)
345 #else
346 IMPLEMENT_DYNAMIC_CLASS( wxDirDialog, wxDialog )
347 #endif
348
349 BEGIN_EVENT_TABLE( wxDirDialog, wxDialog )
350 EVT_TREE_KEY_DOWN (ID_DIRCTRL, wxDirDialog::OnTreeKeyDown)
351 EVT_TREE_SEL_CHANGED (ID_DIRCTRL, wxDirDialog::OnTreeSelected)
352 EVT_SIZE ( wxDirDialog::OnSize)
353 EVT_BUTTON (ID_OK, wxDirDialog::OnOK)
354 EVT_BUTTON (ID_CANCEL, wxDirDialog::OnCancel)
355 EVT_BUTTON (ID_NEW, wxDirDialog::OnNew)
356 EVT_TEXT_ENTER (ID_TEXTCTRL, wxDirDialog::OnOK)
357 // EVT_CHECKBOX (ID_CHECK, wxDirDialog::OnCheck)
358 END_EVENT_TABLE()
359
360 wxDirDialog::wxDirDialog(wxWindow *parent, const wxString& message,
361 const wxString& defaultPath, long style,
362 const wxPoint& pos) :
363 wxDialog(parent, -1, message, pos, wxSize(300,300),
364 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
365 {
366 m_message = message;
367 m_dialogStyle = style;
368 m_parent = parent;
369
370 m_path = defaultPath;
371
372 wxBeginBusyCursor();
373
374 wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
375
376 // 1) dir ctrl
377 m_dir = new wxDirCtrl( this, ID_DIRCTRL, "/", wxDefaultPosition, wxSize(200,200),
378 wxTR_HAS_BUTTONS | wxSUNKEN_BORDER | wxTR_EDIT_LABELS);
379 topsizer->Add( m_dir, 1, wxTOP|wxLEFT|wxRIGHT | wxEXPAND, 10 );
380
381 // 2) text ctrl
382 m_input = new wxTextCtrl( this, ID_TEXTCTRL, m_path, wxDefaultPosition );
383 topsizer->Add( m_input, 0, wxTOP|wxLEFT|wxRIGHT | wxEXPAND, 10 );
384
385 // m_check = new wxCheckBox( this, ID_CHECK, _("Show hidden") );
386 // m_check->SetValue(TRUE);
387
388 #if wxUSE_STATLINE
389 // 3) static line
390 topsizer->Add( new wxStaticLine( this, -1 ), 0, wxEXPAND | wxLEFT|wxRIGHT|wxTOP, 10 );
391 #endif
392
393 // 4) buttons
394 wxSizer* buttonsizer = new wxBoxSizer( wxHORIZONTAL );
395 m_ok = new wxButton( this, ID_OK, _("OK") );
396 buttonsizer->Add( m_ok, 0, wxLEFT|wxRIGHT, 10 );
397 m_cancel = new wxButton( this, ID_CANCEL, _("Cancel") );
398 buttonsizer->Add( m_cancel, 0, wxLEFT|wxRIGHT, 10 );
399 m_new = new wxButton( this, ID_NEW, _("New...") );
400 buttonsizer->Add( m_new, 0, wxLEFT|wxRIGHT, 10 );
401
402 topsizer->Add( buttonsizer, 0, wxALL | wxCENTER, 10 );
403
404 m_ok->SetDefault();
405 m_dir->SetFocus();
406
407 SetAutoLayout( TRUE );
408 SetSizer( topsizer );
409
410 topsizer->SetSizeHints( this );
411 topsizer->Fit( this );
412
413 Centre( wxBOTH );
414
415 wxEndBusyCursor();
416 }
417
418 int wxDirDialog::ShowModal()
419 {
420 m_input->SetValue( m_path );
421 return wxDialog::ShowModal();
422 }
423
424 void wxDirDialog::OnTreeSelected( wxTreeEvent &event )
425 {
426 wxDirItemData *data = (wxDirItemData*)m_dir->GetItemData(event.GetItem());
427 if (data)
428 m_input->SetValue( data->m_path );
429 };
430
431 void wxDirDialog::OnTreeKeyDown( wxTreeEvent &WXUNUSED(event) )
432 {
433 wxDirItemData *data = (wxDirItemData*)m_dir->GetItemData(m_dir->GetSelection());
434 if (data)
435 m_input->SetValue( data->m_path );
436 };
437
438 void wxDirDialog::OnOK( wxCommandEvent& WXUNUSED(event) )
439 {
440 m_path = m_input->GetValue();
441 // Does the path exist? (User may have typed anything in m_input)
442 if (wxPathExists(m_path)) {
443 // OK, path exists, we're done.
444 EndModal(wxID_OK);
445 return;
446 }
447 // Interact with user, find out if the dir is a typo or to be created
448 wxString msg( _("The directory ") );
449 msg = msg + m_path;
450 msg = msg + _("\ndoes not exist\nCreate it now?") ;
451 wxMessageDialog dialog(this, msg, _("Directory does not exist"), wxYES_NO | wxICON_WARNING );
452 if ( dialog.ShowModal() == wxID_YES ) {
453 // Okay, let's make it
454 wxLogNull log;
455 if (wxMkdir(m_path)) {
456 // The new dir was created okay.
457 EndModal(wxID_OK);
458 return;
459 }
460 else {
461 // Trouble...
462 msg = _("Failed to create directory ")+m_path+
463 _("\n(Do you have the required permissions?)");
464 wxMessageDialog errmsg(this, msg, _("Error creating directory"), wxOK | wxICON_ERROR);
465 errmsg.ShowModal();
466 // We still don't have a valid dir. Back to the main dialog.
467 }
468 }
469 // User has answered NO to create dir.
470 }
471
472 void wxDirDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
473 {
474 EndModal(wxID_CANCEL);
475 }
476
477 void wxDirDialog::OnNew( wxCommandEvent& WXUNUSED(event) )
478 {
479 wxTreeItemId id = m_dir->GetSelection();
480 if ((id == m_dir->GetRootItem()) ||
481 (m_dir->GetParent(id) == m_dir->GetRootItem()))
482 {
483 wxMessageDialog msg(this, _("You cannot add a new directory to this section."),
484 _("Create directory"), wxOK | wxICON_INFORMATION );
485 msg.ShowModal();
486 return;
487 }
488
489 wxTreeItemId parent = m_dir->GetParent( id );
490 wxDirItemData *data = (wxDirItemData*)m_dir->GetItemData( parent );
491 wxASSERT( data );
492
493 wxString new_name( _T("NewName") );
494 wxString path( data->m_path );
495 path += _T( "/" );
496 path += new_name;
497 if (wxFileExists(path))
498 {
499 // try NewName0, NewName1 etc.
500 int i = 0;
501 do {
502 new_name = _T("NewName");
503 wxString num;
504 num.Printf( "%d", i );
505 new_name += num;
506
507 path = data->m_path;
508 path += _T( "/" );
509 path += new_name;
510 i++;
511 } while (wxFileExists(path));
512 }
513
514 wxLogNull log;
515 if (!wxMkdir(path))
516 {
517 wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
518 dialog.ShowModal();
519 return;
520 }
521
522 wxDirItemData *new_data = new wxDirItemData( path, new_name );
523 wxTreeItemId new_id = m_dir->AppendItem( parent, new_name, 0, 1, new_data );
524 m_dir->EnsureVisible( new_id );
525 m_dir->EditLabel( new_id );
526 }
527
528 /*
529 void wxDirDialog::OnCheck( wxCommandEvent& WXUNUSED(event) )
530 {
531 printf("Checkbox clicked: %s\n", ( m_check->GetValue() ? "on" : "off" ) );
532 }
533 */
534
535 #endif