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