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