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