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