]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/filedlg.cpp
Prevent GDK assertions when a window has a hidden (never shown) parent -- do not...
[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)
c801d85f
KB
11#pragma implementation "filedlg.h"
12#endif
13
14f355c2
VS
14// For compilers that support precompilation, includes "wx.h".
15#include "wx/wxprec.h"
16
9755e73b
VS
17#if wxUSE_FILEDLG && defined(__WXGTK24__)
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>
9755e73b 26#include "wx/gtk/private.h"
83624f79 27
acfd422a
RR
28//-----------------------------------------------------------------------------
29// idle system
30//-----------------------------------------------------------------------------
31
32extern void wxapp_install_idle_handler();
33extern bool g_isIdle;
34
291a8f20
RR
35//-----------------------------------------------------------------------------
36// "clicked" for OK-button
c801d85f
KB
37//-----------------------------------------------------------------------------
38
9755e73b 39static void gtk_filedialog_ok_callback(GtkWidget *widget, wxFileDialog *dialog)
c801d85f 40{
2748d251 41 int style = dialog->GetStyle();
9755e73b
VS
42 gchar* text = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
43 wxString filename(wxGTK_CONV_BACK(text));
035b704a 44
9755e73b 45 if ((style & wxSAVE) && (style & wxOVERWRITE_PROMPT))
bfc6fde4 46 {
9755e73b 47 if (wxFileExists(filename))
0e1399b3
VZ
48 {
49 wxString msg;
9755e73b
VS
50 msg.Printf(
51 _("File '%s' already exists, do you really want to overwrite it?"),
52 filename.c_str());
0e1399b3 53
9755e73b
VS
54 wxMessageDialog dlg(dialog, msg, _("Confirm"),
55 wxYES_NO | wxICON_QUESTION);
56 if (dlg.ShowModal() != wxID_YES)
0e1399b3
VZ
57 return;
58 }
83624f79 59 }
9755e73b 60 else if ((style & wxOPEN) && ( style & wxFILE_MUST_EXIST))
bfc6fde4 61 {
9755e73b 62 if (!wxFileExists( filename ))
bfc6fde4 63 {
9755e73b
VS
64 wxMessageDialog dlg(dialog,
65 _("Please choose an existing file."),
66 _("Error"), wxOK | wxICON_ERROR);
67 dlg.ShowModal();
bfc6fde4
VZ
68
69 return;
70 }
71 }
035b704a 72
3f6638b8 73 // change to the directory where the user went if asked
9755e73b 74 if (style & wxCHANGE_DIR)
3f6638b8
VZ
75 {
76 wxString cwd;
77 wxSplitPath(filename, &cwd, NULL, NULL);
78
9755e73b 79 if (cwd != wxGetCwd())
3f6638b8
VZ
80 {
81 wxSetWorkingDirectory(cwd);
82 }
83 }
84
76840ed0 85 dialog->SetPath(filename);
9755e73b
VS
86 dialog->UpdateFromDialog();
87
bfc6fde4 88 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK);
9755e73b
VS
89 event.SetEventObject(dialog);
90 dialog->GetEventHandler()->ProcessEvent(event);
ff7b1510 91}
c801d85f 92
291a8f20
RR
93//-----------------------------------------------------------------------------
94// "clicked" for Cancel-button
95//-----------------------------------------------------------------------------
96
9755e73b
VS
97static void gtk_filedialog_cancel_callback(GtkWidget *WXUNUSED(w),
98 wxFileDialog *dialog)
c801d85f 99{
bfc6fde4 100 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
9755e73b
VS
101 event.SetEventObject(dialog);
102 dialog->GetEventHandler()->ProcessEvent(event);
103}
104
105static void gtk_filedialog_response_callback(GtkWidget *w,
106 int response,
107 wxFileDialog *dialog)
108{
109 wxapp_install_idle_handler();
110
a7334928 111 if (response == GTK_RESPONSE_ACCEPT)
9755e73b 112 gtk_filedialog_ok_callback(w, dialog);
c2740a5a
RR
113 else if (response == GTK_RESPONSE_CANCEL)
114 gtk_filedialog_cancel_callback(w, dialog);
115 else // "delete"
116 {
a7334928 117 gtk_filedialog_cancel_callback(w, dialog);
c2740a5a
RR
118 dialog->m_destroyed_by_delete = TRUE;
119 }
ff7b1510 120}
c801d85f 121
291a8f20
RR
122//-----------------------------------------------------------------------------
123// wxFileDialog
124//-----------------------------------------------------------------------------
125
f74172ab 126IMPLEMENT_DYNAMIC_CLASS(wxFileDialog,wxFileDialogBase)
c801d85f 127
9755e73b
VS
128wxFileDialog::wxFileDialog(wxWindow *parent, const wxString& message,
129 const wxString& defaultDir,
130 const wxString& defaultFileName,
131 const wxString& wildCard,
132 long style, const wxPoint& pos)
133 : wxFileDialogBase(parent, message, defaultDir, defaultFileName,
134 wildCard, style, pos)
c801d85f 135{
83624f79 136 m_needParent = FALSE;
c2740a5a 137 m_destroyed_by_delete = FALSE;
83624f79 138
9755e73b
VS
139 if (!PreCreation(parent, pos, wxDefaultSize) ||
140 !CreateBase(parent, wxID_ANY, pos, wxDefaultSize, style,
141 wxDefaultValidator, wxT("filedialog")))
4dcaf11a 142 {
9755e73b 143 wxFAIL_MSG( wxT("wxFileDialog creation failed") );
3f6638b8 144 return;
4dcaf11a 145 }
3f6638b8 146
9755e73b
VS
147 bool multiple = (style & wxMULTIPLE) == wxMULTIPLE;
148 GtkFileChooserAction gtk_action;
149 GtkWindow* gtk_parent = NULL;
150 if (parent)
151 gtk_parent = GTK_WINDOW(parent->m_widget);
152
153 gchar* ok_btn_stock;
154 if ((style & wxSAVE) == wxSAVE)
155 {
156 gtk_action = GTK_FILE_CHOOSER_ACTION_SAVE;
157 ok_btn_stock = GTK_STOCK_SAVE;
158 }
159 else
160 {
161 gtk_action = GTK_FILE_CHOOSER_ACTION_OPEN;
162 ok_btn_stock = GTK_STOCK_OPEN;
163 }
164 m_widget = gtk_file_chooser_dialog_new(
165 wxGTK_CONV(m_message),
166 gtk_parent,
167 gtk_action,
168 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
169 ok_btn_stock, GTK_RESPONSE_ACCEPT,
170 NULL);
171
172 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(m_widget), multiple);
173
174 gtk_signal_connect(GTK_OBJECT(m_widget),
175 "response",
176 GTK_SIGNAL_FUNC(gtk_filedialog_response_callback),
177 (gpointer*)this);
178
179 m_path = m_dir;
180 if (!m_path.empty() && m_path.Last() != wxT('/'))
181 m_path += wxT('/');
182 m_path += m_fileName;
183 SetPath(m_path);
184
185 SetWildcard(wildCard);
186 SetFilterIndex(0);
187}
0e1399b3 188
76840ed0 189wxFileDialog::~wxFileDialog()
9755e73b 190{
c2740a5a
RR
191 if (m_destroyed_by_delete)
192 m_widget = NULL;
9755e73b 193}
0e1399b3 194
9755e73b
VS
195void wxFileDialog::GetFilenames(wxArrayString& files) const
196{
197 GetPaths(files);
198 for (size_t n = 0; n < files.GetCount(); n++ )
199 {
200 wxString name,ext;
201 wxSplitPath(files[n], NULL, &name, &ext);
202 if (!ext.IsEmpty())
203 {
204 name += wxT(".");
205 name += ext;
206 }
207 files[n] = name;
208 }
209}
76840ed0 210
9755e73b
VS
211void wxFileDialog::GetPaths(wxArrayString& paths) const
212{
213 paths.Empty();
214 if (GetWindowStyle() & wxMULTIPLE)
215 {
216 GSList *gpathsi =
217 gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(m_widget));
218 GSList *gpaths = gpathsi;
219 while (gpathsi)
220 {
221 wxString file = wxGTK_CONV_BACK((gchar*) gpathsi->data);
222 paths.Add(file);
223 g_free(gpathsi->data);
224 gpathsi = gpathsi->next;
225 }
226 if (gpaths)
227 g_slist_free(gpaths);
228 }
229 else
230 {
231 paths.Add(m_fileName);
232 }
233}
035b704a 234
9755e73b
VS
235void wxFileDialog::SetMessage(const wxString& message)
236{
237 m_message = message;
238 SetTitle(message);
239}
240
76840ed0
RR
241void wxFileDialog::SetPath(const wxString& path)
242{
243 if (path.empty()) return;
244
245 wxFileName fn(path);
246 m_path = fn.GetFullPath();
c0192099
VS
247 m_dir = fn.GetPath();
248 m_fileName = fn.GetFullName();
6120f2fc 249 UpdateDialog();
76840ed0
RR
250}
251
9755e73b
VS
252void wxFileDialog::SetDirectory(const wxString& dir)
253{
76840ed0
RR
254 if (wxDirExists(dir))
255 {
256 m_dir = dir;
6120f2fc
VS
257 m_path = wxFileName(m_dir, m_fileName).GetFullPath();
258 UpdateDialog();
76840ed0 259 }
9755e73b
VS
260}
261
262void wxFileDialog::SetFilename(const wxString& name)
263{
264 m_fileName = name;
6120f2fc
VS
265 m_path = wxFileName(m_dir, m_fileName).GetFullPath();
266 UpdateDialog();
267}
76840ed0 268
6120f2fc
VS
269void wxFileDialog::UpdateDialog()
270{
271 // set currently selected directory to match the path:
272 if (!m_dir.empty() && wxDirExists(m_dir))
76840ed0 273 {
6120f2fc
VS
274 // NB: This is important -- if we set directory only and not the path,
275 // then dialog will still remember old path set using previous
276 // call to gtk_chooser_set_filename. If the previous directory
277 // was a subdirectory of the directory we want to select now,
278 // the dialog would still contain directory selector controls
279 // for the subdirectory (with the parent directory selected),
280 // instead of showing only the parent directory as expected.
281 // This way, we force GtkFileChooser to really change the
282 // directory. Finally, it doesn't have to be done if filename
283 // is not empty because of the code that sets the filename below.
284 if (m_fileName.empty())
285 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(m_widget),
286 wxGTK_CONV(m_dir));
287
288 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(m_widget),
289 wxGTK_CONV(m_dir));
290 }
291
292 // if the user set only the directory (e.g. by calling SetDirectory)
293 // and not the default filename, then we don't want to set the filename:
294 if (!m_fileName.empty())
295 {
296 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(m_widget),
297 wxGTK_CONV(m_path));
298
299 // pre-fill the filename when saving, too (there's no text entry
300 // control when opening a file, so it doesn't make sense to
301 // do this when opening files):
302 if (GetWindowStyle() & wxSAVE)
303 {
304 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget),
76840ed0 305 wxGTK_CONV(m_fileName));
6120f2fc 306 }
76840ed0 307 }
9755e73b 308}
035b704a 309
9755e73b
VS
310void wxFileDialog::SetWildcard(const wxString& wildCard)
311{
312 m_wildCard = wildCard;
313
314 GtkFileChooser* chooser = GTK_FILE_CHOOSER(m_widget);
315
316 // empty current filter list:
317 GSList* ifilters = gtk_file_chooser_list_filters(chooser);
318 GSList* filters = ifilters;
319 while (ifilters)
320 {
321 gtk_file_chooser_remove_filter(chooser,GTK_FILE_FILTER(ifilters->data));
322 ifilters = ifilters->next;
323 }
324 g_slist_free(filters);
325
326 // parse filters
327 wxArrayString wildDescriptions, wildFilters;
328 if (!wxParseCommonDialogsFilter(m_wildCard, wildDescriptions, wildFilters))
329 {
330 wxFAIL_MSG( wxT("Wrong file type description") );
331 }
332 else
333 {
334 // add parsed to GtkChooser
335 for (size_t n = 0; n < wildFilters.GetCount(); n++)
336 {
337 GtkFileFilter* filter = gtk_file_filter_new();
338 gtk_file_filter_set_name(filter,wxGTK_CONV(wildDescriptions[n]));
339 wxString after = wildFilters[n];
340 do
341 {
342 wxString ext = after.BeforeFirst(wxT(';'));
343 gtk_file_filter_add_pattern(filter,wxGTK_CONV(ext));
344 if (after.Find(wxT(';')) == wxNOT_FOUND)
345 break;
346 after = after.AfterLast(wxT(';'));
347 }
348 while (!after.empty());
349
350 gtk_file_chooser_add_filter(chooser, filter);
351 }
352 }
353}
a3622daa 354
9755e73b
VS
355void wxFileDialog::SetFilterIndex(int filterIndex)
356{
357 m_filterIndex = filterIndex;
c801d85f 358
9755e73b
VS
359 GtkFileChooser *chooser = GTK_FILE_CHOOSER(m_widget);
360 GSList *fnode = gtk_file_chooser_list_filters(chooser);
361 GSList *filters = fnode;
362 int i = 0;
363 while (fnode)
364 {
365 if (i == filterIndex)
366 {
367 gtk_file_chooser_set_filter(chooser, GTK_FILE_FILTER(fnode->data));
368 m_filterIndex = i;
369 break;
370 }
371 i++;
372 fnode = fnode->next;
373 }
374 g_slist_free(filters);
375}
3502e687 376
9755e73b
VS
377void wxFileDialog::UpdateFromDialog()
378{
379 // update filterIndex
380 GSList *fnode = gtk_file_chooser_list_filters(GTK_FILE_CHOOSER(m_widget));
381 GSList *filters = fnode;
382 GtkFileFilter *current =
383 gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(m_widget));
384
385 int i = 0;
386 m_filterIndex = 0;
387 while (fnode)
388 {
389 if (fnode->data == (gpointer)current)
390 {
391 m_filterIndex = i;
392 break;
393 }
394 i++;
395 fnode = fnode->next;
396 }
397 g_slist_free(filters);
398}
3f6638b8 399
9755e73b 400#endif // wxUSE_FILEDLG && defined(__WXGTK24__)