Moved the implemtation of the generic and the
[wxWidgets.git] / src / gtk1 / filedlg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/filedlg.cpp
3 // Purpose: native implementation of wxFileDialog
4 // Author: Robert Roebling, Zbigniew Zagorski
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, 2004 Zbigniew Zagorski
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
11 #pragma implementation "filedlg.h"
12 #endif
13
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16
17 #if wxUSE_FILEDLG
18
19 #include "wx/filedlg.h"
20 #include "wx/utils.h"
21 #include "wx/intl.h"
22 #include "wx/filename.h"
23 #include "wx/msgdlg.h"
24
25 #include <gtk/gtk.h>
26
27 #ifdef __WXGTK24__
28 #include "wx/gtk/private.h"
29
30 //-----------------------------------------------------------------------------
31 // idle system
32 //-----------------------------------------------------------------------------
33
34 extern void wxapp_install_idle_handler();
35 extern bool g_isIdle;
36
37 //-----------------------------------------------------------------------------
38 // "clicked" for OK-button
39 //-----------------------------------------------------------------------------
40
41 static void gtk_filedialog_ok_callback(GtkWidget *widget, wxFileDialog *dialog)
42 {
43 int style = dialog->GetStyle();
44 gchar* text = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
45 wxString filename(wxGTK_CONV_BACK(text));
46
47 if ((style & wxSAVE) && (style & wxOVERWRITE_PROMPT))
48 {
49 if (wxFileExists(filename))
50 {
51 wxString msg;
52 msg.Printf(
53 _("File '%s' already exists, do you really want to overwrite it?"),
54 filename.c_str());
55
56 wxMessageDialog dlg(dialog, msg, _("Confirm"),
57 wxYES_NO | wxICON_QUESTION);
58 if (dlg.ShowModal() != wxID_YES)
59 return;
60 }
61 }
62 else if ((style & wxOPEN) && ( style & wxFILE_MUST_EXIST))
63 {
64 if (!wxFileExists( filename ))
65 {
66 wxMessageDialog dlg(dialog,
67 _("Please choose an existing file."),
68 _("Error"), wxOK | wxICON_ERROR);
69 dlg.ShowModal();
70
71 return;
72 }
73 }
74
75 // change to the directory where the user went if asked
76 if (style & wxCHANGE_DIR)
77 {
78 wxString cwd;
79 wxSplitPath(filename, &cwd, NULL, NULL);
80
81 if (cwd != wxGetCwd())
82 {
83 wxSetWorkingDirectory(cwd);
84 }
85 }
86
87 dialog->SetPath(filename);
88 dialog->UpdateFromDialog();
89
90 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK);
91 event.SetEventObject(dialog);
92 dialog->GetEventHandler()->ProcessEvent(event);
93 }
94
95 //-----------------------------------------------------------------------------
96 // "clicked" for Cancel-button
97 //-----------------------------------------------------------------------------
98
99 static void gtk_filedialog_cancel_callback(GtkWidget *WXUNUSED(w),
100 wxFileDialog *dialog)
101 {
102 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
103 event.SetEventObject(dialog);
104 dialog->GetEventHandler()->ProcessEvent(event);
105 }
106
107 static void gtk_filedialog_response_callback(GtkWidget *w,
108 int response,
109 wxFileDialog *dialog)
110 {
111 wxapp_install_idle_handler();
112
113 if (response == GTK_RESPONSE_ACCEPT)
114 gtk_filedialog_ok_callback(w, dialog);
115 else if (response == GTK_RESPONSE_CANCEL)
116 gtk_filedialog_cancel_callback(w, dialog);
117 else // "delete"
118 {
119 gtk_filedialog_cancel_callback(w, dialog);
120 dialog->m_destroyed_by_delete = TRUE;
121 }
122 }
123 #endif
124
125 //-----------------------------------------------------------------------------
126 // wxFileDialog
127 //-----------------------------------------------------------------------------
128
129 IMPLEMENT_DYNAMIC_CLASS(wxFileDialog,wxGenericFileDialog)
130
131 BEGIN_EVENT_TABLE(wxFileDialog,wxGenericFileDialog)
132 EVT_BUTTON(wxID_OK, wxFileDialog::OnFakeOk)
133 END_EVENT_TABLE()
134
135 wxFileDialog::wxFileDialog(wxWindow *parent, const wxString& message,
136 const wxString& defaultDir,
137 const wxString& defaultFileName,
138 const wxString& wildCard,
139 long style, const wxPoint& pos)
140 : wxGenericFileDialog(parent, message, defaultDir, defaultFileName,
141 wildCard, style, pos, true )
142 {
143 #ifdef __WXGTK24__
144 m_needParent = FALSE;
145 m_destroyed_by_delete = FALSE;
146
147 if (!PreCreation(parent, pos, wxDefaultSize) ||
148 !CreateBase(parent, wxID_ANY, pos, wxDefaultSize, style,
149 wxDefaultValidator, wxT("filedialog")))
150 {
151 wxFAIL_MSG( wxT("wxFileDialog creation failed") );
152 return;
153 }
154
155 bool multiple = (style & wxMULTIPLE) == wxMULTIPLE;
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) == 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 m_widget = gtk_file_chooser_dialog_new(
173 wxGTK_CONV(m_message),
174 gtk_parent,
175 gtk_action,
176 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
177 ok_btn_stock, GTK_RESPONSE_ACCEPT,
178 NULL);
179
180 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(m_widget), multiple);
181
182 gtk_signal_connect(GTK_OBJECT(m_widget),
183 "response",
184 GTK_SIGNAL_FUNC(gtk_filedialog_response_callback),
185 (gpointer*)this);
186
187 m_path = m_dir;
188 if (!m_path.empty() && m_path.Last() != wxT('/'))
189 m_path += wxT('/');
190 m_path += m_fileName;
191 SetPath(m_path);
192
193 SetWildcard(wildCard);
194 SetFilterIndex(0);
195 #else
196 wxGenericFileDialog::Create( parent, message, defaultDir, defaultFileName, wildCard, style, pos );
197 #endif
198 }
199
200 wxFileDialog::~wxFileDialog()
201 {
202 #ifdef __WXGTK24__
203 if (m_destroyed_by_delete)
204 m_widget = NULL;
205 #endif
206 }
207
208 void wxFileDialog::OnFakeOk( wxCommandEvent &event )
209 {
210 #ifdef __WXGTK24__
211 wxDialog::OnOK( event );
212 #else
213 wxGenericFileDialog::OnListOk( event );
214 #endif
215 }
216
217 int wxFileDialog::ShowModal()
218 {
219 #ifdef __WXGTK24__
220 return wxDialog::ShowModal();
221 #else
222 return wxGenericFileDialog::ShowModal();
223 #endif
224 }
225
226 bool wxFileDialog::Show( bool show )
227 {
228 #ifdef __WXGTK24__
229 return wxDialog::Show( show );
230 #else
231 return wxGenericFileDialog::Show( show );
232 #endif
233 }
234
235 void wxFileDialog::GetFilenames(wxArrayString& files) const
236 {
237 #ifdef __WXGTK24__
238 GetPaths(files);
239 for (size_t n = 0; n < files.GetCount(); n++ )
240 {
241 wxString name,ext;
242 wxSplitPath(files[n], NULL, &name, &ext);
243 if (!ext.IsEmpty())
244 {
245 name += wxT(".");
246 name += ext;
247 }
248 files[n] = name;
249 }
250 #else
251 wxGenericFileDialog::GetFilenames( files );
252 #endif
253 }
254
255 void wxFileDialog::GetPaths(wxArrayString& paths) const
256 {
257 #ifdef __WXGTK24__
258 paths.Empty();
259 if (GetWindowStyle() & wxMULTIPLE)
260 {
261 GSList *gpathsi =
262 gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(m_widget));
263 GSList *gpaths = gpathsi;
264 while (gpathsi)
265 {
266 wxString file = wxGTK_CONV_BACK((gchar*) gpathsi->data);
267 paths.Add(file);
268 g_free(gpathsi->data);
269 gpathsi = gpathsi->next;
270 }
271 if (gpaths)
272 g_slist_free(gpaths);
273 }
274 else
275 {
276 paths.Add(m_fileName);
277 }
278 #else
279 wxGenericFileDialog::GetPaths( paths );
280 #endif
281 }
282
283 void wxFileDialog::SetMessage(const wxString& message)
284 {
285 #ifdef __WXGTK24__
286 m_message = message;
287 SetTitle(message);
288 #else
289 wxGenericFileDialog::SetMessage( message );
290 #endif
291 }
292
293 void wxFileDialog::SetPath(const wxString& path)
294 {
295 #ifdef __WXGTK24__
296 if (path.empty()) return;
297
298 wxFileName fn(path);
299 m_path = fn.GetFullPath();
300 m_dir = fn.GetPath();
301 m_fileName = fn.GetFullName();
302 UpdateDialog();
303 #else
304 wxGenericFileDialog::SetPath( path );
305 #endif
306 }
307
308 void wxFileDialog::SetDirectory(const wxString& dir)
309 {
310 #ifdef __WXGTK24__
311 if (wxDirExists(dir))
312 {
313 m_dir = dir;
314 m_path = wxFileName(m_dir, m_fileName).GetFullPath();
315 UpdateDialog();
316 }
317 #else
318 wxGenericFileDialog::SetDirectory( dir );
319 #endif
320 }
321
322 void wxFileDialog::SetFilename(const wxString& name)
323 {
324 #ifdef __WXGTK24__
325 m_fileName = name;
326 m_path = wxFileName(m_dir, m_fileName).GetFullPath();
327 UpdateDialog();
328 #else
329 wxGenericFileDialog::SetFilename( name );
330 #endif
331 }
332
333 void wxFileDialog::SetWildcard(const wxString& wildCard)
334 {
335 #ifdef __WXGTK24__
336 m_wildCard = wildCard;
337
338 GtkFileChooser* chooser = GTK_FILE_CHOOSER(m_widget);
339
340 // empty current filter list:
341 GSList* ifilters = gtk_file_chooser_list_filters(chooser);
342 GSList* filters = ifilters;
343 while (ifilters)
344 {
345 gtk_file_chooser_remove_filter(chooser,GTK_FILE_FILTER(ifilters->data));
346 ifilters = ifilters->next;
347 }
348 g_slist_free(filters);
349
350 // parse filters
351 wxArrayString wildDescriptions, wildFilters;
352 if (!wxParseCommonDialogsFilter(m_wildCard, wildDescriptions, wildFilters))
353 {
354 wxFAIL_MSG( wxT("Wrong file type description") );
355 }
356 else
357 {
358 // add parsed to GtkChooser
359 for (size_t n = 0; n < wildFilters.GetCount(); n++)
360 {
361 GtkFileFilter* filter = gtk_file_filter_new();
362 gtk_file_filter_set_name(filter,wxGTK_CONV(wildDescriptions[n]));
363 wxString after = wildFilters[n];
364 do
365 {
366 wxString ext = after.BeforeFirst(wxT(';'));
367 gtk_file_filter_add_pattern(filter,wxGTK_CONV(ext));
368 if (after.Find(wxT(';')) == wxNOT_FOUND)
369 break;
370 after = after.AfterLast(wxT(';'));
371 }
372 while (!after.empty());
373
374 gtk_file_chooser_add_filter(chooser, filter);
375 }
376 }
377 #else
378 wxGenericFileDialog::SetWildcard( wildCard );
379 #endif
380 }
381
382 void wxFileDialog::SetFilterIndex(int filterIndex)
383 {
384 #ifdef __WXGTK24__
385 m_filterIndex = filterIndex;
386
387 GtkFileChooser *chooser = GTK_FILE_CHOOSER(m_widget);
388 GSList *fnode = gtk_file_chooser_list_filters(chooser);
389 GSList *filters = fnode;
390 int i = 0;
391 while (fnode)
392 {
393 if (i == filterIndex)
394 {
395 gtk_file_chooser_set_filter(chooser, GTK_FILE_FILTER(fnode->data));
396 m_filterIndex = i;
397 break;
398 }
399 i++;
400 fnode = fnode->next;
401 }
402 g_slist_free(filters);
403 #else
404 wxGenericFileDialog::SetFilterIndex( filterIndex );
405 #endif
406 }
407
408 void wxFileDialog::UpdateDialog()
409 {
410 #ifdef __WXGTK24__
411 // set currently selected directory to match the path:
412 if (!m_dir.empty() && wxDirExists(m_dir))
413 {
414 // NB: This is important -- if we set directory only and not the path,
415 // then dialog will still remember old path set using previous
416 // call to gtk_chooser_set_filename. If the previous directory
417 // was a subdirectory of the directory we want to select now,
418 // the dialog would still contain directory selector controls
419 // for the subdirectory (with the parent directory selected),
420 // instead of showing only the parent directory as expected.
421 // This way, we force GtkFileChooser to really change the
422 // directory. Finally, it doesn't have to be done if filename
423 // is not empty because of the code that sets the filename below.
424 if (m_fileName.empty())
425 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(m_widget),
426 wxGTK_CONV(m_dir));
427
428 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_widget),
429 wxGTK_CONV(m_dir));
430 }
431
432 // if the user set only the directory (e.g. by calling SetDirectory)
433 // and not the default filename, then we don't want to set the filename:
434 if (!m_fileName.empty())
435 {
436 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(m_widget),
437 wxGTK_CONV(m_path));
438
439 // pre-fill the filename when saving, too (there's no text entry
440 // control when opening a file, so it doesn't make sense to
441 // do this when opening files):
442 if (GetWindowStyle() & wxSAVE)
443 {
444 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget),
445 wxGTK_CONV(m_fileName));
446 }
447 }
448 #endif
449 }
450
451 void wxFileDialog::UpdateFromDialog()
452 {
453 #ifdef __WXGTK24__
454 // update filterIndex
455 GSList *fnode = gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(m_widget));
456 GSList *filters = fnode;
457 GtkFileFilter *current =
458 gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(m_widget));
459
460 int i = 0;
461 m_filterIndex = 0;
462 while (fnode)
463 {
464 if (fnode->data == (gpointer)current)
465 {
466 m_filterIndex = i;
467 break;
468 }
469 i++;
470 fnode = fnode->next;
471 }
472 g_slist_free(filters);
473 #endif
474 }
475
476 #endif // wxUSE_FILEDLG