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