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