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