1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/filedlg.cpp
3 // Purpose: native implementation of wxFileDialog
4 // Author: Robert Roebling, Zbigniew Zagorski, Mart Raudsepp
6 // Copyright: (c) 1998 Robert Roebling, 2004 Zbigniew Zagorski, 2005 Mart Raudsepp
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
15 #include "wx/filedlg.h"
19 #include "wx/msgdlg.h"
25 #include "wx/gtk/private.h"
27 #include <unistd.h> // chdir
29 #include "wx/filename.h" // wxFilename
30 #include "wx/tokenzr.h" // wxStringTokenizer
31 #include "wx/filefn.h" // ::wxGetCwd
33 //-----------------------------------------------------------------------------
35 //-----------------------------------------------------------------------------
37 extern void wxapp_install_idle_handler();
39 //-----------------------------------------------------------------------------
40 // "clicked" for OK-button
41 //-----------------------------------------------------------------------------
44 static void gtk_filedialog_ok_callback(GtkWidget
*widget
, wxFileDialog
*dialog
)
46 int style
= dialog
->GetStyle();
47 gchar
* filename
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget
));
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
)
53 if ((style
& wxSAVE
) && (style
& wxOVERWRITE_PROMPT
))
55 if ( g_file_test(filename
, G_FILE_TEST_EXISTS
) )
60 _("File '%s' already exists, do you really want to overwrite it?"),
61 wxString(wxConvFileName
->cMB2WX(filename
)).c_str());
63 wxMessageDialog
dlg(dialog
, msg
, _("Confirm"),
64 wxYES_NO
| wxICON_QUESTION
);
65 if (dlg
.ShowModal() != wxID_YES
)
70 // change to the directory where the user went if asked
71 if (style
& wxCHANGE_DIR
)
73 // Use chdir to not care about filename encodings
74 gchar
* folder
= g_path_get_dirname(filename
);
81 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_OK
);
82 event
.SetEventObject(dialog
);
83 dialog
->GetEventHandler()->ProcessEvent(event
);
87 //-----------------------------------------------------------------------------
88 // "clicked" for Cancel-button
89 //-----------------------------------------------------------------------------
92 static void gtk_filedialog_cancel_callback(GtkWidget
*w
, wxFileDialog
*dialog
)
94 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
95 event
.SetEventObject(dialog
);
96 dialog
->GetEventHandler()->ProcessEvent(event
);
101 static void gtk_filedialog_response_callback(GtkWidget
*w
,
103 wxFileDialog
*dialog
)
105 wxapp_install_idle_handler();
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
);
114 #endif // __WXGTK24__
116 //-----------------------------------------------------------------------------
118 //-----------------------------------------------------------------------------
120 IMPLEMENT_DYNAMIC_CLASS(wxFileDialog
,wxGenericFileDialog
)
122 BEGIN_EVENT_TABLE(wxFileDialog
,wxGenericFileDialog
)
123 EVT_BUTTON(wxID_OK
, wxFileDialog
::OnFakeOk
)
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 )
135 if (!gtk_check_version(2,4,0))
137 wxASSERT_MSG( !( (style
& wxSAVE
) && (style
& wxMULTIPLE
) ), wxT("wxFileDialog - wxMULTIPLE used on a save dialog" ) );
138 m_needParent
= false;
140 if (!PreCreation(parent
, pos
, wxDefaultSize
) ||
141 !CreateBase(parent
, wxID_ANY
, pos
, wxDefaultSize
, style
,
142 wxDefaultValidator
, wxT("filedialog")))
144 wxFAIL_MSG( wxT("wxFileDialog creation failed") );
148 GtkFileChooserAction gtk_action
;
149 GtkWindow
* gtk_parent
= NULL
;
151 gtk_parent
= GTK_WINDOW( gtk_widget_get_toplevel(parent
->m_widget
) );
153 const gchar
* ok_btn_stock
;
154 if ( style
& wxSAVE
)
156 gtk_action
= GTK_FILE_CHOOSER_ACTION_SAVE
;
157 ok_btn_stock
= GTK_STOCK_SAVE
;
161 gtk_action
= GTK_FILE_CHOOSER_ACTION_OPEN
;
162 ok_btn_stock
= GTK_STOCK_OPEN
;
165 m_widget
= gtk_file_chooser_dialog_new(
166 wxGTK_CONV(m_message
),
169 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
170 ok_btn_stock
, GTK_RESPONSE_ACCEPT
,
173 gtk_dialog_set_default_response(GTK_DIALOG(m_widget
), GTK_RESPONSE_ACCEPT
);
175 if ( style
& wxMULTIPLE
)
176 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(m_widget
), true);
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
),
183 G_CALLBACK (gtk_widget_hide_on_delete
),
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);
193 g_signal_connect (m_widget
, "response",
194 G_CALLBACK (gtk_filedialog_response_callback
), this);
196 SetWildcard(wildCard
);
198 if ( style
& wxSAVE
)
200 if ( !defaultDir
.empty() )
201 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_widget
),
202 wxConvFileName
->cWX2MB(defaultDir
));
204 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget
),
205 wxConvFileName
->cWX2MB(defaultFileName
));
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
);
214 if ( !defaultFileName
.empty() )
217 if ( defaultDir
.empty() )
222 gtk_file_chooser_set_filename(
223 GTK_FILE_CHOOSER(m_widget
),
224 wxConvFileName
->cWX2MB( wxFileName(dir
, defaultFileName
).GetFullPath() ) );
226 else if ( !defaultDir
.empty() )
227 gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(m_widget
),
228 wxConvFileName
->cWX2MB(defaultDir
) );
233 wxGenericFileDialog
::Create( parent
, message
, defaultDir
, defaultFileName
, wildCard
, style
, pos
);
236 void wxFileDialog
::OnFakeOk( wxCommandEvent
&event
)
239 if (!gtk_check_version(2,4,0))
240 wxDialog
::OnOK( event
);
243 wxGenericFileDialog
::OnListOk( event
);
246 int wxFileDialog
::ShowModal()
249 if (!gtk_check_version(2,4,0))
250 return wxDialog
::ShowModal();
253 return wxGenericFileDialog
::ShowModal();
256 bool wxFileDialog
::Show( bool show
)
259 if (!gtk_check_version(2,4,0))
260 return wxDialog
::Show( show
);
263 return wxGenericFileDialog
::Show( show
);
266 void wxFileDialog
::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
271 wxGenericFileDialog
::DoSetSize( x
, y
, width
, height
, sizeFlags
);
274 wxString wxFileDialog
::GetPath() const
277 if (!gtk_check_version(2,4,0))
278 return wxConvFileName
->cMB2WX(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(m_widget
)));
281 return wxGenericFileDialog
::GetPath();
284 void wxFileDialog
::GetFilenames(wxArrayString
& files
) const
287 if (!gtk_check_version(2,4,0))
290 for (size_t n
= 0; n
< files
.GetCount(); ++n
)
292 wxFileName
file(files
[n
]);
293 files
[n
] = file
.GetFullName();
298 wxGenericFileDialog
::GetFilenames( files
);
301 void wxFileDialog
::GetPaths(wxArrayString
& paths
) const
304 if (!gtk_check_version(2,4,0))
307 if (gtk_file_chooser_get_select_multiple(GTK_FILE_CHOOSER(m_widget
)))
309 GSList
*gpathsi
= gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(m_widget
));
310 GSList
*gpaths
= gpathsi
;
313 wxString
file(wxConvFileName
->cMB2WX((gchar
*) gpathsi
->data
));
315 g_free(gpathsi
->data
);
316 gpathsi
= gpathsi
->next
;
319 g_slist_free(gpaths
);
322 paths
.Add(GetPath());
326 wxGenericFileDialog
::GetPaths( paths
);
329 void wxFileDialog
::SetMessage(const wxString
& message
)
332 if (!gtk_check_version(2,4,0))
339 wxGenericFileDialog
::SetMessage( message
);
342 void wxFileDialog
::SetPath(const wxString
& path
)
345 if (!gtk_check_version(2,4,0))
347 if (path
.empty()) return;
349 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(m_widget
), wxConvFileName
->cWX2MB(path
));
353 wxGenericFileDialog
::SetPath( path
);
356 void wxFileDialog
::SetDirectory(const wxString
& dir
)
359 if (!gtk_check_version(2,4,0))
361 if (wxDirExists(dir
))
363 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_widget
), wxConvFileName
->cWX2MB(dir
));
368 wxGenericFileDialog
::SetDirectory( dir
);
371 wxString wxFileDialog
::GetDirectory() const
374 if (!gtk_check_version(2,4,0))
375 return wxConvFileName
->cMB2WX(
376 gtk_file_chooser_get_current_folder( GTK_FILE_CHOOSER(m_widget
) ) );
379 return wxGenericFileDialog
::GetDirectory();
382 void wxFileDialog
::SetFilename(const wxString
& name
)
385 if (!gtk_check_version(2,4,0))
387 if (GetStyle() & wxSAVE
)
388 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget
), wxConvFileName
->cWX2MB(name
));
390 SetPath(wxFileName(GetDirectory(), name
).GetFullPath());
394 wxGenericFileDialog
::SetFilename( name
);
397 wxString wxFileDialog
::GetFilename() const
400 if (!gtk_check_version(2,4,0))
402 wxConvFileName
->cMB2WX(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(m_widget
))) ).GetFullName();
405 return wxGenericFileDialog
::GetFilename();
408 void wxFileDialog
::SetWildcard(const wxString
& wildCard
)
411 if (!gtk_check_version(2,4,0))
414 wxArrayString wildDescriptions
, wildFilters
;
415 if (!wxParseCommonDialogsFilter(wildCard
, wildDescriptions
, wildFilters
))
417 wxFAIL_MSG( wxT("wxFileDialog::SetWildCard - bad wildcard string") );
421 // Parsing went fine. Set m_wildCard to be returned by wxFileDialogBase::GetWildcard
422 m_wildCard
= wildCard
;
424 GtkFileChooser
* chooser
= GTK_FILE_CHOOSER(m_widget
);
426 // empty current filter list:
427 GSList
* ifilters
= gtk_file_chooser_list_filters(chooser
);
428 GSList
* filters
= ifilters
;
432 gtk_file_chooser_remove_filter(chooser
,GTK_FILE_FILTER(ifilters
->data
));
433 ifilters
= ifilters
->next
;
435 g_slist_free(filters
);
437 // add parsed to GtkChooser
438 for (size_t n
= 0; n
< wildFilters
.GetCount(); ++n
)
440 GtkFileFilter
* filter
= gtk_file_filter_new();
441 gtk_file_filter_set_name(filter
, wxGTK_CONV(wildDescriptions
[n
]));
443 wxStringTokenizer
exttok(wildFilters
[n
], wxT(";"));
444 while (exttok
.HasMoreTokens())
446 wxString token
= exttok
.GetNextToken();
447 gtk_file_filter_add_pattern(filter
, wxGTK_CONV(token
));
450 gtk_file_chooser_add_filter(chooser
, filter
);
453 // Reset the filter index
459 wxGenericFileDialog
::SetWildcard( wildCard
);
462 void wxFileDialog
::SetFilterIndex(int filterIndex
)
465 if (!gtk_check_version(2,4,0))
468 GtkFileChooser
*chooser
= GTK_FILE_CHOOSER(m_widget
);
469 GSList
*filters
= gtk_file_chooser_list_filters(chooser
);
471 filter
= g_slist_nth_data(filters
, filterIndex
);
475 gtk_file_chooser_set_filter(chooser
, GTK_FILE_FILTER(filter
));
479 wxFAIL_MSG( wxT("wxFileDialog::SetFilterIndex - bad filter index") );
482 g_slist_free(filters
);
486 wxGenericFileDialog
::SetFilterIndex( filterIndex
);
489 int wxFileDialog
::GetFilterIndex() const
492 if (!gtk_check_version(2,4,0))
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
);
502 wxFAIL_MSG( wxT("wxFileDialog::GetFilterIndex - bad filter index returned by gtk+") );
510 return wxGenericFileDialog
::GetFilterIndex();
513 #endif // wxUSE_FILEDLG