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