1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/dirdlg.cpp
3 // Purpose:     native implementation of wxDirDialog
4 // Author:      Robert Roebling, Zbigniew Zagorski, Mart Raudsepp, Francesco Montorsi
5 // Copyright:   (c) 1998 Robert Roebling, 2004 Zbigniew Zagorski, 2005 Mart Raudsepp
6 // Licence:     wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8 
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
11 
12 
13 
14 /*
15   NOTE: the GtkFileChooser interface can be used both for wxFileDialog and for wxDirDialog.
16         Thus following code is very similar (even if not identic) to src/gtk/filedlg.cpp
17         If you find a problem in this code, remember to check also that file !
18 */
19 
20 
21 
22 #if wxUSE_DIRDLG
23 
24 #include "wx/dirdlg.h"
25 
26 #ifndef WX_PRECOMP
27     #include "wx/intl.h"
28     #include "wx/filedlg.h"
29 #endif
30 
31 #include "wx/gtk/private.h"
32 #include "wx/gtk/private/mnemonics.h"
33 #include "wx/stockitem.h"
34 
35 extern "C" {
gtk_dirdialog_response_callback(GtkWidget * WXUNUSED (w),gint response,wxDirDialog * dialog)36 static void gtk_dirdialog_response_callback(GtkWidget * WXUNUSED(w),
37                                              gint response,
38                                              wxDirDialog *dialog)
39 {
40     if (response == GTK_RESPONSE_ACCEPT)
41         dialog->GTKOnAccept();
42     else // GTK_RESPONSE_CANCEL or GTK_RESPONSE_NONE
43         dialog->GTKOnCancel();
44 }
45 }
46 
47 //-----------------------------------------------------------------------------
48 // wxDirDialog
49 //-----------------------------------------------------------------------------
50 
51 wxIMPLEMENT_DYNAMIC_CLASS(wxDirDialog, wxDialog);
52 
wxDirDialog(wxWindow * parent,const wxString & title,const wxString & defaultPath,long style,const wxPoint & pos,const wxSize & WXUNUSED (sz),const wxString & WXUNUSED (name))53 wxDirDialog::wxDirDialog(wxWindow* parent,
54                          const wxString& title,
55                          const wxString& defaultPath,
56                          long style,
57                          const wxPoint& pos,
58                          const wxSize& WXUNUSED(sz),
59                          const wxString& WXUNUSED(name))
60 {
61     Create(parent, title, defaultPath, style, pos);
62 }
63 
Create(wxWindow * parent,const wxString & title,const wxString & defaultPath,long style,const wxPoint & pos,const wxSize & WXUNUSED (sz),const wxString & WXUNUSED (name))64 bool wxDirDialog::Create(wxWindow* parent,
65                          const wxString& title,
66                          const wxString& defaultPath,
67                          long style,
68                          const wxPoint& pos,
69                          const wxSize& WXUNUSED(sz),
70                          const wxString& WXUNUSED(name))
71 {
72     m_message = title;
73 
74     wxASSERT_MSG( !( (style & wxDD_MULTIPLE) && (style & wxDD_CHANGE_DIR) ),
75                   "wxDD_CHANGE_DIR can't be used together with wxDD_MULTIPLE" );
76 
77     parent = GetParentForModalDialog(parent, style);
78 
79     if (!PreCreation(parent, pos, wxDefaultSize) ||
80         !CreateBase(parent, wxID_ANY, pos, wxDefaultSize, style,
81                 wxDefaultValidator, wxT("dirdialog")))
82     {
83         wxFAIL_MSG( wxT("wxDirDialog creation failed") );
84         return false;
85     }
86 
87     GtkWindow* gtk_parent = NULL;
88     if (parent)
89         gtk_parent = GTK_WINDOW( gtk_widget_get_toplevel(parent->m_widget) );
90 
91     m_widget = gtk_file_chooser_dialog_new(
92                    wxGTK_CONV(m_message),
93                    gtk_parent,
94                    GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
95 #ifdef __WXGTK4__
96                    static_cast<const char*>(wxGTK_CONV(wxConvertMnemonicsToGTK(wxGetStockLabel(wxID_CANCEL)))),
97 #else
98                    "gtk-cancel",
99 #endif
100                    GTK_RESPONSE_CANCEL,
101 #ifdef __WXGTK4__
102                    static_cast<const char*>(wxGTK_CONV(wxConvertMnemonicsToGTK(wxGetStockLabel(wxID_OPEN)))),
103 #else
104                    "gtk-open",
105 #endif
106                    GTK_RESPONSE_ACCEPT,
107                    NULL);
108 
109     g_object_ref(m_widget);
110 
111     gtk_dialog_set_default_response(GTK_DIALOG(m_widget), GTK_RESPONSE_ACCEPT);
112 #if GTK_CHECK_VERSION(2,18,0)
113     if (wx_is_at_least_gtk2(18))
114     {
115         gtk_file_chooser_set_create_folders(
116             GTK_FILE_CHOOSER(m_widget), !HasFlag(wxDD_DIR_MUST_EXIST) );
117     }
118 #endif
119 
120     // Enable multiple selection if desired
121     gtk_file_chooser_set_select_multiple(
122         GTK_FILE_CHOOSER(m_widget), HasFlag(wxDD_MULTIPLE) );
123 
124     // Enable show hidden folders if desired
125     gtk_file_chooser_set_show_hidden(
126         GTK_FILE_CHOOSER(m_widget), HasFlag(wxDD_SHOW_HIDDEN) );
127 
128     // local-only property could be set to false to allow non-local files to be loaded.
129     // In that case get/set_uri(s) should be used instead of get/set_filename(s) everywhere
130     // and the GtkFileChooserDialog should probably also be created with a backend,
131     // e.g. "gnome-vfs", "default", ... (gtk_file_chooser_dialog_new_with_backend).
132     // Currently local-only is kept as the default - true:
133     // gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(m_widget), true);
134 
135     g_signal_connect (m_widget, "response",
136         G_CALLBACK (gtk_dirdialog_response_callback), this);
137 
138     if ( !defaultPath.empty() )
139         SetPath(defaultPath);
140 
141     return true;
142 }
143 
GTKOnAccept()144 void wxDirDialog::GTKOnAccept()
145 {
146     GSList *fnamesi = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(m_widget));
147     GSList *fnames = fnamesi;
148 
149     while ( fnamesi )
150     {
151         wxString dir(wxString::FromUTF8(static_cast<gchar *>(fnamesi->data)));
152         m_paths.Add(dir);
153 
154         g_free(fnamesi->data);
155         fnamesi = fnamesi->next;
156     }
157 
158     g_slist_free(fnames);
159 
160     // change to the directory where the user went if asked
161     if (HasFlag(wxDD_CHANGE_DIR))
162     {
163         wxSetWorkingDirectory(m_paths.Last());
164     }
165 
166     if (!HasFlag(wxDD_MULTIPLE))
167     {
168         m_path = m_paths.Last();
169     }
170 
171     EndDialog(wxID_OK);
172 }
173 
GTKOnCancel()174 void wxDirDialog::GTKOnCancel()
175 {
176     EndDialog(wxID_CANCEL);
177 }
178 
DoSetSize(int x,int y,int width,int height,int sizeFlags)179 void wxDirDialog::DoSetSize(int x, int y, int width, int height, int sizeFlags)
180 {
181     if (!m_wxwindow)
182         return;
183 
184     wxDirDialogBase::DoSetSize( x, y, width, height, sizeFlags );
185 }
186 
SetPath(const wxString & dir)187 void wxDirDialog::SetPath(const wxString& dir)
188 {
189     if (wxDirExists(dir))
190     {
191         gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_widget),
192                                             wxGTK_CONV_FN(dir));
193     }
194 }
195 
196 #endif // wxUSE_DIRDLG
197