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