xref: /trunk/main/fpicker/source/unx/gnome/SalGtkFilePicker.cxx (revision 3a7cf181c55416e69e525ddc0b38c22235ec1569)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_fpicker.hxx"
30 
31 //------------------------------------------------------------------------
32 // includes
33 //------------------------------------------------------------------------
34 #include <com/sun/star/lang/DisposedException.hpp>
35 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
36 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
37 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
38 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
39 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
40 #include <cppuhelper/interfacecontainer.h>
41 #include <osl/diagnose.h>
42 #include <osl/process.h>
43 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
44 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
45 #include <com/sun/star/uno/Any.hxx>
46 #include <FPServiceInfo.hxx>
47 #include <vos/mutex.hxx>
48 #include <vcl/svapp.hxx>
49 #include <SalGtkFilePicker.hxx>
50 
51 #include <tools/urlobj.hxx>
52 
53 #include <iostream>
54 #include <algorithm>
55 #include <set>
56 #include "resourceprovider.hxx"
57 #ifndef _SV_RC_H
58 #include <tools/rc.hxx>
59 #endif
60 
61 //------------------------------------------------------------------------
62 // namespace directives
63 //------------------------------------------------------------------------
64 
65 using namespace ::com::sun::star;
66 using namespace ::com::sun::star::ui::dialogs;
67 using namespace ::com::sun::star::ui::dialogs::TemplateDescription;
68 using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds;
69 using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds;
70 using namespace ::com::sun::star::lang;
71 using namespace ::com::sun::star::beans;
72 using namespace ::com::sun::star::uno;
73 
74 //------------------------------------------------------------------------
75 // helper functions
76 //------------------------------------------------------------------------
77 
78 namespace
79 {
80     // controling event notifications
81     const bool STARTUP_SUSPENDED = true;
82     const bool STARTUP_ALIVE     = false;
83 
84     uno::Sequence<rtl::OUString> SAL_CALL FilePicker_getSupportedServiceNames()
85     {
86         uno::Sequence<rtl::OUString> aRet(3);
87             aRet[0] = rtl::OUString::createFromAscii( "com.sun.star.ui.dialogs.FilePicker" );
88         aRet[1] = rtl::OUString::createFromAscii( "com.sun.star.ui.dialogs.SystemFilePicker" );
89         aRet[2] = rtl::OUString::createFromAscii( "com.sun.star.ui.dialogs.GtkFilePicker" );
90         return aRet;
91     }
92 }
93 
94 //-----------------------------------------------------------------------------------------
95 // constructor
96 //-----------------------------------------------------------------------------------------
97 
98 static void expandexpanders(GtkContainer *pWidget)
99 {
100     GdkThreadLock aLock;
101 
102     GList *pChildren = gtk_container_get_children(pWidget);
103     for( GList *p = pChildren; p; p = p->next )
104     {
105         if GTK_IS_CONTAINER(GTK_WIDGET(p->data))
106             expandexpanders(GTK_CONTAINER(GTK_WIDGET(p->data)));
107         if GTK_IS_EXPANDER(GTK_WIDGET(p->data))
108             gtk_expander_set_expanded(GTK_EXPANDER(GTK_WIDGET(p->data)), sal_True);
109     }
110     g_list_free(pChildren);
111 }
112 
113 void SalGtkFilePicker::dialog_mapped_cb(GtkWidget *, SalGtkFilePicker *pobjFP)
114 {
115     pobjFP->InitialMapping();
116 }
117 
118 void SalGtkFilePicker::InitialMapping()
119 {
120     GdkThreadLock aLock;
121 
122     if (!mbPreviewState )
123     {
124         gtk_widget_hide( m_pPreview );
125         gtk_file_chooser_set_preview_widget_active( GTK_FILE_CHOOSER( m_pDialog ), false);
126     }
127     gtk_widget_set_size_request (m_pPreview, -1, -1);
128 }
129 
130 SalGtkFilePicker::SalGtkFilePicker( const uno::Reference<lang::XMultiServiceFactory>& xServiceMgr ) :
131     SalGtkPicker(xServiceMgr),
132     cppu::WeakComponentImplHelper10<
133         XFilterManager,
134             XFilterGroupManager,
135             XFilePickerControlAccess,
136         XFilePickerNotifier,
137             XFilePreview,
138             XFilePicker2,
139         lang::XInitialization,
140         util::XCancellable,
141         lang::XEventListener,
142         lang::XServiceInfo>( m_rbHelperMtx ),
143     m_xServiceMgr( xServiceMgr ),
144     m_pFilterList( NULL ),
145     m_pVBox ( NULL ),
146     mnHID_FolderChange( 0 ),
147     mnHID_SelectionChange( 0 ),
148     bVersionWidthUnset( false ),
149     mbPreviewState( sal_False ),
150     mHID_Preview( 0 ),
151     m_pPreview( NULL ),
152     m_pPseudoFilter( NULL ),
153     m_PreviewImageWidth( 256 ),
154     m_PreviewImageHeight( 256 )
155 {
156     int i;
157 
158     for( i = 0; i < TOGGLE_LAST; i++ )
159     {
160         m_pToggles[i] = NULL;
161         mbToggleVisibility[i] = false;
162     }
163 
164     for( i = 0; i < BUTTON_LAST; i++ )
165     {
166         m_pButtons[i] = NULL;
167         mbButtonVisibility[i] = false;
168     }
169 
170     for( i = 0; i < LIST_LAST; i++ )
171     {
172         m_pHBoxs[i] = NULL;
173         m_pAligns[i] = NULL;
174         m_pLists[i] = NULL;
175         m_pListLabels[i] = NULL;
176         mbListVisibility[i] = false;
177     }
178 
179     CResourceProvider aResProvider;
180     OUString aFilePickerTitle = aResProvider.getResString( FILE_PICKER_TITLE_OPEN );
181 
182     GdkThreadLock aLock;
183 
184     m_pDialog = gtk_file_chooser_dialog_new(
185             OUStringToOString( aFilePickerTitle, RTL_TEXTENCODING_UTF8 ).getStr(),
186             NULL,
187             GTK_FILE_CHOOSER_ACTION_OPEN,
188             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
189             GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
190             (char *)NULL );
191 
192     gtk_dialog_set_default_response( GTK_DIALOG (m_pDialog), GTK_RESPONSE_ACCEPT );
193 
194     gtk_file_chooser_set_local_only( GTK_FILE_CHOOSER( m_pDialog ), sal_False );
195     gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER( m_pDialog ), sal_False );
196 
197     m_pVBox = gtk_vbox_new( sal_False, 0 );
198 
199     // We don't want clickable items to have a huge hit-area
200     GtkWidget *pHBox = gtk_hbox_new( sal_False, 0 );
201     GtkWidget *pThinVBox = gtk_vbox_new( sal_False, 0 );
202 
203     gtk_box_pack_end (GTK_BOX( m_pVBox ), pHBox, sal_False, sal_False, 0);
204     gtk_box_pack_start (GTK_BOX( pHBox ), pThinVBox, sal_False, sal_False, 0);
205     gtk_widget_show( pHBox );
206     gtk_widget_show( pThinVBox );
207 
208     OUString aLabel;
209 
210     for( i = 0; i < TOGGLE_LAST; i++ )
211     {
212         m_pToggles[i] = gtk_check_button_new();
213 
214 #define LABEL_TOGGLE( elem ) \
215         case elem : \
216             aLabel = aResProvider.getResString( CHECKBOX_##elem ); \
217             setLabel( CHECKBOX_##elem, aLabel ); \
218             break
219 
220         switch( i ) {
221 
222         LABEL_TOGGLE( AUTOEXTENSION );
223         LABEL_TOGGLE( PASSWORD );
224         LABEL_TOGGLE( FILTEROPTIONS );
225         LABEL_TOGGLE( READONLY );
226         LABEL_TOGGLE( LINK );
227         LABEL_TOGGLE( PREVIEW );
228         LABEL_TOGGLE( SELECTION );
229             default:
230                 OSL_TRACE("Handle unknown control %d\n", i);
231                 break;
232         }
233 
234         gtk_box_pack_end( GTK_BOX( pThinVBox ), m_pToggles[i], sal_False, sal_False, 0 );
235     }
236 
237     for( i = 0; i < LIST_LAST; i++ )
238     {
239         m_pHBoxs[i] = gtk_hbox_new( sal_False, 0 );
240 
241         m_pAligns[i] = gtk_alignment_new(0, 0, 0, 1);
242 
243         m_pLists[i] = gtk_combo_box_new_text();
244 
245         m_pListLabels[i] = gtk_label_new( "" );
246 
247 #define LABEL_LIST( elem ) \
248         case elem : \
249             aLabel = aResProvider.getResString( LISTBOX_##elem##_LABEL ); \
250             setLabel( LISTBOX_##elem##_LABEL, aLabel ); \
251             break
252 
253         switch( i )
254         {
255             LABEL_LIST( VERSION );
256             LABEL_LIST( TEMPLATE );
257             LABEL_LIST( IMAGE_TEMPLATE );
258             default:
259                 OSL_TRACE("Handle unknown control %d\n", i);
260                 break;
261         }
262 
263         gtk_container_add( GTK_CONTAINER( m_pAligns[i]), m_pLists[i] );
264         gtk_box_pack_end( GTK_BOX( m_pHBoxs[i] ), m_pAligns[i], sal_False, sal_False, 0 );
265 
266         gtk_box_pack_end( GTK_BOX( m_pHBoxs[i] ), m_pListLabels[i], sal_False, sal_False, 0 );
267 
268         gtk_box_pack_end( GTK_BOX( m_pVBox ), m_pHBoxs[i], sal_False, sal_False, 0 );
269     }
270 
271     aLabel = aResProvider.getResString( FILE_PICKER_FILE_TYPE );
272     m_pFilterExpander = gtk_expander_new_with_mnemonic(
273         OUStringToOString( aLabel, RTL_TEXTENCODING_UTF8 ).getStr());
274 
275     gtk_box_pack_end( GTK_BOX( m_pVBox ), m_pFilterExpander, sal_False, sal_True, 0 );
276 
277     GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
278     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
279         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
280     gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
281         GTK_SHADOW_IN);
282     gtk_container_add (GTK_CONTAINER (m_pFilterExpander), scrolled_window);
283     gtk_widget_show (scrolled_window);
284 
285     ByteString sExpand(getenv("SAL_EXPANDFPICKER"));
286     sal_Int32 nExpand  = sExpand.ToInt32();
287     switch (nExpand)
288     {
289         default:
290         case 0:
291             break;
292         case 1:
293             gtk_expander_set_expanded(GTK_EXPANDER(m_pFilterExpander), sal_True);
294             break;
295         case 2:
296             expandexpanders(GTK_CONTAINER(m_pDialog));
297             gtk_expander_set_expanded(GTK_EXPANDER(m_pFilterExpander), sal_True);
298             break;
299     }
300 
301     m_pFilterStore = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING,
302         G_TYPE_STRING, G_TYPE_STRING);
303     m_pFilterView = gtk_tree_view_new_with_model (GTK_TREE_MODEL(m_pFilterStore));
304     gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(m_pFilterView), false);
305     gtk_tree_view_set_rules_hint (GTK_TREE_VIEW(m_pFilterView), true);
306 
307     GtkTreeViewColumn *column;
308     GtkCellRenderer *cell;
309 
310     for (i = 0; i < 2; ++i)
311     {
312         column = gtk_tree_view_column_new ();
313         cell = gtk_cell_renderer_text_new ();
314         gtk_tree_view_column_set_expand (column, sal_True);
315         gtk_tree_view_column_pack_start (column, cell, sal_False);
316         gtk_tree_view_column_set_attributes (column, cell, "text", i, (char *)NULL);
317         gtk_tree_view_append_column (GTK_TREE_VIEW(m_pFilterView), column);
318     }
319 
320     gtk_container_add (GTK_CONTAINER (scrolled_window), m_pFilterView);
321     gtk_widget_show (m_pFilterView);
322 
323     gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER( m_pDialog ), m_pVBox );
324 
325     m_pPreview = gtk_image_new();
326     gtk_file_chooser_set_preview_widget( GTK_FILE_CHOOSER( m_pDialog ), m_pPreview );
327 
328     g_signal_connect( G_OBJECT( m_pToggles[PREVIEW] ), "toggled",
329                       G_CALLBACK( preview_toggled_cb ), this );
330     g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW(m_pFilterView)), "changed",
331                       G_CALLBACK ( type_changed_cb ), this);
332     g_signal_connect( G_OBJECT( m_pDialog ), "notify::filter",
333                       G_CALLBACK( filter_changed_cb ), this);
334     g_signal_connect( G_OBJECT( m_pFilterExpander ), "activate",
335                       G_CALLBACK( expander_changed_cb ), this);
336     g_signal_connect (G_OBJECT( m_pDialog ), "map",
337                       G_CALLBACK (dialog_mapped_cb), this);
338 
339     gtk_widget_show( m_pVBox );
340 
341     PangoLayout  *layout = gtk_widget_create_pango_layout (m_pFilterView, NULL);
342     guint ypad;
343     PangoRectangle row_height;
344     pango_layout_set_markup (layout, "All Files", -1);
345     pango_layout_get_pixel_extents (layout, NULL, &row_height);
346     g_object_get (cell, "ypad", &ypad, (char *)NULL);
347     guint height = (row_height.height + 2*ypad) * 5;
348     gtk_widget_set_size_request (m_pFilterView, -1, height);
349     gtk_widget_set_size_request (m_pPreview, 1, height);
350 
351     gtk_file_chooser_set_preview_widget_active( GTK_FILE_CHOOSER( m_pDialog ), true);
352 }
353 
354 //------------------------------------------------------------------------------------
355 // XFilePickerNotifier
356 //------------------------------------------------------------------------------------
357 
358 void SAL_CALL SalGtkFilePicker::addFilePickerListener( const uno::Reference<XFilePickerListener>& xListener )
359     throw( uno::RuntimeException )
360 {
361     m_xListener = xListener;
362 }
363 
364 void SAL_CALL SalGtkFilePicker::removeFilePickerListener( const uno::Reference<XFilePickerListener>& )
365     throw( uno::RuntimeException )
366 {
367     m_xListener.clear();
368 }
369 
370 // -------------------------------------------------
371 // XEventListener
372 // -------------------------------------------------
373 
374 void SAL_CALL SalGtkFilePicker::disposing( const lang::EventObject& aEvent ) throw( uno::RuntimeException )
375 {
376     uno::Reference<XFilePickerListener> xFilePickerListener( aEvent.Source, ::com::sun::star::uno::UNO_QUERY );
377 
378     if( xFilePickerListener.is() )
379         removeFilePickerListener( xFilePickerListener );
380 }
381 
382 //-----------------------------------------------------------------------------------------
383 // FilePicker Event functions
384 //-----------------------------------------------------------------------------------------
385 
386 void SAL_CALL SalGtkFilePicker::fileSelectionChanged( FilePickerEvent aEvent )
387 {
388     OSL_TRACE( "file selection changed");
389     if (m_xListener.is()) m_xListener->fileSelectionChanged( aEvent );
390 }
391 
392 void SAL_CALL SalGtkFilePicker::directoryChanged( FilePickerEvent aEvent )
393 {
394     OSL_TRACE("directory changed");
395     if (m_xListener.is()) m_xListener->directoryChanged( aEvent );
396 }
397 
398 void SAL_CALL SalGtkFilePicker::controlStateChanged( FilePickerEvent aEvent )
399 {
400     OSL_TRACE("control state changed");
401     if (m_xListener.is()) m_xListener->controlStateChanged( aEvent );
402 }
403 
404 //-----------------------------------------------------------------------------------------
405 // If there are more then one listener the return value of the last one wins
406 //-----------------------------------------------------------------------------------------
407 
408 rtl::OUString SAL_CALL SalGtkFilePicker::helpRequested( FilePickerEvent aEvent ) const
409 {
410     rtl::OUString aHelpText;
411 
412     ::cppu::OInterfaceContainerHelper* pICHelper =
413         rBHelper.getContainer( getCppuType( ( uno::Reference<XFilePickerListener> * )0 ) );
414 
415     if( pICHelper )
416     {
417         ::cppu::OInterfaceIteratorHelper iter( *pICHelper );
418 
419         while( iter.hasMoreElements() )
420         {
421             try
422             {
423                 /*
424                       if there are multiple listeners responding
425                           to this notification the next response
426                   overwrittes  the one before if it is not empty
427                         */
428 
429                 rtl::OUString aTempString;
430 
431                 uno::Reference<XFilePickerListener> xFPListener( iter.next(), uno::UNO_QUERY );
432                 if( xFPListener.is() )
433                         {
434                     aTempString = xFPListener->helpRequested( aEvent );
435                     if( aTempString.getLength() )
436                         aHelpText = aTempString;
437                         }
438 
439             }
440             catch( uno::RuntimeException& )
441             {
442                 OSL_ENSURE( false, "RuntimeException during event dispatching" );
443             }
444         }
445     }
446 
447     return aHelpText;
448 }
449 
450 //=====================================================================
451 
452 struct FilterEntry
453 {
454 protected:
455     ::rtl::OUString     m_sTitle;
456     ::rtl::OUString     m_sFilter;
457 
458     UnoFilterList       m_aSubFilters;
459 
460 public:
461     FilterEntry( const ::rtl::OUString& _rTitle, const ::rtl::OUString& _rFilter )
462         :m_sTitle( _rTitle )
463         ,m_sFilter( _rFilter )
464     {
465     }
466 
467     FilterEntry( const ::rtl::OUString& _rTitle, const UnoFilterList& _rSubFilters );
468 
469     ::rtl::OUString     getTitle() const { return m_sTitle; }
470     ::rtl::OUString     getFilter() const { return m_sFilter; }
471 
472     /// determines if the filter has sub filter (i.e., the filter is a filter group in real)
473     sal_Bool        hasSubFilters( ) const;
474 
475     /** retrieves the filters belonging to the entry
476     @return
477         the number of sub filters
478     */
479     sal_Int32       getSubFilters( UnoFilterList& _rSubFilterList );
480 
481     // helpers for iterating the sub filters
482     const UnoFilterEntry*   beginSubFilters() const { return m_aSubFilters.getConstArray(); }
483     const UnoFilterEntry*   endSubFilters() const { return m_aSubFilters.getConstArray() + m_aSubFilters.getLength(); }
484 };
485 
486 //=====================================================================
487 
488 //---------------------------------------------------------------------
489 FilterEntry::FilterEntry( const ::rtl::OUString& _rTitle, const UnoFilterList& _rSubFilters )
490     :m_sTitle( _rTitle )
491     ,m_aSubFilters( _rSubFilters )
492 {
493 }
494 
495 //---------------------------------------------------------------------
496 sal_Bool FilterEntry::hasSubFilters() const
497 {
498     return( 0 < m_aSubFilters.getLength() );
499 }
500 
501 //---------------------------------------------------------------------
502 sal_Int32 FilterEntry::getSubFilters( UnoFilterList& _rSubFilterList )
503 {
504     _rSubFilterList = m_aSubFilters;
505     return m_aSubFilters.getLength();
506 }
507 
508 static bool
509 isFilterString( const rtl::OUString &rFilterString, const char *pMatch )
510 {
511         sal_Int32 nIndex = 0;
512         rtl::OUString aToken;
513         bool bIsFilter = true;
514 
515         rtl::OUString aMatch(rtl::OUString::createFromAscii(pMatch));
516 
517         do
518         {
519             aToken = rFilterString.getToken( 0, ';', nIndex );
520             if( !aToken.match( aMatch ) )
521             {
522                 bIsFilter = false;
523                 break;
524             }
525         }
526         while( nIndex >= 0 );
527 
528         return bIsFilter;
529 }
530 
531 static rtl::OUString
532 shrinkFilterName( const rtl::OUString &rFilterName, bool bAllowNoStar = false )
533 {
534     int i;
535     int nBracketLen = -1;
536     int nBracketEnd = -1;
537     const sal_Unicode *pStr = rFilterName;
538     OUString aRealName = rFilterName;
539 
540     for( i = aRealName.getLength() - 1; i > 0; i-- )
541     {
542         if( pStr[i] == ')' )
543             nBracketEnd = i;
544         else if( pStr[i] == '(' )
545         {
546             nBracketLen = nBracketEnd - i;
547             if( nBracketEnd <= 0 )
548                 continue;
549             if( isFilterString( rFilterName.copy( i + 1, nBracketLen - 1 ), "*." ) )
550                 aRealName = aRealName.replaceAt( i, nBracketLen + 1, rtl::OUString() );
551             else if (bAllowNoStar)
552             {
553                 if( isFilterString( rFilterName.copy( i + 1, nBracketLen - 1 ), ".") )
554                     aRealName = aRealName.replaceAt( i, nBracketLen + 1, rtl::OUString() );
555             }
556         }
557     }
558 
559     return aRealName;
560 }
561 
562 static void
563 dialog_remove_buttons( GtkDialog *pDialog )
564 {
565     GdkThreadLock aLock;
566 
567     g_return_if_fail( GTK_IS_DIALOG( pDialog ) );
568 
569     GList *pChildren =
570         gtk_container_get_children( GTK_CONTAINER( pDialog->action_area ) );
571 
572     for( GList *p = pChildren; p; p = p->next )
573         gtk_widget_destroy( GTK_WIDGET( p->data ) );
574 
575     g_list_free( pChildren );
576 }
577 
578 //------------------------------------------------------------------------------------
579 namespace {
580     //................................................................................
581     struct FilterTitleMatch : public ::std::unary_function< FilterEntry, bool >
582     {
583     protected:
584         const ::rtl::OUString& rTitle;
585 
586     public:
587         FilterTitleMatch( const ::rtl::OUString& _rTitle ) : rTitle( _rTitle ) { }
588 
589         //............................................................................
590         bool operator () ( const FilterEntry& _rEntry )
591         {
592             sal_Bool bMatch;
593             if( !_rEntry.hasSubFilters() )
594                 // a real filter
595                 bMatch = ( _rEntry.getTitle() == rTitle );
596             else
597                 // a filter group -> search the sub filters
598                 bMatch =
599                     _rEntry.endSubFilters() != ::std::find_if(
600                         _rEntry.beginSubFilters(),
601                         _rEntry.endSubFilters(),
602                         *this
603                     );
604 
605             return bMatch ? true : false;
606         }
607         bool operator () ( const UnoFilterEntry& _rEntry )
608         {
609             OUString aShrunkName = shrinkFilterName( _rEntry.First );
610             return aShrunkName == rTitle ? true : false;
611         }
612     };
613 }
614 
615 
616 //------------------------------------------------------------------------------------
617 sal_Bool SalGtkFilePicker::FilterNameExists( const ::rtl::OUString& rTitle )
618 {
619     sal_Bool bRet = sal_False;
620 
621     if( m_pFilterList )
622         bRet =
623             m_pFilterList->end() != ::std::find_if(
624                 m_pFilterList->begin(),
625                 m_pFilterList->end(),
626                 FilterTitleMatch( rTitle )
627             );
628 
629     return bRet;
630 }
631 
632 //------------------------------------------------------------------------------------
633 sal_Bool SalGtkFilePicker::FilterNameExists( const UnoFilterList& _rGroupedFilters )
634 {
635     sal_Bool bRet = sal_False;
636 
637     if( m_pFilterList )
638     {
639         const UnoFilterEntry* pStart = _rGroupedFilters.getConstArray();
640         const UnoFilterEntry* pEnd = pStart + _rGroupedFilters.getLength();
641         for( ; pStart != pEnd; ++pStart )
642             if( m_pFilterList->end() != ::std::find_if(
643                         m_pFilterList->begin(),
644                         m_pFilterList->end(),
645                         FilterTitleMatch( pStart->First ) ) )
646                 break;
647 
648         bRet = pStart != pEnd;
649     }
650 
651     return bRet;
652 }
653 
654 //------------------------------------------------------------------------------------
655 void SalGtkFilePicker::ensureFilterList( const ::rtl::OUString& _rInitialCurrentFilter )
656 {
657     if( !m_pFilterList )
658     {
659         m_pFilterList = new FilterList;
660 
661         // set the first filter to the current filter
662         if ( !m_aCurrentFilter.getLength() )
663             m_aCurrentFilter = _rInitialCurrentFilter;
664     }
665 }
666 
667 
668 //-----------------------------------------------------------------------------------------
669 //
670 //-----------------------------------------------------------------------------------------
671 
672 void SAL_CALL SalGtkFilePicker::appendFilter( const rtl::OUString& aTitle, const rtl::OUString& aFilter )
673     throw( lang::IllegalArgumentException, uno::RuntimeException )
674 {
675     OSL_ASSERT( m_pDialog != NULL );
676 
677     if( FilterNameExists( aTitle ) )
678             throw IllegalArgumentException();
679 
680     // ensure that we have a filter list
681     ensureFilterList( aTitle );
682 
683     // append the filter
684     m_pFilterList->insert( m_pFilterList->end(), FilterEntry( aTitle, aFilter ) );
685 }
686 
687 //-----------------------------------------------------------------------------------------
688 //
689 //-----------------------------------------------------------------------------------------
690 
691 void SAL_CALL SalGtkFilePicker::setCurrentFilter( const rtl::OUString& aTitle )
692     throw( lang::IllegalArgumentException, uno::RuntimeException )
693 {
694     OSL_ASSERT( m_pDialog != NULL );
695 
696     OSL_TRACE( "Setting current filter to %s\n",
697         OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
698 
699     if( aTitle != m_aCurrentFilter )
700     {
701         m_aCurrentFilter = aTitle;
702         SetCurFilter( m_aCurrentFilter );
703         OSL_TRACE( "REALLY Setting current filter to %s\n",
704             OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
705 
706     }
707 
708     // TODO m_pImpl->setCurrentFilter( aTitle );
709 }
710 
711 //-----------------------------------------------------------------------------------------
712 //
713 //-----------------------------------------------------------------------------------------
714 
715 void SalGtkFilePicker::updateCurrentFilterFromName(const gchar* filtername)
716 {
717     OUString aFilterName(filtername, strlen(filtername), RTL_TEXTENCODING_UTF8);
718     FilterList::iterator aEnd = m_pFilterList->end();
719     for (FilterList::iterator aIter = m_pFilterList->begin(); aIter != aEnd; ++aIter)
720     {
721         if (aFilterName == shrinkFilterName( aIter->getTitle()))
722         {
723             m_aCurrentFilter = aIter->getTitle();
724             break;
725         }
726     }
727 }
728 
729 void SalGtkFilePicker::UpdateFilterfromUI()
730 {
731     // Update the filtername from the users selection if they have had a chance to do so.
732     // If the user explicitly sets a type then use that, if not then take the implicit type
733     // from the filter of the files glob on which he is currently searching
734     if (!mnHID_FolderChange || !mnHID_SelectionChange)
735         return;
736 
737     GdkThreadLock aLock;
738 
739     GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(m_pFilterView));
740     GtkTreeIter iter;
741     GtkTreeModel *model;
742     if (gtk_tree_selection_get_selected (selection, &model, &iter))
743     {
744         gchar *title;
745         gtk_tree_model_get (model, &iter, 2, &title, -1);
746         updateCurrentFilterFromName(title);
747         g_free (title);
748     }
749     else if( GtkFileFilter *filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(m_pDialog)))
750     {
751         if (m_pPseudoFilter != filter)
752             updateCurrentFilterFromName(gtk_file_filter_get_name( filter ));
753         else
754             updateCurrentFilterFromName(OUStringToOString( m_aInitialFilter, RTL_TEXTENCODING_UTF8 ).getStr());
755     }
756 }
757 
758 rtl::OUString SAL_CALL SalGtkFilePicker::getCurrentFilter() throw( uno::RuntimeException )
759 {
760     OSL_ASSERT( m_pDialog != NULL );
761 
762     OSL_TRACE( "GetCURRENTfilter\n" );
763 
764     UpdateFilterfromUI();
765 
766     OSL_TRACE( "Returning current filter of %s\n",
767         OUStringToOString( m_aCurrentFilter, RTL_TEXTENCODING_UTF8 ).getStr() );
768 
769     return m_aCurrentFilter;
770 }
771 
772 //-----------------------------------------------------------------------------------------
773 // XFilterGroupManager functions
774 //-----------------------------------------------------------------------------------------
775 
776 void SAL_CALL SalGtkFilePicker::appendFilterGroup( const rtl::OUString& /*sGroupTitle*/, const uno::Sequence<beans::StringPair>& aFilters )
777     throw( lang::IllegalArgumentException, uno::RuntimeException )
778 {
779     OSL_ASSERT( m_pDialog != NULL );
780 
781     // TODO m_pImpl->appendFilterGroup( sGroupTitle, aFilters );
782     // check the names
783     if( FilterNameExists( aFilters ) )
784         // TODO: a more precise exception message
785             throw IllegalArgumentException();
786 
787     // ensure that we have a filter list
788     ::rtl::OUString sInitialCurrentFilter;
789     if( aFilters.getLength() )
790         sInitialCurrentFilter = aFilters[0].First;
791 
792     ensureFilterList( sInitialCurrentFilter );
793 
794     // append the filter
795     const StringPair* pSubFilters   = aFilters.getConstArray();
796     const StringPair* pSubFiltersEnd = pSubFilters + aFilters.getLength();
797     for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters )
798         m_pFilterList->insert( m_pFilterList->end(), FilterEntry( pSubFilters->First, pSubFilters->Second ) );
799 
800 }
801 
802 //-----------------------------------------------------------------------------------------
803 // XFilePicker functions
804 //-----------------------------------------------------------------------------------------
805 
806 void SAL_CALL SalGtkFilePicker::setMultiSelectionMode( sal_Bool bMode ) throw( uno::RuntimeException )
807 {
808     OSL_ASSERT( m_pDialog != NULL );
809 
810     GdkThreadLock aLock;
811 
812     gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER(m_pDialog), bMode );
813 }
814 
815 void SAL_CALL SalGtkFilePicker::setDefaultName( const rtl::OUString& aName )
816     throw( uno::RuntimeException )
817 {
818     OSL_ASSERT( m_pDialog != NULL );
819 
820     GdkThreadLock aLock;
821 
822     OString aStr = OUStringToOString( aName, RTL_TEXTENCODING_UTF8 );
823     GtkFileChooserAction eAction = gtk_file_chooser_get_action( GTK_FILE_CHOOSER( m_pDialog ) );
824 
825     // set_current_name launches a Gtk critical error if called for other than save
826     if( GTK_FILE_CHOOSER_ACTION_SAVE == eAction )
827         gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER( m_pDialog ), aStr.getStr() );
828 }
829 
830 void SAL_CALL SalGtkFilePicker::setDisplayDirectory( const rtl::OUString& rDirectory )
831     throw( lang::IllegalArgumentException, uno::RuntimeException )
832 {
833     implsetDisplayDirectory(rDirectory);
834 }
835 
836 rtl::OUString SAL_CALL SalGtkFilePicker::getDisplayDirectory() throw( uno::RuntimeException )
837 {
838     return implgetDisplayDirectory();
839 }
840 
841 uno::Sequence<rtl::OUString> SAL_CALL SalGtkFilePicker::getFiles() throw( uno::RuntimeException )
842 {
843     uno::Sequence< rtl::OUString > aFiles = getSelectedFiles();
844     /*
845       The previous multiselection API design was completely broken
846       and unimplementable for some hetrogenous pseudo-URIs eg. search://
847       Thus crop unconditionally to a single selection.
848     */
849     aFiles.realloc (1);
850     return aFiles;
851 }
852 
853 uno::Sequence<rtl::OUString> SAL_CALL SalGtkFilePicker::getSelectedFiles() throw( uno::RuntimeException )
854 {
855     OSL_ASSERT( m_pDialog != NULL );
856 
857     GdkThreadLock aLock;
858 
859     GSList* pPathList = gtk_file_chooser_get_uris( GTK_FILE_CHOOSER(m_pDialog) );
860 
861     int nCount = g_slist_length( pPathList );
862     int nIndex = 0;
863     OSL_TRACE( "GETFILES called %d files\n", nCount );
864 
865     // get the current action setting
866     GtkFileChooserAction eAction = gtk_file_chooser_get_action(
867         GTK_FILE_CHOOSER( m_pDialog ));
868 
869     uno::Sequence< rtl::OUString > aSelectedFiles(nCount);
870 
871     // Convert to OOo
872     for( GSList *pElem = pPathList; pElem; pElem = pElem->next)
873     {
874         gchar *pURI = reinterpret_cast<gchar*>(pElem->data);
875         aSelectedFiles[ nIndex ] = uritounicode(pURI);
876 
877         if( GTK_FILE_CHOOSER_ACTION_SAVE == eAction )
878         {
879             OUString sFilterName;
880             sal_Int32 nTokenIndex = 0;
881             bool bExtensionTypedIn = false;
882 
883             GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(m_pFilterView));
884             GtkTreeIter iter;
885             GtkTreeModel *model;
886             if (gtk_tree_selection_get_selected (selection, &model, &iter))
887             {
888                 gchar *title;
889                 gtk_tree_model_get (model, &iter, 2, &title, -1);
890                 sFilterName = OUString( title, strlen( title), RTL_TEXTENCODING_UTF8 );
891                 g_free (title);
892             }
893             else
894             {
895                 if( aSelectedFiles[nIndex].indexOf('.') > 0 )
896                 {
897                     rtl::OUString sExtension;
898                     nTokenIndex = 0;
899                     do
900                         sExtension = aSelectedFiles[nIndex].getToken( 0, '.', nTokenIndex );
901                     while( nTokenIndex >= 0 );
902 
903                     if( sExtension.getLength() >= 3 ) // 3 = typical/minimum extension length
904                     {
905                         static const OUString aStarDot = OUString::createFromAscii( "*." );
906 
907                         ::rtl::OUString aNewFilter;
908                         ::rtl::OUString aOldFilter = getCurrentFilter();
909                         sal_Bool bChangeFilter = sal_True;
910                         for ( FilterList::iterator aListIter = m_pFilterList->begin();
911                               aListIter != m_pFilterList->end();
912                               ++aListIter
913                         )
914                         {
915                             if( aListIter->getFilter().indexOf( aStarDot+sExtension ) >= 0 )
916                             {
917                                 if( !aNewFilter.getLength() )
918                                     aNewFilter = aListIter->getTitle();
919 
920                                 if( aOldFilter == aListIter->getTitle() )
921                                     bChangeFilter = sal_False;
922 
923                                 bExtensionTypedIn = true;
924                             }
925                         }
926                         if( bChangeFilter )
927                             setCurrentFilter( aNewFilter );
928                     }
929                 }
930 
931                 GtkFileFilter *filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(m_pDialog));
932                 if (m_pPseudoFilter != filter)
933                 {
934                     const gchar* filtername =
935                         gtk_file_filter_get_name( filter );
936                     sFilterName = OUString( filtername, strlen( filtername ), RTL_TEXTENCODING_UTF8 );
937                 }
938                 else
939                     sFilterName = m_aInitialFilter;
940             }
941 
942             OSL_TRACE( "2: current filter is %s\n",
943                 OUStringToOString( sFilterName, RTL_TEXTENCODING_UTF8 ).getStr() );
944 
945             FilterList::iterator aListIter = ::std::find_if(
946                 m_pFilterList->begin(), m_pFilterList->end(), FilterTitleMatch(sFilterName) );
947 
948             OUString aFilter;
949             if (aListIter != m_pFilterList->end())
950                 aFilter = aListIter->getFilter();
951 
952             OSL_TRACE( "turned into %s\n",
953                 OUStringToOString( aFilter, RTL_TEXTENCODING_UTF8 ).getStr() );
954 
955             nTokenIndex = 0;
956             rtl::OUString sToken;
957             //   rtl::OUString strExt;
958             do
959             {
960                 sToken = aFilter.getToken( 0, '.', nTokenIndex );
961 
962                 if ( sToken.lastIndexOf( ';' ) != -1 )
963                 {
964                     sal_Int32 nZero = 0;
965                     OUString aCurrentToken = sToken.getToken( 0, ';', nZero);
966 
967                     sToken = aCurrentToken;
968                     break;
969                 }
970             }
971             while( nTokenIndex >= 0 );
972 
973             if( !bExtensionTypedIn && ( !sToken.equalsAscii( "*" ) ) )
974             {
975                 //if the filename does not already have the auto extension, stick it on
976                 OUString sExtension = OUString::createFromAscii( "." ) + sToken;
977                 OUString &rBase = aSelectedFiles[nIndex];
978                 sal_Int32 nExtensionIdx = rBase.getLength() - sExtension.getLength();
979                 OSL_TRACE( "idx are %d %d\n", rBase.lastIndexOf( sExtension ), nExtensionIdx );
980 
981                 if( rBase.lastIndexOf( sExtension ) != nExtensionIdx )
982                     rBase += sExtension;
983             }
984 
985         }
986 
987         nIndex++;
988         g_free( pURI );
989     }
990 
991     g_slist_free( pPathList );
992 
993     return aSelectedFiles;
994 }
995 
996 //-----------------------------------------------------------------------------------------
997 // XExecutableDialog functions
998 //-----------------------------------------------------------------------------------------
999 
1000 void SAL_CALL SalGtkFilePicker::setTitle( const rtl::OUString& rTitle ) throw( uno::RuntimeException )
1001 {
1002     implsetTitle(rTitle);
1003 }
1004 
1005 sal_Int16 SAL_CALL SalGtkFilePicker::execute() throw( uno::RuntimeException )
1006 {
1007     OSL_TRACE( "1: HERE WE ARE\n");
1008     OSL_ASSERT( m_pDialog != NULL );
1009 
1010     GdkThreadLock aLock;
1011 
1012     sal_Int16 retVal = 0;
1013 
1014     SetFilters();
1015 
1016     mnHID_FolderChange =
1017         g_signal_connect( GTK_FILE_CHOOSER( m_pDialog ), "current-folder-changed",
1018             G_CALLBACK( folder_changed_cb ), ( gpointer )this );
1019 
1020     mnHID_SelectionChange =
1021         g_signal_connect( GTK_FILE_CHOOSER( m_pDialog ), "selection-changed",
1022             G_CALLBACK( selection_changed_cb ), ( gpointer )this );
1023 
1024     int btn = GTK_RESPONSE_NO;
1025 
1026     uno::Reference< awt::XExtendedToolkit > xToolkit(
1027         m_xServiceMgr->createInstance( ::rtl::OUString::createFromAscii("com.sun.star.awt.Toolkit") ), uno::UNO_QUERY);
1028 
1029     RunDialog* pRunDialog = new RunDialog(m_pDialog, xToolkit);
1030     uno::Reference < awt::XTopWindowListener > xLifeCycle(pRunDialog);
1031     while( GTK_RESPONSE_NO == btn )
1032     {
1033         btn = GTK_RESPONSE_YES; // we dont want to repeat unless user clicks NO for file save.
1034 
1035         gint nStatus = pRunDialog->run();
1036         switch( nStatus )
1037         {
1038             case GTK_RESPONSE_ACCEPT:
1039                 if( GTK_FILE_CHOOSER_ACTION_SAVE == gtk_file_chooser_get_action( GTK_FILE_CHOOSER( m_pDialog ) ) )
1040                 {
1041                     Sequence < OUString > aPathSeq = getFiles();
1042                     if( aPathSeq.getLength() == 1 )
1043                     {
1044                         OString sFileName = unicodetouri( aPathSeq[0] );
1045                         if( g_file_test( g_filename_from_uri( sFileName.getStr(), NULL, NULL ), G_FILE_TEST_IS_REGULAR ) )
1046                         {
1047                             CResourceProvider aResProvider;
1048                             GtkWidget *dlg;
1049 
1050                             dlg = gtk_message_dialog_new( NULL,
1051                                 GTK_DIALOG_MODAL,
1052                                 GTK_MESSAGE_QUESTION,
1053                                 GTK_BUTTONS_YES_NO,
1054                                   OUStringToOString(
1055                                     aResProvider.getResString( FILE_PICKER_OVERWRITE ),
1056                                     RTL_TEXTENCODING_UTF8 ).getStr() );
1057 
1058                             gtk_window_set_title( GTK_WINDOW( dlg ),
1059                                 OUStringToOString(aResProvider.getResString(FILE_PICKER_TITLE_SAVE ),
1060                                 RTL_TEXTENCODING_UTF8 ).getStr() );
1061 
1062                             RunDialog* pAnotherDialog = new RunDialog(dlg, xToolkit);
1063                             uno::Reference < awt::XTopWindowListener > xAnotherLifeCycle(pAnotherDialog);
1064                             btn = pAnotherDialog->run();
1065 
1066                             gtk_widget_destroy( dlg );
1067                         }
1068 
1069                         if( btn == GTK_RESPONSE_YES )
1070                             retVal = ExecutableDialogResults::OK;
1071                     }
1072                 }
1073                 else
1074                     retVal = ExecutableDialogResults::OK;
1075                 break;
1076 
1077             case GTK_RESPONSE_CANCEL:
1078                 retVal = ExecutableDialogResults::CANCEL;
1079                 break;
1080 
1081             case 1: //PLAY
1082                 {
1083                     FilePickerEvent evt;
1084                     evt.ElementId = PUSHBUTTON_PLAY;
1085                     OSL_TRACE( "filter_changed, isn't it great %x\n", this);
1086                     controlStateChanged( evt );
1087                     btn = GTK_RESPONSE_NO;
1088                 }
1089                 break;
1090 
1091             default:
1092                 retVal = 0;
1093                 break;
1094         }
1095     }
1096 
1097     if (mnHID_FolderChange)
1098         g_signal_handler_disconnect(GTK_FILE_CHOOSER( m_pDialog ), mnHID_FolderChange);
1099     if (mnHID_SelectionChange)
1100         g_signal_handler_disconnect(GTK_FILE_CHOOSER( m_pDialog ), mnHID_SelectionChange);
1101 
1102     return retVal;
1103 }
1104 
1105 //------------------------------------------------------------------------------------
1106 
1107 // cf. offapi/com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.idl
1108 GtkWidget *SalGtkFilePicker::getWidget( sal_Int16 nControlId, GType *pType )
1109 {
1110     OSL_TRACE("control id is %d", nControlId);
1111     GType      tType = GTK_TYPE_TOGGLE_BUTTON; //prevent waring by initializing
1112     GtkWidget *pWidget = 0;
1113 
1114 #define MAP_TOGGLE( elem ) \
1115         case ExtendedFilePickerElementIds::CHECKBOX_##elem: \
1116             pWidget = m_pToggles[elem]; tType = GTK_TYPE_TOGGLE_BUTTON; \
1117             break
1118 #define MAP_BUTTON( elem ) \
1119         case ExtendedFilePickerElementIds::PUSHBUTTON_##elem: \
1120             pWidget = m_pButtons[elem]; tType = GTK_TYPE_BUTTON; \
1121             break
1122 #define MAP_LIST( elem ) \
1123         case ExtendedFilePickerElementIds::LISTBOX_##elem: \
1124             pWidget = m_pLists[elem]; tType = GTK_TYPE_COMBO_BOX; \
1125             break
1126 #define MAP_LIST_LABEL( elem ) \
1127         case ExtendedFilePickerElementIds::LISTBOX_##elem##_LABEL: \
1128             pWidget = m_pListLabels[elem]; tType = GTK_TYPE_LABEL; \
1129             break
1130 
1131     switch( nControlId )
1132     {
1133         MAP_TOGGLE( AUTOEXTENSION );
1134         MAP_TOGGLE( PASSWORD );
1135         MAP_TOGGLE( FILTEROPTIONS );
1136         MAP_TOGGLE( READONLY );
1137         MAP_TOGGLE( LINK );
1138         MAP_TOGGLE( PREVIEW );
1139         MAP_TOGGLE( SELECTION );
1140         MAP_BUTTON( PLAY );
1141         MAP_LIST( VERSION );
1142         MAP_LIST( TEMPLATE );
1143         MAP_LIST( IMAGE_TEMPLATE );
1144         MAP_LIST_LABEL( VERSION );
1145         MAP_LIST_LABEL( TEMPLATE );
1146         MAP_LIST_LABEL( IMAGE_TEMPLATE );
1147     default:
1148         OSL_TRACE("Handle unknown control %d\n", nControlId);
1149         break;
1150     }
1151 #undef MAP
1152 
1153     if( pType )
1154         *pType = tType;
1155     return pWidget;
1156 }
1157 
1158 
1159 
1160 //------------------------------------------------------------------------------------
1161 // XFilePickerControlAccess functions
1162 //------------------------------------------------------------------------------------
1163 namespace
1164 {
1165     void HackWidthToFirst(GtkComboBox *pWidget)
1166     {
1167         GdkThreadLock aLock;
1168 
1169         GtkRequisition requisition;
1170         gtk_widget_size_request(GTK_WIDGET(pWidget), &requisition);
1171         gtk_widget_set_size_request(GTK_WIDGET(pWidget), requisition.width, -1);
1172     }
1173 }
1174 
1175 void SalGtkFilePicker::HandleSetListValue(GtkComboBox *pWidget, sal_Int16 nControlAction, const uno::Any& rValue)
1176 {
1177     GdkThreadLock aLock;
1178 
1179     switch (nControlAction)
1180     {
1181         case ControlActions::ADD_ITEM:
1182             {
1183                 OUString sItem;
1184                 rValue >>= sItem;
1185                 gtk_combo_box_append_text(pWidget, rtl::OUStringToOString(sItem, RTL_TEXTENCODING_UTF8).getStr());
1186                 if (!bVersionWidthUnset)
1187                 {
1188                     HackWidthToFirst(pWidget);
1189                     bVersionWidthUnset = true;
1190                 }
1191             }
1192             break;
1193         case ControlActions::ADD_ITEMS:
1194             {
1195                 Sequence< OUString > aStringList;
1196                 rValue >>= aStringList;
1197                 sal_Int32 nItemCount = aStringList.getLength();
1198                 for (sal_Int32 i = 0; i < nItemCount; ++i)
1199                 {
1200                     gtk_combo_box_append_text(pWidget,
1201                         rtl::OUStringToOString(aStringList[i], RTL_TEXTENCODING_UTF8).getStr());
1202                     if (!bVersionWidthUnset)
1203                     {
1204                         HackWidthToFirst(pWidget);
1205                         bVersionWidthUnset = true;
1206                     }
1207                 }
1208             }
1209             break;
1210         case ControlActions::DELETE_ITEM:
1211             {
1212                 sal_Int32 nPos=0;
1213                 rValue >>= nPos;
1214                 gtk_combo_box_remove_text(pWidget, nPos);
1215             }
1216             break;
1217         case ControlActions::DELETE_ITEMS:
1218             {
1219                 gtk_combo_box_set_active(pWidget, -1);
1220                 gint nItems = 0;
1221                 do
1222                 {
1223                         nItems =
1224                                 gtk_tree_model_iter_n_children(
1225                                   gtk_combo_box_get_model(pWidget), NULL);
1226                         for (gint nI = 0; nI < nItems; ++nI)
1227                             gtk_combo_box_remove_text(pWidget, nI);
1228                 }
1229                 while (nItems);
1230             }
1231             break;
1232         case ControlActions::SET_SELECT_ITEM:
1233             {
1234                 sal_Int32 nPos=0;
1235                 rValue >>= nPos;
1236                 gtk_combo_box_set_active(pWidget, nPos);
1237             }
1238             break;
1239         default:
1240             OSL_TRACE("undocumented/unimplemented ControlAction for a list");
1241             break;
1242     }
1243 
1244     //I think its best to make it insensitive unless there is the chance to
1245     //actually select something from the list.
1246     gint nItems = gtk_tree_model_iter_n_children(
1247                     gtk_combo_box_get_model(pWidget), NULL);
1248     gtk_widget_set_sensitive(GTK_WIDGET(pWidget), nItems > 1 ? true : false);
1249 }
1250 
1251 uno::Any SalGtkFilePicker::HandleGetListValue(GtkComboBox *pWidget, sal_Int16 nControlAction) const
1252 {
1253     GdkThreadLock aLock;
1254 
1255     uno::Any aAny;
1256     switch (nControlAction)
1257     {
1258         case ControlActions::GET_ITEMS:
1259             {
1260                 Sequence< OUString > aItemList;
1261 
1262                 GtkTreeModel *pTree = gtk_combo_box_get_model(pWidget);
1263                 GtkTreeIter iter;
1264                 if (gtk_tree_model_get_iter_first(pTree, &iter))
1265                 {
1266                     sal_Int32 nSize = gtk_tree_model_iter_n_children(
1267                         pTree, NULL);
1268 
1269                     aItemList.realloc(nSize);
1270                     for (sal_Int32 i=0; i < nSize; ++i)
1271                     {
1272                         gchar *item;
1273                         gtk_tree_model_get(gtk_combo_box_get_model(pWidget),
1274                             &iter, 0, &item, -1);
1275                         aItemList[i] = OUString(item, strlen(item), RTL_TEXTENCODING_UTF8);
1276                         g_free(item);
1277                         gtk_tree_model_iter_next(pTree, &iter);
1278                     }
1279                 }
1280                 aAny <<= aItemList;
1281             }
1282             break;
1283         case ControlActions::GET_SELECTED_ITEM:
1284             {
1285                 GtkTreeIter iter;
1286                 if (gtk_combo_box_get_active_iter(pWidget, &iter))
1287                 {
1288                         gchar *item;
1289                         gtk_tree_model_get(gtk_combo_box_get_model(pWidget),
1290                             &iter, 0, &item, -1);
1291                         OUString sItem(item, strlen(item), RTL_TEXTENCODING_UTF8);
1292                         aAny <<= sItem;
1293                         g_free(item);
1294                 }
1295             }
1296             break;
1297         case ControlActions::GET_SELECTED_ITEM_INDEX:
1298             {
1299                 gint nActive = gtk_combo_box_get_active(pWidget);
1300                 aAny <<= static_cast< sal_Int32 >(nActive);
1301             }
1302             break;
1303         default:
1304             OSL_TRACE("undocumented/unimplemented ControlAction for a list");
1305             break;
1306     }
1307     return aAny;
1308 }
1309 
1310 void SAL_CALL SalGtkFilePicker::setValue( sal_Int16 nControlId, sal_Int16 nControlAction, const uno::Any& rValue )
1311     throw( uno::RuntimeException )
1312 {
1313     OSL_ASSERT( m_pDialog != NULL );
1314 
1315     OSL_TRACE( "SETTING VALUE %d\n", nControlAction );
1316     GType tType;
1317     GtkWidget *pWidget;
1318 
1319     GdkThreadLock aLock;
1320 
1321     if( !( pWidget = getWidget( nControlId, &tType ) ) )
1322         OSL_TRACE("enable unknown control %d\n", nControlId);
1323     else if( tType == GTK_TYPE_TOGGLE_BUTTON )
1324     {
1325         sal_Bool bChecked = false;
1326         rValue >>= bChecked;
1327         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( pWidget ), bChecked );
1328     }
1329     else if( tType == GTK_TYPE_COMBO_BOX )
1330         HandleSetListValue(GTK_COMBO_BOX(pWidget), nControlAction, rValue);
1331     else
1332     {
1333         OSL_TRACE("Can't set value on button / list %d %d\n",
1334             nControlId, nControlAction);
1335     }
1336 }
1337 
1338 uno::Any SAL_CALL SalGtkFilePicker::getValue( sal_Int16 nControlId, sal_Int16 nControlAction )
1339     throw( uno::RuntimeException )
1340 {
1341     OSL_ASSERT( m_pDialog != NULL );
1342 
1343     uno::Any aRetval;
1344 
1345     GType tType;
1346     GtkWidget *pWidget;
1347 
1348     GdkThreadLock aLock;
1349 
1350     if( !( pWidget = getWidget( nControlId, &tType ) ) )
1351         OSL_TRACE("enable unknown control %d\n", nControlId);
1352     else if( tType == GTK_TYPE_TOGGLE_BUTTON )
1353         aRetval <<= (sal_Bool) gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( pWidget ) );
1354     else if( tType == GTK_TYPE_COMBO_BOX )
1355         aRetval = HandleGetListValue(GTK_COMBO_BOX(pWidget), nControlAction);
1356     else
1357         OSL_TRACE("Can't get value on button / list %d %d\n",
1358             nControlId, nControlAction );
1359 
1360     return aRetval;
1361 }
1362 
1363 void SAL_CALL SalGtkFilePicker::enableControl( sal_Int16 nControlId, sal_Bool bEnable )
1364 throw( uno::RuntimeException )
1365 {
1366     OSL_ASSERT( m_pDialog != NULL );
1367 
1368     GtkWidget *pWidget;
1369 
1370     GdkThreadLock aLock;
1371 
1372     if ( nControlId == ExtendedFilePickerElementIds::LISTBOX_FILTER_SELECTOR )
1373         gtk_expander_set_expanded( GTK_EXPANDER( m_pFilterExpander ), bEnable );
1374     else if( ( pWidget = getWidget( nControlId ) ) )
1375     {
1376         if( bEnable )
1377         {
1378             OSL_TRACE( "enable\n" );
1379             gtk_widget_set_sensitive( pWidget, sal_True );
1380         }
1381         else
1382         {
1383             OSL_TRACE( "disable\n" );
1384             gtk_widget_set_sensitive( pWidget, sal_False );
1385         }
1386     }
1387     else
1388         OSL_TRACE("enable unknown control %d\n", nControlId );
1389 }
1390 
1391 void SAL_CALL SalGtkFilePicker::setLabel( sal_Int16 nControlId, const ::rtl::OUString& rLabel )
1392     throw( uno::RuntimeException )
1393 {
1394     OSL_ASSERT( m_pDialog != NULL );
1395 
1396     GType tType;
1397     GtkWidget *pWidget;
1398 
1399     GdkThreadLock aLock;
1400 
1401     if( !( pWidget = getWidget( nControlId, &tType ) ) )
1402     {
1403         OSL_TRACE("Set label on unknown control %d\n", nControlId);
1404         return;
1405     }
1406 
1407     OString aTxt = OUStringToOString( rLabel.replace('~', '_'), RTL_TEXTENCODING_UTF8 );
1408     if (nControlId == ExtendedFilePickerElementIds::PUSHBUTTON_PLAY)
1409     {
1410 #ifdef GTK_STOCK_MEDIA_PLAY
1411         if (!msPlayLabel.getLength())
1412             msPlayLabel = rLabel;
1413         if (msPlayLabel == rLabel)
1414             gtk_button_set_label(GTK_BUTTON(pWidget), GTK_STOCK_MEDIA_PLAY);
1415         else
1416             gtk_button_set_label(GTK_BUTTON(pWidget), GTK_STOCK_MEDIA_STOP);
1417 #else
1418         gtk_button_set_label(GTK_BUTTON(pWidget), aTxt.getStr());
1419 #endif
1420     }
1421     else if( tType == GTK_TYPE_TOGGLE_BUTTON || tType == GTK_TYPE_BUTTON || tType == GTK_TYPE_LABEL )
1422         g_object_set( pWidget, "label", aTxt.getStr(),
1423                       "use_underline", sal_True, (char *)NULL );
1424     else
1425         OSL_TRACE("Can't set label on list\n");
1426 }
1427 
1428 rtl::OUString SAL_CALL SalGtkFilePicker::getLabel( sal_Int16 nControlId )
1429     throw( uno::RuntimeException )
1430 {
1431     OSL_ASSERT( m_pDialog != NULL );
1432 
1433     GType tType;
1434     OString aTxt;
1435     GtkWidget *pWidget;
1436 
1437     GdkThreadLock aLock;
1438 
1439     if( !( pWidget = getWidget( nControlId, &tType ) ) )
1440         OSL_TRACE("Get label on unknown control %d\n", nControlId);
1441     else if( tType == GTK_TYPE_TOGGLE_BUTTON || tType == GTK_TYPE_BUTTON || tType == GTK_TYPE_LABEL )
1442         aTxt = gtk_button_get_label( GTK_BUTTON( pWidget ) );
1443     else
1444         OSL_TRACE("Can't get label on list\n");
1445 
1446     return OStringToOUString( aTxt, RTL_TEXTENCODING_UTF8 );
1447 }
1448 
1449 //------------------------------------------------------------------------------------
1450 // XFilePreview functions
1451 //------------------------------------------------------------------------------------
1452 
1453 uno::Sequence<sal_Int16> SAL_CALL SalGtkFilePicker::getSupportedImageFormats() throw( uno::RuntimeException )
1454 {
1455     OSL_ASSERT( m_pDialog != NULL );
1456 
1457     // TODO return m_pImpl->getSupportedImageFormats();
1458     return uno::Sequence<sal_Int16>();
1459 }
1460 
1461 sal_Int32 SAL_CALL SalGtkFilePicker::getTargetColorDepth() throw( uno::RuntimeException )
1462 {
1463     OSL_ASSERT( m_pDialog != NULL );
1464 
1465     // TODO return m_pImpl->getTargetColorDepth();
1466     return 0;
1467 }
1468 
1469 sal_Int32 SAL_CALL SalGtkFilePicker::getAvailableWidth() throw( uno::RuntimeException )
1470 {
1471     OSL_ASSERT( m_pDialog != NULL );
1472 
1473     return m_PreviewImageWidth;
1474 }
1475 
1476 sal_Int32 SAL_CALL SalGtkFilePicker::getAvailableHeight() throw( uno::RuntimeException )
1477 {
1478     OSL_ASSERT( m_pDialog != NULL );
1479 
1480     return m_PreviewImageHeight;
1481 }
1482 
1483 void SAL_CALL SalGtkFilePicker::setImage( sal_Int16 /*aImageFormat*/, const uno::Any& /*aImage*/ )
1484     throw( lang::IllegalArgumentException, uno::RuntimeException )
1485 {
1486     OSL_ASSERT( m_pDialog != NULL );
1487 
1488     // TODO m_pImpl->setImage( aImageFormat, aImage );
1489 }
1490 
1491 void SalGtkFilePicker::implChangeType( GtkTreeSelection *selection )
1492 {
1493     CResourceProvider aResProvider;
1494     OUString aLabel = aResProvider.getResString( FILE_PICKER_FILE_TYPE );
1495 
1496     GdkThreadLock aLock;
1497 
1498     GtkTreeIter iter;
1499     GtkTreeModel *model;
1500     if (gtk_tree_selection_get_selected (selection, &model, &iter))
1501     {
1502         gchar *title;
1503         gtk_tree_model_get (model, &iter, 2, &title, -1);
1504         aLabel += rtl::OUString::createFromAscii( ": " );
1505         aLabel += rtl::OUString( title, strlen(title), RTL_TEXTENCODING_UTF8 );
1506         g_free (title);
1507     }
1508     gtk_expander_set_label (GTK_EXPANDER (m_pFilterExpander),
1509         OUStringToOString( aLabel, RTL_TEXTENCODING_UTF8 ).getStr());
1510     FilePickerEvent evt;
1511     evt.ElementId = LISTBOX_FILTER;
1512     controlStateChanged( evt );
1513 }
1514 
1515 void SalGtkFilePicker::type_changed_cb( GtkTreeSelection *selection, SalGtkFilePicker *pobjFP )
1516 {
1517     pobjFP->implChangeType(selection);
1518 }
1519 
1520 void SalGtkFilePicker::unselect_type()
1521 {
1522     GdkThreadLock aLock;
1523 
1524     gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(m_pFilterView)));
1525 }
1526 
1527 void SalGtkFilePicker::expander_changed_cb( GtkExpander *expander, SalGtkFilePicker *pobjFP )
1528 {
1529     if (gtk_expander_get_expanded(expander))
1530         pobjFP->unselect_type();
1531 }
1532 
1533 void SalGtkFilePicker::filter_changed_cb( GtkFileChooser *, GParamSpec *,
1534     SalGtkFilePicker *pobjFP )
1535 {
1536     FilePickerEvent evt;
1537     evt.ElementId = LISTBOX_FILTER;
1538     OSL_TRACE( "filter_changed, isn't it great %x\n", pobjFP );
1539     pobjFP->controlStateChanged( evt );
1540 }
1541 
1542 void SalGtkFilePicker::folder_changed_cb( GtkFileChooser *, SalGtkFilePicker *pobjFP )
1543 {
1544     FilePickerEvent evt;
1545     OSL_TRACE( "folder_changed, isn't it great %x\n", pobjFP );
1546     pobjFP->directoryChanged( evt );
1547 }
1548 
1549 void SalGtkFilePicker::selection_changed_cb( GtkFileChooser *, SalGtkFilePicker *pobjFP )
1550 {
1551     FilePickerEvent evt;
1552     OSL_TRACE( "selection_changed, isn't it great %x\n", pobjFP );
1553     pobjFP->fileSelectionChanged( evt );
1554 }
1555 
1556 void SalGtkFilePicker::update_preview_cb( GtkFileChooser *file_chooser, SalGtkFilePicker* pobjFP )
1557 {
1558     GtkWidget *preview;
1559     char *filename;
1560     GdkPixbuf *pixbuf;
1561     gboolean have_preview = sal_False;
1562 
1563     preview = pobjFP->m_pPreview;
1564     filename = gtk_file_chooser_get_preview_filename( file_chooser );
1565 
1566     if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( pobjFP->m_pToggles[PREVIEW] ) ) && g_file_test( filename, G_FILE_TEST_IS_REGULAR ) )
1567     {
1568         pixbuf = gdk_pixbuf_new_from_file_at_size(
1569                 filename,
1570                 pobjFP->m_PreviewImageWidth,
1571                 pobjFP->m_PreviewImageHeight, NULL );
1572 
1573         have_preview = ( pixbuf != NULL );
1574 
1575         gtk_image_set_from_pixbuf( GTK_IMAGE( preview ), pixbuf );
1576         if( pixbuf )
1577             gdk_pixbuf_unref( pixbuf );
1578 
1579     }
1580 
1581     gtk_file_chooser_set_preview_widget_active( file_chooser, have_preview );
1582 
1583     if( filename )
1584         g_free( filename );
1585 }
1586 
1587 sal_Bool SAL_CALL SalGtkFilePicker::setShowState( sal_Bool bShowState ) throw( uno::RuntimeException )
1588 {
1589     OSL_ASSERT( m_pDialog != NULL );
1590 
1591     // TODO return m_pImpl->setShowState( bShowState );
1592     if( bShowState != mbPreviewState )
1593     {
1594         GdkThreadLock aLock;
1595 
1596         if( bShowState )
1597         {
1598             // Show
1599             if( !mHID_Preview )
1600             {
1601                 mHID_Preview = g_signal_connect(
1602                     GTK_FILE_CHOOSER( m_pDialog ), "update-preview",
1603                     G_CALLBACK( update_preview_cb ), ( gpointer )this );
1604             }
1605             gtk_widget_show( m_pPreview );
1606         }
1607         else
1608         {
1609             // Hide
1610             gtk_widget_hide( m_pPreview );
1611         }
1612 
1613         // also emit the signal
1614         g_signal_emit_by_name( GTK_OBJECT( m_pDialog ), "update-preview" );
1615 
1616         mbPreviewState = bShowState;
1617     }
1618     return true;
1619 }
1620 
1621 sal_Bool SAL_CALL SalGtkFilePicker::getShowState() throw( uno::RuntimeException )
1622 {
1623     OSL_ASSERT( m_pDialog != NULL );
1624 
1625     return mbPreviewState;
1626 }
1627 
1628 //------------------------------------------------------------------------------------
1629 // XInitialization
1630 //------------------------------------------------------------------------------------
1631 
1632 void SAL_CALL SalGtkFilePicker::initialize( const uno::Sequence<uno::Any>& aArguments )
1633     throw( uno::Exception, uno::RuntimeException )
1634 {
1635     // parameter checking
1636     uno::Any aAny;
1637     if( 0 == aArguments.getLength() )
1638         throw lang::IllegalArgumentException(
1639             rtl::OUString::createFromAscii( "no arguments" ),
1640             static_cast<XFilePicker2*>( this ), 1 );
1641 
1642     aAny = aArguments[0];
1643 
1644     if( ( aAny.getValueType() != ::getCppuType( ( sal_Int16* )0 ) ) &&
1645          (aAny.getValueType() != ::getCppuType( ( sal_Int8* )0 ) ) )
1646          throw lang::IllegalArgumentException(
1647             rtl::OUString::createFromAscii( "invalid argument type" ),
1648             static_cast<XFilePicker2*>( this ), 1 );
1649 
1650     sal_Int16 templateId = -1;
1651     aAny >>= templateId;
1652 
1653     GtkFileChooserAction eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1654     const gchar *first_button_text = GTK_STOCK_OPEN;
1655 
1656 
1657     //   TODO: extract full semantic from
1658     //   svtools/source/filepicker/filepicker.cxx (getWinBits)
1659     switch( templateId )
1660     {
1661         case FILEOPEN_SIMPLE:
1662             eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1663             first_button_text = GTK_STOCK_OPEN;
1664             OSL_TRACE( "3all true\n" );
1665             break;
1666         case FILESAVE_SIMPLE:
1667             eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1668             first_button_text = GTK_STOCK_SAVE;
1669             OSL_TRACE( "2all true\n" );
1670                 break;
1671         case FILESAVE_AUTOEXTENSION_PASSWORD:
1672             eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1673             first_button_text = GTK_STOCK_SAVE;
1674             mbToggleVisibility[PASSWORD] = true;
1675             OSL_TRACE( "1all true\n" );
1676             // TODO
1677             break;
1678         case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
1679             eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1680             first_button_text = GTK_STOCK_SAVE;
1681             mbToggleVisibility[PASSWORD] = true;
1682             mbToggleVisibility[FILTEROPTIONS] = true;
1683             OSL_TRACE( "4all true\n" );
1684             // TODO
1685                 break;
1686         case FILESAVE_AUTOEXTENSION_SELECTION:
1687             eAction = GTK_FILE_CHOOSER_ACTION_SAVE; // SELECT_FOLDER ?
1688             first_button_text = GTK_STOCK_SAVE;
1689             mbToggleVisibility[SELECTION] = true;
1690             OSL_TRACE( "5all true\n" );
1691             // TODO
1692                 break;
1693         case FILESAVE_AUTOEXTENSION_TEMPLATE:
1694             eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1695             first_button_text = GTK_STOCK_SAVE;
1696             mbListVisibility[TEMPLATE] = true;
1697             OSL_TRACE( "6all true\n" );
1698             // TODO
1699                 break;
1700         case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
1701             eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1702             first_button_text = GTK_STOCK_OPEN;
1703             mbToggleVisibility[LINK] = true;
1704             mbToggleVisibility[PREVIEW] = true;
1705             mbListVisibility[IMAGE_TEMPLATE] = true;
1706             // TODO
1707                 break;
1708         case FILEOPEN_PLAY:
1709             eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1710             first_button_text = GTK_STOCK_OPEN;
1711             mbButtonVisibility[PLAY] = true;
1712             // TODO
1713                 break;
1714         case FILEOPEN_READONLY_VERSION:
1715             eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1716             first_button_text = GTK_STOCK_OPEN;
1717             mbToggleVisibility[READONLY] = true;
1718             mbListVisibility[VERSION] = true;
1719             break;
1720         case FILEOPEN_LINK_PREVIEW:
1721             eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1722             first_button_text = GTK_STOCK_OPEN;
1723             mbToggleVisibility[LINK] = true;
1724             mbToggleVisibility[PREVIEW] = true;
1725             // TODO
1726                 break;
1727         case FILESAVE_AUTOEXTENSION:
1728             eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1729             first_button_text = GTK_STOCK_SAVE;
1730             OSL_TRACE( "7all true\n" );
1731             // TODO
1732                 break;
1733         default:
1734                 throw lang::IllegalArgumentException(
1735                 rtl::OUString::createFromAscii( "Unknown template" ),
1736                 static_cast< XFilePicker2* >( this ),
1737                 1 );
1738     }
1739 
1740     GdkThreadLock aLock;
1741 
1742     if( GTK_FILE_CHOOSER_ACTION_SAVE == eAction )
1743     {
1744         CResourceProvider aResProvider;
1745         OUString aFilePickerTitle(aResProvider.getResString( FILE_PICKER_TITLE_SAVE ));
1746         gtk_window_set_title ( GTK_WINDOW( m_pDialog ),
1747             OUStringToOString( aFilePickerTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
1748     }
1749 
1750     gtk_file_chooser_set_action( GTK_FILE_CHOOSER( m_pDialog ), eAction);
1751     dialog_remove_buttons( GTK_DIALOG( m_pDialog ) );
1752     gtk_dialog_add_button( GTK_DIALOG( m_pDialog ), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL );
1753     for( int nTVIndex = 0; nTVIndex < BUTTON_LAST; nTVIndex++ )
1754     {
1755         if( mbButtonVisibility[nTVIndex] )
1756         {
1757 #ifdef GTK_STOCK_MEDIA_PLAY
1758             m_pButtons[ nTVIndex ] = gtk_dialog_add_button( GTK_DIALOG( m_pDialog ), GTK_STOCK_MEDIA_PLAY, 1 );
1759 #else
1760             CResourceProvider aResProvider;
1761             OString aPlay = OUStringToOString( aResProvider.getResString( PUSHBUTTON_PLAY ), RTL_TEXTENCODING_UTF8 );
1762             m_pButtons[ nTVIndex ] = gtk_dialog_add_button( GTK_DIALOG( m_pDialog ), aPlay.getStr(), 1 );
1763 #endif
1764         }
1765     }
1766     gtk_dialog_add_button( GTK_DIALOG( m_pDialog ), first_button_text, GTK_RESPONSE_ACCEPT );
1767 
1768     gtk_dialog_set_default_response( GTK_DIALOG (m_pDialog), GTK_RESPONSE_ACCEPT );
1769 
1770     // Setup special flags
1771     for( int nTVIndex = 0; nTVIndex < TOGGLE_LAST; nTVIndex++ )
1772     {
1773         if( mbToggleVisibility[nTVIndex] )
1774             gtk_widget_show( m_pToggles[ nTVIndex ] );
1775     }
1776 
1777     for( int nTVIndex = 0; nTVIndex < LIST_LAST; nTVIndex++ )
1778     {
1779         if( mbListVisibility[nTVIndex] )
1780         {
1781             gtk_widget_set_sensitive( m_pLists[ nTVIndex ], false );
1782             gtk_widget_show( m_pLists[ nTVIndex ] );
1783             gtk_widget_show( m_pListLabels[ nTVIndex ] );
1784             gtk_widget_show( m_pAligns[ nTVIndex ] );
1785             gtk_widget_show( m_pHBoxs[ nTVIndex ] );
1786         }
1787     }
1788 }
1789 
1790 void SalGtkFilePicker::preview_toggled_cb( GtkObject *cb, SalGtkFilePicker* pobjFP )
1791 {
1792     if( pobjFP->mbToggleVisibility[PREVIEW] )
1793         pobjFP->setShowState( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( cb ) ) );
1794 }
1795 
1796 //------------------------------------------------------------------------------------
1797 // XCancellable
1798 //------------------------------------------------------------------------------------
1799 
1800 void SAL_CALL SalGtkFilePicker::cancel() throw( uno::RuntimeException )
1801 {
1802     OSL_ASSERT( m_pDialog != NULL );
1803 
1804     // TODO m_pImpl->cancel();
1805 }
1806 
1807 // -------------------------------------------------
1808 // XServiceInfo
1809 // -------------------------------------------------
1810 
1811 rtl::OUString SAL_CALL SalGtkFilePicker::getImplementationName()
1812     throw( uno::RuntimeException )
1813 {
1814     return rtl::OUString::createFromAscii( FILE_PICKER_IMPL_NAME );
1815 }
1816 
1817 // -------------------------------------------------
1818 //  XServiceInfo
1819 // -------------------------------------------------
1820 
1821 sal_Bool SAL_CALL SalGtkFilePicker::supportsService( const rtl::OUString& ServiceName )
1822     throw( uno::RuntimeException )
1823 {
1824     uno::Sequence <rtl::OUString> SupportedServicesNames = FilePicker_getSupportedServiceNames();
1825 
1826     for( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
1827         if( SupportedServicesNames[n].compareTo( ServiceName ) == 0)
1828             return sal_True;
1829 
1830     return sal_False;
1831 }
1832 
1833 // -------------------------------------------------
1834 //  XServiceInfo
1835 // -------------------------------------------------
1836 
1837 uno::Sequence<rtl::OUString> SAL_CALL SalGtkFilePicker::getSupportedServiceNames()
1838     throw( uno::RuntimeException )
1839 {
1840     return FilePicker_getSupportedServiceNames();
1841 }
1842 
1843 
1844 //--------------------------------------------------
1845 // Misc
1846 //-------------------------------------------------
1847 void SalGtkFilePicker::SetCurFilter( const OUString& rFilter )
1848 {
1849     GdkThreadLock aLock;
1850 
1851     // Get all the filters already added
1852     GSList *filters = gtk_file_chooser_list_filters ( GTK_FILE_CHOOSER( m_pDialog ) );
1853     bool bFound = false;
1854 
1855     for( GSList *iter = filters; !bFound && iter; iter = iter->next )
1856     {
1857         GtkFileFilter* pFilter = reinterpret_cast<GtkFileFilter *>( iter->data );
1858         G_CONST_RETURN gchar * filtername = gtk_file_filter_get_name( pFilter );
1859         OUString sFilterName( filtername, strlen( filtername ), RTL_TEXTENCODING_UTF8 );
1860 
1861         OUString aShrunkName = shrinkFilterName( rFilter );
1862         if( aShrunkName.equals( sFilterName) )
1863         {
1864             OSL_TRACE( "actually setting %s\n", filtername );
1865             gtk_file_chooser_set_filter( GTK_FILE_CHOOSER( m_pDialog ), pFilter );
1866             bFound = true;
1867         }
1868     }
1869 
1870     g_slist_free( filters );
1871 }
1872 
1873 extern "C"
1874 {
1875 static gboolean
1876 case_insensitive_filter (const GtkFileFilterInfo *filter_info, gpointer data)
1877 {
1878     gboolean bRetval = sal_False;
1879     const char *pFilter = (const char *) data;
1880 
1881     g_return_val_if_fail( data != NULL, sal_False );
1882     g_return_val_if_fail( filter_info != NULL, sal_False );
1883 
1884     if( !filter_info->uri )
1885         return sal_False;
1886 
1887     const char *pExtn = strrchr( filter_info->uri, '.' );
1888     if( !pExtn )
1889         return sal_False;
1890     pExtn++;
1891 
1892     if( !g_ascii_strcasecmp( pFilter, pExtn ) )
1893         bRetval = sal_True;
1894 
1895 #ifdef DEBUG
1896     fprintf( stderr, "'%s' match extn '%s' vs '%s' yeilds %d\n",
1897         filter_info->uri, pExtn, pFilter, bRetval );
1898 #endif
1899 
1900     return bRetval;
1901 }
1902 }
1903 
1904 GtkFileFilter* SalGtkFilePicker::implAddFilter( const OUString& rFilter, const OUString& rType )
1905 {
1906     GdkThreadLock aLock;
1907 
1908     GtkFileFilter *filter = gtk_file_filter_new();
1909 
1910     OUString aShrunkName = shrinkFilterName( rFilter );
1911     OString aFilterName = rtl::OUStringToOString( aShrunkName, RTL_TEXTENCODING_UTF8 );
1912     gtk_file_filter_set_name( filter, aFilterName );
1913 
1914     static const OUString aStarDot = OUString::createFromAscii( "*." );
1915     OUString aTokens;
1916 
1917     bool bAllGlob = !rType.compareToAscii( "*.*" ) || !rType.compareToAscii( "*" );
1918     if (bAllGlob)
1919         gtk_file_filter_add_pattern( filter, "*" );
1920     else
1921     {
1922         sal_Int32 nIndex = 0;
1923         rtl::OUString aToken;
1924         do
1925         {
1926             aToken = rType.getToken( 0, ';', nIndex );
1927             // Assume all have the "*.<extn>" syntax
1928             aToken = aToken.copy( aToken.lastIndexOf( aStarDot ) + 2 );
1929             if (aToken.getLength())
1930             {
1931                 if (aTokens.getLength())
1932                     aTokens += OUString::createFromAscii(",");
1933                 aTokens = aTokens += aToken;
1934                 gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_URI,
1935                     case_insensitive_filter,
1936                     g_strdup( rtl::OUStringToOString( aToken, RTL_TEXTENCODING_UTF8 ) ),
1937                     (GDestroyNotify) g_free );
1938 
1939                 OSL_TRACE( "fustering with %s\n", rtl::OUStringToOString( aToken, RTL_TEXTENCODING_UTF8 ).getStr());
1940             }
1941 #ifdef DEBUG
1942             else
1943             {
1944                 g_warning( "Duff filter token '%s'\n",
1945                     (const sal_Char *) rtl::OUStringToOString(
1946                         rType.getToken( 0, ';', nIndex ), RTL_TEXTENCODING_UTF8 ) );
1947             }
1948 #endif
1949         }
1950         while( nIndex >= 0 );
1951     }
1952 
1953     gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( m_pDialog ), filter );
1954 
1955     if (!bAllGlob)
1956     {
1957         GtkTreeIter iter;
1958         gtk_list_store_append (m_pFilterStore, &iter);
1959         gtk_list_store_set (m_pFilterStore, &iter,
1960             0, OUStringToOString(shrinkFilterName( rFilter, true ), RTL_TEXTENCODING_UTF8).getStr(),
1961             1, OUStringToOString(aTokens, RTL_TEXTENCODING_UTF8).getStr(),
1962             2, aFilterName.getStr(),
1963             3, OUStringToOString(rType, RTL_TEXTENCODING_UTF8).getStr(),
1964             -1);
1965     }
1966     return filter;
1967 }
1968 
1969 void SalGtkFilePicker::implAddFilterGroup( const OUString& /*_rFilter*/, const Sequence< StringPair >& _rFilters )
1970 {
1971     // Gtk+ has no filter group concept I think so ...
1972     // implAddFilter( _rFilter, String() );
1973     const StringPair* pSubFilters   = _rFilters.getConstArray();
1974     const StringPair* pSubFiltersEnd = pSubFilters + _rFilters.getLength();
1975     for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters )
1976         implAddFilter( pSubFilters->First, pSubFilters->Second );
1977 }
1978 
1979 void SalGtkFilePicker::SetFilters()
1980 {
1981     GdkThreadLock aLock;
1982 
1983     if (!m_aInitialFilter.getLength())
1984         m_aInitialFilter = m_aCurrentFilter;
1985 
1986     rtl::OUString sPseudoFilter;
1987     if( GTK_FILE_CHOOSER_ACTION_SAVE == gtk_file_chooser_get_action( GTK_FILE_CHOOSER( m_pDialog ) ) )
1988     {
1989         std::set<OUString> aAllFormats;
1990         if( m_pFilterList && !m_pFilterList->empty() )
1991         {
1992             for (   FilterList::iterator aListIter = m_pFilterList->begin();
1993                     aListIter != m_pFilterList->end();
1994                     ++aListIter
1995                 )
1996             {
1997                 if( aListIter->hasSubFilters() )
1998                 {   // it's a filter group
1999                     UnoFilterList aSubFilters;
2000                     aListIter->getSubFilters( aSubFilters );
2001                     const StringPair* pSubFilters   = aSubFilters.getConstArray();
2002                     const StringPair* pSubFiltersEnd = pSubFilters + aSubFilters.getLength();
2003                     for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters )
2004                         aAllFormats.insert(pSubFilters->Second);
2005                 }
2006                 else
2007                     aAllFormats.insert(aListIter->getFilter());
2008             }
2009         }
2010         if (aAllFormats.size() > 1)
2011         {
2012             rtl::OUString sAllFilter;
2013             std::set<OUString>::const_iterator aEnd = aAllFormats.end();
2014             for (std::set<OUString>::const_iterator aIter = aAllFormats.begin(); aIter != aEnd; ++aIter)
2015             {
2016                 if (sAllFilter.getLength())
2017                     sAllFilter += OUString(sal_Unicode(';'));
2018                 sAllFilter += *aIter;
2019             }
2020             CResourceProvider aResProvider;
2021             sPseudoFilter = aResProvider.getResString(FILE_PICKER_ALLFORMATS);
2022             m_pPseudoFilter = implAddFilter( sPseudoFilter, sAllFilter );
2023         }
2024     }
2025 
2026     if( m_pFilterList && !m_pFilterList->empty() )
2027     {
2028         for (   FilterList::iterator aListIter = m_pFilterList->begin();
2029                 aListIter != m_pFilterList->end();
2030                 ++aListIter
2031             )
2032         {
2033             if( aListIter->hasSubFilters() )
2034             {   // it's a filter group
2035 
2036                 UnoFilterList aSubFilters;
2037                 aListIter->getSubFilters( aSubFilters );
2038 
2039                 implAddFilterGroup( aListIter->getTitle(), aSubFilters );
2040             }
2041             else
2042             {
2043                 // it's a single filter
2044 
2045                 implAddFilter( aListIter->getTitle(), aListIter->getFilter() );
2046             }
2047         }
2048     }
2049 
2050     if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(m_pFilterStore), NULL)) //If m_pFilterStore is not empty
2051         gtk_widget_show( m_pFilterExpander );
2052     else
2053         gtk_widget_hide( m_pFilterExpander );
2054 
2055     // set the default filter
2056     if (sPseudoFilter.getLength())
2057         SetCurFilter( sPseudoFilter );
2058     else if(m_aCurrentFilter.getLength())
2059         SetCurFilter( m_aCurrentFilter );
2060 
2061     OSL_TRACE( "end setting filters\n");
2062 }
2063 
2064 SalGtkFilePicker::~SalGtkFilePicker()
2065 {
2066     int i;
2067 
2068     for( i = 0; i < TOGGLE_LAST; i++ )
2069         gtk_widget_destroy( m_pToggles[i] );
2070 
2071     for( i = 0; i < LIST_LAST; i++ )
2072     {
2073         gtk_widget_destroy( m_pListLabels[i] );
2074         gtk_widget_destroy( m_pAligns[i] ); //m_pAligns[i] owns m_pLists[i]
2075         gtk_widget_destroy( m_pHBoxs[i] );
2076     }
2077 
2078     delete m_pFilterList;
2079 
2080     gtk_widget_destroy( m_pVBox );
2081 }
2082 
2083 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
2084