]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/filectrl.cpp
Don't crash in wxWebView under OS X if custom URI is invalid.
[wxWidgets.git] / src / gtk / filectrl.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/filectrl.cpp
3 // Purpose: wxGtkFileCtrl Implementation
4 // Author: Diaa M. Sami
5 // Created: 2007-08-10
6 // RCS-ID: $Id$
7 // Copyright: (c) Diaa M. Sami
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 #include "wx/wxprec.h"
12
13 #ifdef __BORLANDC__
14 #pragma hdrstop
15 #endif
16
17 #if wxUSE_FILECTRL && !defined(__WXUNIVERSAL__)
18
19 #include "wx/filectrl.h"
20
21 #include "wx/gtk/private.h"
22 #include "wx/filename.h"
23 #include "wx/scopeguard.h"
24 #include "wx/tokenzr.h"
25
26 //-----------------------------------------------------------------------------
27 // wxGtkFileChooser implementation
28 //-----------------------------------------------------------------------------
29
30 void wxGtkFileChooser::SetWidget(GtkFileChooser *w)
31 {
32 // check arguments
33 wxASSERT( w );
34 wxASSERT( GTK_FILE_CHOOSER( w ) );
35
36 this->m_widget = w;
37 }
38
39 wxString wxGtkFileChooser::GetPath() const
40 {
41 wxGtkString str( gtk_file_chooser_get_filename( m_widget ) );
42
43 wxString string;
44 if (str)
45 string = wxString::FromUTF8(str);
46 return string;
47 }
48
49 void wxGtkFileChooser::GetFilenames( wxArrayString& files ) const
50 {
51 GetPaths( files );
52 for ( size_t n = 0; n < files.GetCount(); ++n )
53 {
54 const wxFileName file( files[n] );
55 files[n] = file.GetFullName();
56 }
57 }
58
59 void wxGtkFileChooser::GetPaths( wxArrayString& paths ) const
60 {
61 paths.Empty();
62 if ( gtk_file_chooser_get_select_multiple( m_widget ) )
63 {
64 GSList *gpathsi = gtk_file_chooser_get_filenames( m_widget );
65 GSList *gpaths = gpathsi;
66 while ( gpathsi )
67 {
68 wxString file(wxString::FromUTF8(static_cast<gchar *>(gpathsi->data)));
69 paths.Add( file );
70 g_free( gpathsi->data );
71 gpathsi = gpathsi->next;
72 }
73
74 g_slist_free( gpaths );
75 }
76 else
77 paths.Add( GetPath() );
78 }
79
80 bool wxGtkFileChooser::SetPath( const wxString& path )
81 {
82 if ( path.empty() )
83 return true;
84
85 switch ( gtk_file_chooser_get_action( m_widget ) )
86 {
87 case GTK_FILE_CHOOSER_ACTION_SAVE:
88 {
89 wxFileName fn(path);
90
91 const wxString fname = fn.GetFullName();
92 gtk_file_chooser_set_current_name( m_widget, fname.utf8_str() );
93
94 // set the initial file name and/or directory
95 const wxString dir = fn.GetPath();
96 return gtk_file_chooser_set_current_folder( m_widget,
97 dir.utf8_str() ) != 0;
98 }
99
100 case GTK_FILE_CHOOSER_ACTION_OPEN:
101 return gtk_file_chooser_set_filename( m_widget, path.utf8_str() ) != 0;
102
103 case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
104 case GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER:
105 break;
106 }
107
108 wxFAIL_MSG( "Unexpected file chooser type" );
109
110 return false;
111 }
112
113 bool wxGtkFileChooser::SetDirectory( const wxString& dir )
114 {
115 return gtk_file_chooser_set_current_folder( m_widget, dir.utf8_str() ) != 0;
116 }
117
118 wxString wxGtkFileChooser::GetDirectory() const
119 {
120 const wxGtkString str( gtk_file_chooser_get_current_folder( m_widget ) );
121 return wxString::FromUTF8(str);
122 }
123
124 wxString wxGtkFileChooser::GetFilename() const
125 {
126 return wxFileName( GetPath() ).GetFullName();
127 }
128
129 void wxGtkFileChooser::SetWildcard( const wxString& wildCard )
130 {
131 m_wildcards.Empty();
132
133 // parse filters
134 wxArrayString wildDescriptions, wildFilters;
135
136 if ( !wxParseCommonDialogsFilter( wildCard, wildDescriptions, wildFilters ) )
137 {
138 wxFAIL_MSG( wxT( "wxGtkFileChooser::SetWildcard - bad wildcard string" ) );
139 }
140 else
141 {
142 // Parsing went fine. Set m_wildCard to be returned by wxGtkFileChooserBase::GetWildcard
143 GtkFileChooser* chooser = m_widget;
144
145 // empty current filter list:
146 GSList* ifilters = gtk_file_chooser_list_filters( chooser );
147 GSList* filters = ifilters;
148
149 m_ignoreNextFilterEvent = true;
150 wxON_BLOCK_EXIT_SET(m_ignoreNextFilterEvent, false);
151
152 while ( ifilters )
153 {
154 gtk_file_chooser_remove_filter( chooser, GTK_FILE_FILTER( ifilters->data ) );
155 ifilters = ifilters->next;
156 }
157 g_slist_free( filters );
158
159 if (!wildCard.empty())
160 {
161 // add parsed to GtkChooser
162 for ( size_t n = 0; n < wildFilters.GetCount(); ++n )
163 {
164 GtkFileFilter* filter = gtk_file_filter_new();
165
166 gtk_file_filter_set_name( filter, wxGTK_CONV_SYS( wildDescriptions[n] ) );
167
168 wxStringTokenizer exttok( wildFilters[n], wxT( ";" ) );
169
170 int n1 = 1;
171 while ( exttok.HasMoreTokens() )
172 {
173 wxString token = exttok.GetNextToken();
174 gtk_file_filter_add_pattern( filter, wxGTK_CONV_SYS( token ) );
175
176 if (n1 == 1)
177 m_wildcards.Add( token ); // Only add first pattern to list, used later when saving
178 n1++;
179 }
180
181 gtk_file_chooser_add_filter( chooser, filter );
182 }
183
184 // Reset the filter index
185 SetFilterIndex( 0 );
186 }
187 }
188 }
189
190 void wxGtkFileChooser::SetFilterIndex( int filterIndex )
191 {
192 gpointer filter;
193 GtkFileChooser *chooser = m_widget;
194 GSList *filters = gtk_file_chooser_list_filters( chooser );
195
196 filter = g_slist_nth_data( filters, filterIndex );
197
198 if ( filter != NULL )
199 {
200 gtk_file_chooser_set_filter( chooser, GTK_FILE_FILTER( filter ) );
201 }
202 else
203 {
204 wxFAIL_MSG( wxT( "wxGtkFileChooser::SetFilterIndex - bad filter index" ) );
205 }
206
207 g_slist_free( filters );
208 }
209
210 int wxGtkFileChooser::GetFilterIndex() const
211 {
212 GtkFileChooser *chooser = m_widget;
213 GtkFileFilter *filter = gtk_file_chooser_get_filter( chooser );
214 GSList *filters = gtk_file_chooser_list_filters( chooser );
215 const gint index = g_slist_index( filters, filter );
216 g_slist_free( filters );
217
218 if ( index == -1 )
219 {
220 wxFAIL_MSG( wxT( "wxGtkFileChooser::GetFilterIndex - bad filter index returned by gtk+" ) );
221 return 0;
222 }
223 else
224 return index;
225 }
226
227 bool wxGtkFileChooser::HasFilterChoice() const
228 {
229 return gtk_file_chooser_get_filter( m_widget ) != NULL;
230 }
231
232 //-----------------------------------------------------------------------------
233 // end wxGtkFileChooser Implementation
234 //-----------------------------------------------------------------------------
235
236 #if wxUSE_FILECTRL
237
238 // gtk signal handlers
239
240 extern "C"
241 {
242 static void
243 gtkfilechooserwidget_file_activated_callback( GtkWidget *WXUNUSED( widget ), wxGtkFileCtrl *fileCtrl )
244 {
245 GenerateFileActivatedEvent( fileCtrl, fileCtrl );
246 }
247 }
248
249 extern "C"
250 {
251 static void
252 gtkfilechooserwidget_selection_changed_callback( GtkWidget *WXUNUSED( widget ), wxGtkFileCtrl *fileCtrl )
253 {
254 // check next selection event and ignore it if it has 0 files
255 // because such events are redundantly generated by gtk.
256 if ( fileCtrl->m_checkNextSelEvent )
257 {
258 wxArrayString filenames;
259 fileCtrl->GetFilenames( filenames );
260
261 if ( filenames.Count() != 0 )
262 fileCtrl->m_checkNextSelEvent = false;
263 }
264
265 if ( !fileCtrl->m_checkNextSelEvent )
266 GenerateSelectionChangedEvent( fileCtrl, fileCtrl );
267 }
268 }
269
270 extern "C"
271 {
272 static void
273 gtkfilechooserwidget_folder_changed_callback( GtkWidget *WXUNUSED( widget ), wxGtkFileCtrl *fileCtrl )
274 {
275 if ( fileCtrl->m_ignoreNextFolderChangeEvent )
276 {
277 fileCtrl->m_ignoreNextFolderChangeEvent = false;
278 }
279 else
280 {
281 GenerateFolderChangedEvent( fileCtrl, fileCtrl );
282 }
283
284 fileCtrl->m_checkNextSelEvent = true;
285 }
286 }
287
288 extern "C"
289 {
290 static void
291 gtkfilechooserwidget_notify_callback( GObject *WXUNUSED( gobject ), GParamSpec *arg1, wxGtkFileCtrl *fileCtrl )
292 {
293 const char *name = g_param_spec_get_name (arg1);
294 if ( strcmp( name, "filter" ) == 0 &&
295 fileCtrl->HasFilterChoice() &&
296 !fileCtrl->GTKShouldIgnoreNextFilterEvent() )
297 {
298 GenerateFilterChangedEvent( fileCtrl, fileCtrl );
299 }
300 }
301 }
302
303 // wxGtkFileCtrl implementation
304
305 IMPLEMENT_DYNAMIC_CLASS( wxGtkFileCtrl, wxControl )
306
307 wxGtkFileCtrl::~wxGtkFileCtrl()
308 {
309 if (m_fcWidget)
310 GTKDisconnect(m_fcWidget);
311 }
312
313 void wxGtkFileCtrl::Init()
314 {
315 m_checkNextSelEvent = false;
316
317 // ignore the first folder change event which is fired upon startup.
318 m_ignoreNextFolderChangeEvent = true;
319 }
320
321 bool wxGtkFileCtrl::Create( wxWindow *parent,
322 wxWindowID id,
323 const wxString& defaultDirectory,
324 const wxString& defaultFileName,
325 const wxString& wildCard,
326 long style,
327 const wxPoint& pos,
328 const wxSize& size,
329 const wxString& name )
330 {
331 if ( !PreCreation( parent, pos, size ) ||
332 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ) )
333 {
334 wxFAIL_MSG( wxT( "wxGtkFileCtrl creation failed" ) );
335 return false;
336 }
337
338 GtkFileChooserAction gtkAction = GTK_FILE_CHOOSER_ACTION_OPEN;
339
340 if ( style & wxFC_SAVE )
341 gtkAction = GTK_FILE_CHOOSER_ACTION_SAVE;
342
343 m_widget = gtk_alignment_new ( 0, 0, 1, 1 );
344 g_object_ref(m_widget);
345 m_fcWidget = GTK_FILE_CHOOSER( gtk_file_chooser_widget_new(gtkAction) );
346 gtk_widget_show ( GTK_WIDGET( m_fcWidget ) );
347 gtk_container_add ( GTK_CONTAINER ( m_widget ), GTK_WIDGET( m_fcWidget ) );
348
349 m_focusWidget = GTK_WIDGET( m_fcWidget );
350
351 g_signal_connect ( m_fcWidget, "file-activated",
352 G_CALLBACK ( gtkfilechooserwidget_file_activated_callback ),
353 this );
354
355 g_signal_connect ( m_fcWidget, "current-folder-changed",
356 G_CALLBACK ( gtkfilechooserwidget_folder_changed_callback ),
357 this );
358
359 g_signal_connect ( m_fcWidget, "selection-changed",
360 G_CALLBACK ( gtkfilechooserwidget_selection_changed_callback ),
361 this );
362
363 g_signal_connect ( m_fcWidget, "notify",
364 G_CALLBACK ( gtkfilechooserwidget_notify_callback ),
365 this );
366
367 m_fc.SetWidget( m_fcWidget );
368
369 if ( style & wxFC_MULTIPLE )
370 gtk_file_chooser_set_select_multiple( m_fcWidget, true );
371
372 SetWildcard( wildCard );
373
374 // if defaultDir is specified it should contain the directory and
375 // defaultFileName should contain the default name of the file, however if
376 // directory is not given, defaultFileName contains both
377 wxFileName fn;
378 if ( defaultDirectory.empty() )
379 fn.Assign( defaultFileName );
380 else if ( !defaultFileName.empty() )
381 fn.Assign( defaultDirectory, defaultFileName );
382 else
383 fn.AssignDir( defaultDirectory );
384
385 // set the initial file name and/or directory
386 const wxString dir = fn.GetPath();
387 if ( !dir.empty() )
388 {
389 gtk_file_chooser_set_current_folder( m_fcWidget,
390 wxGTK_CONV_FN(dir) );
391 }
392
393 const wxString fname = fn.GetFullName();
394 if ( style & wxFC_SAVE )
395 {
396 if ( !fname.empty() )
397 {
398 gtk_file_chooser_set_current_name( m_fcWidget,
399 wxGTK_CONV_FN(fname) );
400 }
401 }
402 else // wxFC_OPEN
403 {
404 if ( !fname.empty() )
405 {
406 gtk_file_chooser_set_filename( m_fcWidget,
407 wxGTK_CONV_FN(fn.GetFullPath()) );
408 }
409 }
410
411 m_parent->DoAddChild( this );
412
413 PostCreation( size );
414
415 return TRUE;
416 }
417
418 bool wxGtkFileCtrl::SetPath( const wxString& path )
419 {
420 return m_fc.SetPath( path );
421 }
422
423 bool wxGtkFileCtrl::SetDirectory( const wxString& dir )
424 {
425 return m_fc.SetDirectory( dir );
426 }
427
428 bool wxGtkFileCtrl::SetFilename( const wxString& name )
429 {
430 if ( HasFlag( wxFC_SAVE ) )
431 {
432 gtk_file_chooser_set_current_name( m_fcWidget, wxGTK_CONV( name ) );
433 return true;
434 }
435 else
436 return SetPath( wxFileName( GetDirectory(), name ).GetFullPath() );
437 }
438
439 void wxGtkFileCtrl::SetWildcard( const wxString& wildCard )
440 {
441 m_wildCard = wildCard;
442
443 m_fc.SetWildcard( wildCard );
444 }
445
446 void wxGtkFileCtrl::SetFilterIndex( int filterIndex )
447 {
448 m_fc.SetFilterIndex( filterIndex );
449 }
450
451 wxString wxGtkFileCtrl::GetPath() const
452 {
453 return m_fc.GetPath();
454 }
455
456 void wxGtkFileCtrl::GetPaths( wxArrayString& paths ) const
457 {
458 m_fc.GetPaths( paths );
459 }
460
461 wxString wxGtkFileCtrl::GetDirectory() const
462 {
463 return m_fc.GetDirectory();
464 }
465
466 wxString wxGtkFileCtrl::GetFilename() const
467 {
468 return m_fc.GetFilename();
469 }
470
471 void wxGtkFileCtrl::GetFilenames( wxArrayString& files ) const
472 {
473 m_fc.GetFilenames( files );
474 }
475
476 void wxGtkFileCtrl::ShowHidden(bool show)
477 {
478 gtk_file_chooser_set_show_hidden(m_fcWidget, show);
479 }
480
481 #endif // wxUSE_FILECTRL
482
483 #endif // wxUSE_FILECTRL && !defined(__WXUNIVERSAL__)