]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/filectrl.cpp
revert nested event loop support for wxGTK1 because it causes applications hangs
[wxWidgets.git] / src / gtk / filectrl.cpp
CommitLineData
0cf3e587
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/gtk/filectrl.cpp
3// Purpose: wxGtkFileCtrl Implementation
4// Author: Diaa M. Sami
5// Created: 2007-08-10
0cf3e587
VZ
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
a82b0593 16#if wxUSE_FILECTRL && !defined(__WXUNIVERSAL__)
cc681534 17
89e5d5bb 18#include "wx/filectrl.h"
0cf3e587
VZ
19
20#include "wx/gtk/private.h"
0cf3e587 21#include "wx/filename.h"
6305f044 22#include "wx/scopeguard.h"
0cf3e587
VZ
23#include "wx/tokenzr.h"
24
25//-----------------------------------------------------------------------------
26// wxGtkFileChooser implementation
27//-----------------------------------------------------------------------------
28
29void 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
38wxString wxGtkFileChooser::GetPath() const
39{
40 wxGtkString str( gtk_file_chooser_get_filename( m_widget ) );
41
260020e3 42 wxString string;
f069ac48 43 if (str)
b74d7c85 44 string = wxString::FromUTF8(str);
260020e3 45 return string;
0cf3e587
VZ
46}
47
48void 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
58void 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 {
b74d7c85 67 wxString file(wxString::FromUTF8(static_cast<gchar *>(gpathsi->data)));
0cf3e587
VZ
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
79bool wxGtkFileChooser::SetPath( const wxString& path )
80{
b74d7c85
VZ
81 if ( path.empty() )
82 return true;
0cf3e587 83
9618496b
VZ
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;
0cf3e587
VZ
110}
111
112bool wxGtkFileChooser::SetDirectory( const wxString& dir )
113{
b74d7c85 114 return gtk_file_chooser_set_current_folder( m_widget, dir.utf8_str() ) != 0;
0cf3e587
VZ
115}
116
117wxString wxGtkFileChooser::GetDirectory() const
118{
119 const wxGtkString str( gtk_file_chooser_get_current_folder( m_widget ) );
b74d7c85 120 return wxString::FromUTF8(str);
0cf3e587
VZ
121}
122
123wxString wxGtkFileChooser::GetFilename() const
124{
125 return wxFileName( GetPath() ).GetFullName();
126}
127
128void wxGtkFileChooser::SetWildcard( const wxString& wildCard )
129{
20380343
RR
130 m_wildcards.Empty();
131
0cf3e587
VZ
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
6305f044
VZ
148 m_ignoreNextFilterEvent = true;
149 wxON_BLOCK_EXIT_SET(m_ignoreNextFilterEvent, false);
150
0cf3e587
VZ
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( ";" ) );
03647350 168
81d6a507 169 int n1 = 1;
0cf3e587
VZ
170 while ( exttok.HasMoreTokens() )
171 {
172 wxString token = exttok.GetNextToken();
173 gtk_file_filter_add_pattern( filter, wxGTK_CONV_SYS( token ) );
03647350 174
81d6a507 175 if (n1 == 1)
20380343 176 m_wildcards.Add( token ); // Only add first pattern to list, used later when saving
81d6a507 177 n1++;
0cf3e587
VZ
178 }
179
180 gtk_file_chooser_add_filter( chooser, filter );
181 }
182
183 // Reset the filter index
184 SetFilterIndex( 0 );
185 }
186 }
187}
188
189void 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
209int 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;
74ab5f5b 224}
0cf3e587 225
6305f044
VZ
226bool wxGtkFileChooser::HasFilterChoice() const
227{
228 return gtk_file_chooser_get_filter( m_widget ) != NULL;
229}
230
0cf3e587
VZ
231//-----------------------------------------------------------------------------
232// end wxGtkFileChooser Implementation
233//-----------------------------------------------------------------------------
234
235#if wxUSE_FILECTRL
236
237// gtk signal handlers
238
239extern "C"
240{
241 static void
242 gtkfilechooserwidget_file_activated_callback( GtkWidget *WXUNUSED( widget ), wxGtkFileCtrl *fileCtrl )
243 {
244 GenerateFileActivatedEvent( fileCtrl, fileCtrl );
245 }
246}
247
248extern "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
269extern "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
6305f044
VZ
287extern "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
0cf3e587
VZ
302// wxGtkFileCtrl implementation
303
304IMPLEMENT_DYNAMIC_CLASS( wxGtkFileCtrl, wxControl )
305
8ab75332
PC
306wxGtkFileCtrl::~wxGtkFileCtrl()
307{
308 if (m_fcWidget)
309 GTKDisconnect(m_fcWidget);
310}
311
0cf3e587
VZ
312void wxGtkFileCtrl::Init()
313{
0cf3e587
VZ
314 m_checkNextSelEvent = false;
315
316 // ignore the first folder change event which is fired upon startup.
317 m_ignoreNextFolderChangeEvent = true;
318}
319
320bool 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
260020e3 337 GtkFileChooserAction gtkAction = GTK_FILE_CHOOSER_ACTION_OPEN;
0cf3e587
VZ
338
339 if ( style & wxFC_SAVE )
0cf3e587 340 gtkAction = GTK_FILE_CHOOSER_ACTION_SAVE;
0cf3e587
VZ
341
342 m_widget = gtk_alignment_new ( 0, 0, 1, 1 );
9ff9d30c 343 g_object_ref(m_widget);
260020e3 344 m_fcWidget = GTK_FILE_CHOOSER( gtk_file_chooser_widget_new(gtkAction) );
0cf3e587
VZ
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
6305f044
VZ
362 g_signal_connect ( m_fcWidget, "notify",
363 G_CALLBACK ( gtkfilechooserwidget_notify_callback ),
364 this );
365
0cf3e587
VZ
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,
c282e47d 389 wxGTK_CONV_FN(dir) );
0cf3e587
VZ
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,
c282e47d 398 wxGTK_CONV_FN(fname) );
0cf3e587
VZ
399 }
400 }
401 else // wxFC_OPEN
402 {
403 if ( !fname.empty() )
404 {
405 gtk_file_chooser_set_filename( m_fcWidget,
c282e47d 406 wxGTK_CONV_FN(fn.GetFullPath()) );
0cf3e587
VZ
407 }
408 }
409
410 m_parent->DoAddChild( this );
411
412 PostCreation( size );
413
414 return TRUE;
415}
416
417bool wxGtkFileCtrl::SetPath( const wxString& path )
418{
419 return m_fc.SetPath( path );
420}
421
422bool wxGtkFileCtrl::SetDirectory( const wxString& dir )
423{
424 return m_fc.SetDirectory( dir );
425}
426
427bool wxGtkFileCtrl::SetFilename( const wxString& name )
428{
700d08c1 429 if ( HasFlag( wxFC_SAVE ) )
0cf3e587 430 {
700d08c1
RR
431 gtk_file_chooser_set_current_name( m_fcWidget, wxGTK_CONV( name ) );
432 return true;
0cf3e587 433 }
700d08c1
RR
434 else
435 return SetPath( wxFileName( GetDirectory(), name ).GetFullPath() );
0cf3e587
VZ
436}
437
438void wxGtkFileCtrl::SetWildcard( const wxString& wildCard )
439{
440 m_wildCard = wildCard;
441
442 m_fc.SetWildcard( wildCard );
443}
444
445void wxGtkFileCtrl::SetFilterIndex( int filterIndex )
446{
447 m_fc.SetFilterIndex( filterIndex );
448}
449
450wxString wxGtkFileCtrl::GetPath() const
451{
452 return m_fc.GetPath();
453}
454
455void wxGtkFileCtrl::GetPaths( wxArrayString& paths ) const
456{
457 m_fc.GetPaths( paths );
458}
459
460wxString wxGtkFileCtrl::GetDirectory() const
461{
462 return m_fc.GetDirectory();
463}
464
465wxString wxGtkFileCtrl::GetFilename() const
466{
467 return m_fc.GetFilename();
468}
469
470void wxGtkFileCtrl::GetFilenames( wxArrayString& files ) const
471{
472 m_fc.GetFilenames( files );
473}
474
260020e3 475void wxGtkFileCtrl::ShowHidden(bool show)
0cf3e587 476{
89e5d5bb 477 gtk_file_chooser_set_show_hidden(m_fcWidget, show);
0cf3e587
VZ
478}
479
ff654490 480#endif // wxUSE_FILECTRL
cc681534 481
a82b0593 482#endif // wxUSE_FILECTRL && !defined(__WXUNIVERSAL__)