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