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