File/dir dialog styles and other changes (patch 1488371):
[wxWidgets.git] / src / generic / dirdlgg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/dirdlg.cpp
3 // Purpose: wxDirDialog
4 // Author: Harm van der Heijden, Robert Roebling & Julian Smart
5 // Modified by:
6 // Created: 12/12/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Harm van der Heijden, Robert Roebling, Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_DIRDLG
20
21 #ifndef WX_PRECOMP
22 #include "wx/textctrl.h"
23 #include "wx/button.h"
24 #include "wx/checkbox.h"
25 #include "wx/sizer.h"
26 #include "wx/intl.h"
27 #include "wx/log.h"
28 #include "wx/msgdlg.h"
29 #include "wx/bmpbuttn.h"
30 #endif
31
32 #include "wx/statline.h"
33 #include "wx/dirctrl.h"
34 #include "wx/generic/dirdlgg.h"
35 #include "wx/artprov.h"
36
37 // ----------------------------------------------------------------------------
38 // constants
39 // ----------------------------------------------------------------------------
40
41 static const int ID_DIRCTRL = 1000;
42 static const int ID_TEXTCTRL = 1001;
43 static const int ID_NEW = 1004;
44 static const int ID_SHOW_HIDDEN = 1005;
45 static const int ID_GO_HOME = 1006;
46
47 // ---------------------------------------------------------------------------
48 // macros
49 // ---------------------------------------------------------------------------
50
51 /* Macro for avoiding #ifdefs when value have to be different depending on size of
52 device we display on - take it from something like wxDesktopPolicy in the future
53 */
54
55 #if defined(__SMARTPHONE__)
56 #define wxLARGESMALL(large,small) small
57 #else
58 #define wxLARGESMALL(large,small) large
59 #endif
60
61 //-----------------------------------------------------------------------------
62 // wxGenericDirDialog
63 //-----------------------------------------------------------------------------
64
65 IMPLEMENT_DYNAMIC_CLASS(wxGenericDirDialog, wxDialog)
66
67 BEGIN_EVENT_TABLE(wxGenericDirDialog, wxDialog)
68 EVT_CLOSE (wxGenericDirDialog::OnCloseWindow)
69 EVT_BUTTON (wxID_OK, wxGenericDirDialog::OnOK)
70 EVT_BUTTON (ID_NEW, wxGenericDirDialog::OnNew)
71 EVT_BUTTON (ID_GO_HOME, wxGenericDirDialog::OnGoHome)
72 EVT_TREE_KEY_DOWN (wxID_ANY, wxGenericDirDialog::OnTreeKeyDown)
73 EVT_TREE_SEL_CHANGED (wxID_ANY, wxGenericDirDialog::OnTreeSelected)
74 EVT_TEXT_ENTER (ID_TEXTCTRL, wxGenericDirDialog::OnOK)
75 EVT_CHECKBOX (ID_SHOW_HIDDEN, wxGenericDirDialog::OnShowHidden)
76 END_EVENT_TABLE()
77
78 wxGenericDirDialog::wxGenericDirDialog(wxWindow* parent, const wxString& title,
79 const wxString& defaultPath, long style,
80 const wxPoint& pos, const wxSize& sz,
81 const wxString& name)
82 {
83 Create(parent, title, defaultPath, style, pos, sz, name);
84 }
85
86 bool wxGenericDirDialog::Create(wxWindow* parent,
87 const wxString& title,
88 const wxString& defaultPath, long style,
89 const wxPoint& pos,
90 const wxSize& sz,
91 const wxString& name)
92 {
93 wxBusyCursor cursor;
94
95 if (!wxDirDialogBase::Create(parent, title, defaultPath, style, pos, sz, name))
96 return false;
97
98 m_path = defaultPath;
99 if (m_path == wxT("~"))
100 wxGetHomeDir(&m_path);
101 if (m_path == wxT("."))
102 m_path = wxGetCwd();
103
104 wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL );
105
106 // smartphones does not support or do not waste space for wxButtons
107 #if defined(__SMARTPHONE__)
108
109 wxMenu *dirMenu = new wxMenu;
110 dirMenu->Append(ID_GO_HOME, _("Home"));
111
112 if (!HasFlag(wxDD_DIR_MUST_EXIST))
113 {
114 dirMenu->Append(ID_NEW, _("New directory"));
115 }
116
117 dirMenu->AppendCheckItem(ID_SHOW_HIDDEN, _("Show hidden directories"));
118 dirMenu->AppendSeparator();
119 dirMenu->Append(wxID_CANCEL, _("Cancel"));
120
121 #else
122
123 // 0) 'New' and 'Home' Buttons
124 wxSizer* buttonsizer = new wxBoxSizer( wxHORIZONTAL );
125
126 // VS: 'Home directory' concept is unknown to MS-DOS
127 #if !defined(__DOS__)
128 wxBitmapButton* homeButton =
129 new wxBitmapButton(this, ID_GO_HOME,
130 wxArtProvider::GetBitmap(wxART_GO_HOME, wxART_BUTTON));
131 buttonsizer->Add( homeButton, 0, wxLEFT|wxRIGHT, 10 );
132 #endif
133
134 // I'm not convinced we need a New button, and we tend to get annoying
135 // accidental-editing with label editing enabled.
136 if (!HasFlag(wxDD_DIR_MUST_EXIST))
137 {
138 wxBitmapButton* newButton =
139 new wxBitmapButton(this, ID_NEW,
140 wxArtProvider::GetBitmap(wxART_NEW_DIR, wxART_BUTTON));
141 buttonsizer->Add( newButton, 0, wxRIGHT, 10 );
142 #if wxUSE_TOOLTIPS
143 newButton->SetToolTip(_("Create new directory"));
144 #endif
145 }
146
147 #if wxUSE_TOOLTIPS
148 homeButton->SetToolTip(_("Go to home directory"));
149 #endif
150
151 topsizer->Add( buttonsizer, 0, wxTOP | wxALIGN_RIGHT, 10 );
152
153 #endif // __SMARTPHONE__/!__SMARTPHONE__
154
155 // 1) dir ctrl
156 m_dirCtrl = NULL; // this is necessary, event handler called from
157 // wxGenericDirCtrl would crash otherwise!
158 long dirStyle = wxDIRCTRL_DIR_ONLY | wxDEFAULT_CONTROL_BORDER;
159
160 #ifdef __WXMSW__
161 if (!HasFlag(wxDD_DIR_MUST_EXIST))
162 {
163 // Only under Windows do we need the wxTR_EDIT_LABEL tree control style
164 // before we can call EditLabel (required for "New directory")
165 dirStyle |= wxDIRCTRL_EDIT_LABELS;
166 }
167 #endif
168
169 m_dirCtrl = new wxGenericDirCtrl(this, ID_DIRCTRL,
170 m_path, wxDefaultPosition,
171 wxSize(300, 200),
172 dirStyle);
173
174 topsizer->Add( m_dirCtrl, 1, wxTOP|wxLEFT|wxRIGHT | wxEXPAND, wxLARGESMALL(10,0) );
175
176 #ifndef __SMARTPHONE__
177 // Make the an option depending on a flag?
178 wxCheckBox* check = new wxCheckBox( this, ID_SHOW_HIDDEN, _("Show hidden directories") );
179 topsizer->Add( check, 0, wxLEFT|wxRIGHT|wxTOP | wxALIGN_RIGHT, 10 );
180 #endif // !__SMARTPHONE__
181
182 // 2) text ctrl
183 m_input = new wxTextCtrl( this, ID_TEXTCTRL, m_path, wxDefaultPosition );
184 topsizer->Add( m_input, 0, wxTOP|wxLEFT|wxRIGHT | wxEXPAND, wxLARGESMALL(10,0) );
185
186 // 3) buttons if any
187 wxSizer *buttonSizer = CreateButtonSizer( wxOK|wxCANCEL , true, wxLARGESMALL(10,0) );
188 if(buttonSizer->GetChildren().GetCount() > 0 )
189 {
190 topsizer->Add( buttonSizer, 0, wxEXPAND | wxALL, wxLARGESMALL(10,0) );
191 }
192 else
193 {
194 topsizer->AddSpacer( wxLARGESMALL(10,0) );
195 delete buttonSizer;
196 }
197
198 #ifdef __SMARTPHONE__
199 // overwrite menu achieved with earlier CreateButtonSizer() call
200 SetRightMenu(wxID_ANY, _("Options"), dirMenu);
201 #endif
202
203 m_input->SetFocus();
204
205 SetAutoLayout( true );
206 SetSizer( topsizer );
207
208 topsizer->SetSizeHints( this );
209 topsizer->Fit( this );
210
211 Centre( wxBOTH );
212
213 return true;
214 }
215
216 void wxGenericDirDialog::EndModal(int retCode)
217 {
218 // before proceeding, change the current working directory if user asked so
219 if (retCode == wxID_OK && HasFlag(wxDD_CHANGE_DIR))
220 wxSetWorkingDirectory(m_path);
221
222 wxDialog::EndModal(retCode);
223 }
224
225 void wxGenericDirDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
226 {
227 EndModal(wxID_CANCEL);
228 }
229
230 void wxGenericDirDialog::OnOK(wxCommandEvent& WXUNUSED(event))
231 {
232 m_path = m_input->GetValue();
233
234 // Does the path exist? (User may have typed anything in m_input)
235 if (wxDirExists(m_path))
236 {
237 // OK, path exists, we're done.
238 EndModal(wxID_OK);
239 return;
240 }
241
242 // Interact with user, find out if the dir is a typo or to be created
243 wxString msg;
244 msg.Printf(_("The directory '%s' does not exist\nCreate it now?"),
245 m_path.c_str());
246 wxMessageDialog dialog(this, msg, _("Directory does not exist"),
247 wxYES_NO | wxICON_WARNING);
248
249 if ( dialog.ShowModal() == wxID_YES )
250 {
251 // Okay, let's make it
252 wxLogNull log;
253 if (wxMkdir(m_path))
254 {
255 // The new dir was created okay.
256 EndModal(wxID_OK);
257 return;
258 }
259 else
260 {
261 // Trouble...
262 msg.Printf(_("Failed to create directory '%s'\n(Do you have the required permissions?)"),
263 m_path.c_str());
264 wxMessageDialog errmsg(this, msg, _("Error creating directory"), wxOK | wxICON_ERROR);
265 errmsg.ShowModal();
266 // We still don't have a valid dir. Back to the main dialog.
267 }
268 }
269 // User has answered NO to create dir.
270 }
271
272 void wxGenericDirDialog::SetPath(const wxString& path)
273 {
274 m_dirCtrl->SetPath(path);
275 m_path = path;
276 }
277
278 wxString wxGenericDirDialog::GetPath(void) const
279 {
280 return m_path;
281 }
282
283 int wxGenericDirDialog::ShowModal()
284 {
285 m_input->SetValue( m_path );
286 return wxDialog::ShowModal();
287 }
288
289 void wxGenericDirDialog::OnTreeSelected( wxTreeEvent &event )
290 {
291 if (!m_dirCtrl)
292 return;
293
294 wxTreeItemId item = event.GetItem();
295
296 wxDirItemData *data = NULL;
297
298 if(item.IsOk())
299 data = (wxDirItemData*)m_dirCtrl->GetTreeCtrl()->GetItemData(item);
300
301 if (data)
302 m_input->SetValue( data->m_path );
303 }
304
305 void wxGenericDirDialog::OnTreeKeyDown( wxTreeEvent &WXUNUSED(event) )
306 {
307 if (!m_dirCtrl)
308 return;
309
310 wxDirItemData *data = (wxDirItemData*)m_dirCtrl->GetTreeCtrl()->GetItemData(m_dirCtrl->GetTreeCtrl()->GetSelection());
311 if (data)
312 m_input->SetValue( data->m_path );
313 }
314
315 void wxGenericDirDialog::OnShowHidden( wxCommandEvent& event )
316 {
317 if (!m_dirCtrl)
318 return;
319
320 m_dirCtrl->ShowHidden( event.GetInt() != 0 );
321 }
322
323 void wxGenericDirDialog::OnNew( wxCommandEvent& WXUNUSED(event) )
324 {
325 wxTreeItemId id = m_dirCtrl->GetTreeCtrl()->GetSelection();
326 if ((id == m_dirCtrl->GetTreeCtrl()->GetRootItem()) ||
327 (m_dirCtrl->GetTreeCtrl()->GetItemParent(id) == m_dirCtrl->GetTreeCtrl()->GetRootItem()))
328 {
329 wxMessageDialog msg(this, _("You cannot add a new directory to this section."),
330 _("Create directory"), wxOK | wxICON_INFORMATION );
331 msg.ShowModal();
332 return;
333 }
334
335 wxTreeItemId parent = id ; // m_dirCtrl->GetTreeCtrl()->GetItemParent( id );
336 wxDirItemData *data = (wxDirItemData*)m_dirCtrl->GetTreeCtrl()->GetItemData( parent );
337 wxASSERT( data );
338
339 wxString new_name( _("NewName") );
340 wxString path( data->m_path );
341 if (!wxEndsWithPathSeparator(path))
342 path += wxFILE_SEP_PATH;
343 path += new_name;
344 if (wxDirExists(path))
345 {
346 // try NewName0, NewName1 etc.
347 int i = 0;
348 do {
349 new_name = _("NewName");
350 wxString num;
351 num.Printf( wxT("%d"), i );
352 new_name += num;
353
354 path = data->m_path;
355 if (!wxEndsWithPathSeparator(path))
356 path += wxFILE_SEP_PATH;
357 path += new_name;
358 i++;
359 } while (wxDirExists(path));
360 }
361
362 wxLogNull log;
363 if (!wxMkdir(path))
364 {
365 wxMessageDialog dialog(this, _("Operation not permitted."), _("Error"), wxOK | wxICON_ERROR );
366 dialog.ShowModal();
367 return;
368 }
369
370 wxDirItemData *new_data = new wxDirItemData( path, new_name, true );
371
372 // TODO: THIS CODE DOESN'T WORK YET. We need to avoid duplication of the first child
373 // of the parent.
374 wxTreeItemId new_id = m_dirCtrl->GetTreeCtrl()->AppendItem( parent, new_name, 0, 0, new_data );
375 m_dirCtrl->GetTreeCtrl()->EnsureVisible( new_id );
376 m_dirCtrl->GetTreeCtrl()->EditLabel( new_id );
377 }
378
379 void wxGenericDirDialog::OnGoHome(wxCommandEvent& WXUNUSED(event))
380 {
381 SetPath(wxGetUserHome());
382 }
383
384 #endif // wxUSE_DIRDLG