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