fix the bug which prevented the same wxFile/DirDialog object from being used twice...
[wxWidgets.git] / src / gtk / filedlg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/filedlg.cpp
3 // Purpose: native implementation of wxFileDialog
4 // Author: Robert Roebling, Zbigniew Zagorski, Mart Raudsepp
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, 2004 Zbigniew Zagorski, 2005 Mart Raudsepp
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if wxUSE_FILEDLG
14
15 #include "wx/filedlg.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/intl.h"
19 #include "wx/msgdlg.h"
20 #endif
21
22 #ifdef __WXGTK24__
23
24 #include <gtk/gtk.h>
25 #include "wx/gtk/private.h"
26
27 #include <unistd.h> // chdir
28
29 #include "wx/filename.h" // wxFilename
30 #include "wx/tokenzr.h" // wxStringTokenizer
31 #include "wx/filefn.h" // ::wxGetCwd
32
33 //-----------------------------------------------------------------------------
34 // idle system
35 //-----------------------------------------------------------------------------
36
37 extern void wxapp_install_idle_handler();
38
39 //-----------------------------------------------------------------------------
40 // "clicked" for OK-button
41 //-----------------------------------------------------------------------------
42
43 extern "C" {
44 static void gtk_filedialog_ok_callback(GtkWidget *widget, wxFileDialog *dialog)
45 {
46 int style = dialog->GetStyle();
47 gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
48
49 // gtk version numbers must be identical with the one in ctor (that calls set_do_overwrite_confirmation)
50 #if GTK_CHECK_VERSION(2,7,3)
51 if(gtk_check_version(2,7,3) != NULL)
52 #endif
53 if ((style & wxSAVE) && (style & wxOVERWRITE_PROMPT))
54 {
55 if ( g_file_test(filename, G_FILE_TEST_EXISTS) )
56 {
57 wxString msg;
58
59 msg.Printf(
60 _("File '%s' already exists, do you really want to overwrite it?"),
61 wxString(wxConvFileName->cMB2WX(filename)).c_str());
62
63 wxMessageDialog dlg(dialog, msg, _("Confirm"),
64 wxYES_NO | wxICON_QUESTION);
65 if (dlg.ShowModal() != wxID_YES)
66 return;
67 }
68 }
69
70 // change to the directory where the user went if asked
71 if (style & wxCHANGE_DIR)
72 {
73 // Use chdir to not care about filename encodings
74 gchar* folder = g_path_get_dirname(filename);
75 chdir(folder);
76 g_free(folder);
77 }
78
79 g_free(filename);
80
81 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK);
82 event.SetEventObject(dialog);
83 dialog->GetEventHandler()->ProcessEvent(event);
84 }
85 }
86
87 //-----------------------------------------------------------------------------
88 // "clicked" for Cancel-button
89 //-----------------------------------------------------------------------------
90
91 extern "C" {
92 static void gtk_filedialog_cancel_callback(GtkWidget *w, wxFileDialog *dialog)
93 {
94 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
95 event.SetEventObject(dialog);
96 dialog->GetEventHandler()->ProcessEvent(event);
97 }
98 }
99
100 extern "C" {
101 static void gtk_filedialog_response_callback(GtkWidget *w,
102 gint response,
103 wxFileDialog *dialog)
104 {
105 wxapp_install_idle_handler();
106
107 if (response == GTK_RESPONSE_ACCEPT)
108 gtk_filedialog_ok_callback(w, dialog);
109 else // GTK_RESPONSE_CANCEL or GTK_RESPONSE_NONE
110 gtk_filedialog_cancel_callback(w, dialog);
111 }
112 }
113
114 #endif // __WXGTK24__
115
116 //-----------------------------------------------------------------------------
117 // wxFileDialog
118 //-----------------------------------------------------------------------------
119
120 IMPLEMENT_DYNAMIC_CLASS(wxFileDialog,wxGenericFileDialog)
121
122 BEGIN_EVENT_TABLE(wxFileDialog,wxGenericFileDialog)
123 EVT_BUTTON(wxID_OK, wxFileDialog::OnFakeOk)
124 END_EVENT_TABLE()
125
126 wxFileDialog::wxFileDialog(wxWindow *parent, const wxString& message,
127 const wxString& defaultDir,
128 const wxString& defaultFileName,
129 const wxString& wildCard,
130 long style, const wxPoint& pos)
131 : wxGenericFileDialog(parent, message, defaultDir, defaultFileName,
132 wildCard, style, pos, true )
133 {
134 #ifdef __WXGTK24__
135 if (!gtk_check_version(2,4,0))
136 {
137 wxASSERT_MSG( !( (style & wxSAVE) && (style & wxMULTIPLE) ), wxT("wxFileDialog - wxMULTIPLE used on a save dialog" ) );
138 m_needParent = false;
139
140 if (!PreCreation(parent, pos, wxDefaultSize) ||
141 !CreateBase(parent, wxID_ANY, pos, wxDefaultSize, style,
142 wxDefaultValidator, wxT("filedialog")))
143 {
144 wxFAIL_MSG( wxT("wxFileDialog creation failed") );
145 return;
146 }
147
148 GtkFileChooserAction gtk_action;
149 GtkWindow* gtk_parent = NULL;
150 if (parent)
151 gtk_parent = GTK_WINDOW( gtk_widget_get_toplevel(parent->m_widget) );
152
153 const gchar* ok_btn_stock;
154 if ( style & wxSAVE )
155 {
156 gtk_action = GTK_FILE_CHOOSER_ACTION_SAVE;
157 ok_btn_stock = GTK_STOCK_SAVE;
158 }
159 else
160 {
161 gtk_action = GTK_FILE_CHOOSER_ACTION_OPEN;
162 ok_btn_stock = GTK_STOCK_OPEN;
163 }
164
165 m_widget = gtk_file_chooser_dialog_new(
166 wxGTK_CONV(m_message),
167 gtk_parent,
168 gtk_action,
169 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
170 ok_btn_stock, GTK_RESPONSE_ACCEPT,
171 NULL);
172
173 gtk_dialog_set_default_response(GTK_DIALOG(m_widget), GTK_RESPONSE_ACCEPT);
174
175 if ( style & wxMULTIPLE )
176 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(m_widget), true);
177
178 // gtk_widget_hide_on_delete is used here to avoid that Gtk automatically destroys
179 // the dialog when the user press ESC on the dialog: in that case a second call to
180 // ShowModal() would result in a bunch of Gtk-CRITICAL errors...
181 g_signal_connect (G_OBJECT(m_widget),
182 "delete_event",
183 G_CALLBACK (gtk_widget_hide_on_delete),
184 (gpointer)this);
185
186 // local-only property could be set to false to allow non-local files to be loaded.
187 // In that case get/set_uri(s) should be used instead of get/set_filename(s) everywhere
188 // and the GtkFileChooserDialog should probably also be created with a backend,
189 // e.g "gnome-vfs", "default", ... (gtk_file_chooser_dialog_new_with_backend).
190 // Currently local-only is kept as the default - true:
191 // gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(m_widget), true);
192
193 g_signal_connect (m_widget, "response",
194 G_CALLBACK (gtk_filedialog_response_callback), this);
195
196 SetWildcard(wildCard);
197
198 if ( style & wxSAVE )
199 {
200 if ( !defaultDir.empty() )
201 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_widget),
202 wxConvFileName->cWX2MB(defaultDir));
203
204 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget),
205 wxConvFileName->cWX2MB(defaultFileName));
206
207 #if GTK_CHECK_VERSION(2,7,3)
208 if ((style & wxOVERWRITE_PROMPT) && !gtk_check_version(2,7,3))
209 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(m_widget), TRUE);
210 #endif
211 }
212 else
213 {
214 if ( !defaultFileName.empty() )
215 {
216 wxString dir;
217 if ( defaultDir.empty() )
218 dir = ::wxGetCwd();
219 else
220 dir = defaultDir;
221
222 gtk_file_chooser_set_filename(
223 GTK_FILE_CHOOSER(m_widget),
224 wxConvFileName->cWX2MB( wxFileName(dir, defaultFileName).GetFullPath() ) );
225 }
226 else if ( !defaultDir.empty() )
227 gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(m_widget),
228 wxConvFileName->cWX2MB(defaultDir) );
229 }
230 }
231 else
232 #endif
233 wxGenericFileDialog::Create( parent, message, defaultDir, defaultFileName, wildCard, style, pos );
234 }
235
236 void wxFileDialog::OnFakeOk( wxCommandEvent &event )
237 {
238 #ifdef __WXGTK24__
239 if (!gtk_check_version(2,4,0))
240 wxDialog::OnOK( event );
241 else
242 #endif
243 wxGenericFileDialog::OnListOk( event );
244 }
245
246 int wxFileDialog::ShowModal()
247 {
248 #ifdef __WXGTK24__
249 if (!gtk_check_version(2,4,0))
250 return wxDialog::ShowModal();
251 else
252 #endif
253 return wxGenericFileDialog::ShowModal();
254 }
255
256 bool wxFileDialog::Show( bool show )
257 {
258 #ifdef __WXGTK24__
259 if (!gtk_check_version(2,4,0))
260 return wxDialog::Show( show );
261 else
262 #endif
263 return wxGenericFileDialog::Show( show );
264 }
265
266 void wxFileDialog::DoSetSize(int x, int y, int width, int height, int sizeFlags )
267 {
268 if (!m_wxwindow)
269 return;
270 else
271 wxGenericFileDialog::DoSetSize( x, y, width, height, sizeFlags );
272 }
273
274 wxString wxFileDialog::GetPath() const
275 {
276 #ifdef __WXGTK24__
277 if (!gtk_check_version(2,4,0))
278 return wxConvFileName->cMB2WX(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(m_widget)));
279 else
280 #endif
281 return wxGenericFileDialog::GetPath();
282 }
283
284 void wxFileDialog::GetFilenames(wxArrayString& files) const
285 {
286 #ifdef __WXGTK24__
287 if (!gtk_check_version(2,4,0))
288 {
289 GetPaths(files);
290 for (size_t n = 0; n < files.GetCount(); ++n )
291 {
292 wxFileName file(files[n]);
293 files[n] = file.GetFullName();
294 }
295 }
296 else
297 #endif
298 wxGenericFileDialog::GetFilenames( files );
299 }
300
301 void wxFileDialog::GetPaths(wxArrayString& paths) const
302 {
303 #ifdef __WXGTK24__
304 if (!gtk_check_version(2,4,0))
305 {
306 paths.Empty();
307 if (gtk_file_chooser_get_select_multiple(GTK_FILE_CHOOSER(m_widget)))
308 {
309 GSList *gpathsi = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(m_widget));
310 GSList *gpaths = gpathsi;
311 while (gpathsi)
312 {
313 wxString file(wxConvFileName->cMB2WX((gchar*) gpathsi->data));
314 paths.Add(file);
315 g_free(gpathsi->data);
316 gpathsi = gpathsi->next;
317 }
318
319 g_slist_free(gpaths);
320 }
321 else
322 paths.Add(GetPath());
323 }
324 else
325 #endif
326 wxGenericFileDialog::GetPaths( paths );
327 }
328
329 void wxFileDialog::SetMessage(const wxString& message)
330 {
331 #ifdef __WXGTK24__
332 if (!gtk_check_version(2,4,0))
333 {
334 m_message = message;
335 SetTitle(message);
336 }
337 else
338 #endif
339 wxGenericFileDialog::SetMessage( message );
340 }
341
342 void wxFileDialog::SetPath(const wxString& path)
343 {
344 #ifdef __WXGTK24__
345 if (!gtk_check_version(2,4,0))
346 {
347 if (path.empty()) return;
348
349 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(m_widget), wxConvFileName->cWX2MB(path));
350 }
351 else
352 #endif
353 wxGenericFileDialog::SetPath( path );
354 }
355
356 void wxFileDialog::SetDirectory(const wxString& dir)
357 {
358 #ifdef __WXGTK24__
359 if (!gtk_check_version(2,4,0))
360 {
361 if (wxDirExists(dir))
362 {
363 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_widget), wxConvFileName->cWX2MB(dir));
364 }
365 }
366 else
367 #endif
368 wxGenericFileDialog::SetDirectory( dir );
369 }
370
371 wxString wxFileDialog::GetDirectory() const
372 {
373 #ifdef __WXGTK24__
374 if (!gtk_check_version(2,4,0))
375 return wxConvFileName->cMB2WX(
376 gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER(m_widget) ) );
377 else
378 #endif
379 return wxGenericFileDialog::GetDirectory();
380 }
381
382 void wxFileDialog::SetFilename(const wxString& name)
383 {
384 #ifdef __WXGTK24__
385 if (!gtk_check_version(2,4,0))
386 {
387 if (GetStyle() & wxSAVE)
388 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget), wxConvFileName->cWX2MB(name));
389 else
390 SetPath(wxFileName(GetDirectory(), name).GetFullPath());
391 }
392 else
393 #endif
394 wxGenericFileDialog::SetFilename( name );
395 }
396
397 wxString wxFileDialog::GetFilename() const
398 {
399 #ifdef __WXGTK24__
400 if (!gtk_check_version(2,4,0))
401 return wxFileName(
402 wxConvFileName->cMB2WX(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(m_widget))) ).GetFullName();
403 else
404 #endif
405 return wxGenericFileDialog::GetFilename();
406 }
407
408 void wxFileDialog::SetWildcard(const wxString& wildCard)
409 {
410 #ifdef __WXGTK24__
411 if (!gtk_check_version(2,4,0))
412 {
413 // parse filters
414 wxArrayString wildDescriptions, wildFilters;
415 if (!wxParseCommonDialogsFilter(wildCard, wildDescriptions, wildFilters))
416 {
417 wxFAIL_MSG( wxT("wxFileDialog::SetWildCard - bad wildcard string") );
418 }
419 else
420 {
421 // Parsing went fine. Set m_wildCard to be returned by wxFileDialogBase::GetWildcard
422 m_wildCard = wildCard;
423
424 GtkFileChooser* chooser = GTK_FILE_CHOOSER(m_widget);
425
426 // empty current filter list:
427 GSList* ifilters = gtk_file_chooser_list_filters(chooser);
428 GSList* filters = ifilters;
429
430 while (ifilters)
431 {
432 gtk_file_chooser_remove_filter(chooser,GTK_FILE_FILTER(ifilters->data));
433 ifilters = ifilters->next;
434 }
435 g_slist_free(filters);
436
437 // add parsed to GtkChooser
438 for (size_t n = 0; n < wildFilters.GetCount(); ++n)
439 {
440 GtkFileFilter* filter = gtk_file_filter_new();
441 gtk_file_filter_set_name(filter, wxGTK_CONV(wildDescriptions[n]));
442
443 wxStringTokenizer exttok(wildFilters[n], wxT(";"));
444 while (exttok.HasMoreTokens())
445 {
446 wxString token = exttok.GetNextToken();
447 gtk_file_filter_add_pattern(filter, wxGTK_CONV(token));
448 }
449
450 gtk_file_chooser_add_filter(chooser, filter);
451 }
452
453 // Reset the filter index
454 SetFilterIndex(0);
455 }
456 }
457 else
458 #endif
459 wxGenericFileDialog::SetWildcard( wildCard );
460 }
461
462 void wxFileDialog::SetFilterIndex(int filterIndex)
463 {
464 #ifdef __WXGTK24__
465 if (!gtk_check_version(2,4,0))
466 {
467 gpointer filter;
468 GtkFileChooser *chooser = GTK_FILE_CHOOSER(m_widget);
469 GSList *filters = gtk_file_chooser_list_filters(chooser);
470
471 filter = g_slist_nth_data(filters, filterIndex);
472
473 if (filter != NULL)
474 {
475 gtk_file_chooser_set_filter(chooser, GTK_FILE_FILTER(filter));
476 }
477 else
478 {
479 wxFAIL_MSG( wxT("wxFileDialog::SetFilterIndex - bad filter index") );
480 }
481
482 g_slist_free(filters);
483 }
484 else
485 #endif
486 wxGenericFileDialog::SetFilterIndex( filterIndex );
487 }
488
489 int wxFileDialog::GetFilterIndex() const
490 {
491 #ifdef __WXGTK24__
492 if (!gtk_check_version(2,4,0))
493 {
494 GtkFileChooser *chooser = GTK_FILE_CHOOSER(m_widget);
495 GtkFileFilter *filter = gtk_file_chooser_get_filter(chooser);
496 GSList *filters = gtk_file_chooser_list_filters(chooser);
497 gint index = g_slist_index(filters, filter);
498 g_slist_free(filters);
499
500 if (index == -1)
501 {
502 wxFAIL_MSG( wxT("wxFileDialog::GetFilterIndex - bad filter index returned by gtk+") );
503 return 0;
504 }
505 else
506 return index;
507 }
508 else
509 #endif
510 return wxGenericFileDialog::GetFilterIndex();
511 }
512
513 #endif // wxUSE_FILEDLG