xref: /AOO41X/main/fpicker/source/unx/gnome/SalGtkFilePicker.cxx (revision 24c56ab9f1bd1305754aa2f564704f38ff57627e)
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     // controling event notifications
77     const bool STARTUP_SUSPENDED = true;
78     const bool STARTUP_ALIVE     = false;
79 
FilePicker_getSupportedServiceNames()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 
expandexpanders(GtkContainer * pWidget)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 
dialog_mapped_cb(GtkWidget *,SalGtkFilePicker * pobjFP)109 void SalGtkFilePicker::dialog_mapped_cb(GtkWidget *, SalGtkFilePicker *pobjFP)
110 {
111     pobjFP->InitialMapping();
112 }
113 
InitialMapping()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 
SalGtkFilePicker(const uno::Reference<lang::XMultiServiceFactory> & xServiceMgr)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 
addFilePickerListener(const uno::Reference<XFilePickerListener> & xListener)354 void SAL_CALL SalGtkFilePicker::addFilePickerListener( const uno::Reference<XFilePickerListener>& xListener )
355     throw( uno::RuntimeException )
356 {
357     m_xListener = xListener;
358 }
359 
removeFilePickerListener(const uno::Reference<XFilePickerListener> &)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 
disposing(const lang::EventObject & aEvent)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 
fileSelectionChanged(FilePickerEvent aEvent)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 
directoryChanged(FilePickerEvent aEvent)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 
controlStateChanged(FilePickerEvent aEvent)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 
helpRequested(FilePickerEvent aEvent) const404 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:
FilterEntryFilterEntry457     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 
getTitleFilterEntry465     ::rtl::OUString     getTitle() const { return m_sTitle; }
getFilterFilterEntry466     ::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
beginSubFiltersFilterEntry478     const UnoFilterEntry*   beginSubFilters() const { return m_aSubFilters.getConstArray(); }
endSubFiltersFilterEntry479     const UnoFilterEntry*   endSubFilters() const { return m_aSubFilters.getConstArray() + m_aSubFilters.getLength(); }
480 };
481 
482 //=====================================================================
483 
484 //---------------------------------------------------------------------
FilterEntry(const::rtl::OUString & _rTitle,const UnoFilterList & _rSubFilters)485 FilterEntry::FilterEntry( const ::rtl::OUString& _rTitle, const UnoFilterList& _rSubFilters )
486     :m_sTitle( _rTitle )
487     ,m_aSubFilters( _rSubFilters )
488 {
489 }
490 
491 //---------------------------------------------------------------------
hasSubFilters() const492 sal_Bool FilterEntry::hasSubFilters() const
493 {
494     return( 0 < m_aSubFilters.getLength() );
495 }
496 
497 //---------------------------------------------------------------------
getSubFilters(UnoFilterList & _rSubFilterList)498 sal_Int32 FilterEntry::getSubFilters( UnoFilterList& _rSubFilterList )
499 {
500     _rSubFilterList = m_aSubFilters;
501     return m_aSubFilters.getLength();
502 }
503 
504 static bool
isFilterString(const rtl::OUString & rFilterString,const char * pMatch)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
shrinkFilterName(const rtl::OUString & rFilterName,bool bAllowNoStar=false)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
dialog_remove_buttons(GtkDialog * pDialog)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:
FilterTitleMatch__anon08addf850211::FilterTitleMatch583         FilterTitleMatch( const ::rtl::OUString& _rTitle ) : rTitle( _rTitle ) { }
584 
585         //............................................................................
operator ()__anon08addf850211::FilterTitleMatch586         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         }
operator ()__anon08addf850211::FilterTitleMatch603         bool operator () ( const UnoFilterEntry& _rEntry )
604         {
605             OUString aShrunkName = shrinkFilterName( _rEntry.First );
606             return aShrunkName == rTitle ? true : false;
607         }
608     };
609 }
610 
611 
612 //------------------------------------------------------------------------------------
FilterNameExists(const::rtl::OUString & rTitle)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 //------------------------------------------------------------------------------------
FilterNameExists(const UnoFilterList & _rGroupedFilters)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 //------------------------------------------------------------------------------------
ensureFilterList(const::rtl::OUString & _rInitialCurrentFilter)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 
appendFilter(const rtl::OUString & aTitle,const rtl::OUString & aFilter)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 
setCurrentFilter(const rtl::OUString & aTitle)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 
updateCurrentFilterFromName(const gchar * filtername)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 
UpdateFilterfromUI()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 
getCurrentFilter()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 
appendFilterGroup(const rtl::OUString &,const uno::Sequence<beans::StringPair> & aFilters)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 
setMultiSelectionMode(sal_Bool bMode)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 
setDefaultName(const rtl::OUString & aName)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 
setDisplayDirectory(const rtl::OUString & rDirectory)826 void SAL_CALL SalGtkFilePicker::setDisplayDirectory( const rtl::OUString& rDirectory )
827     throw( lang::IllegalArgumentException, uno::RuntimeException )
828 {
829     implsetDisplayDirectory(rDirectory);
830 }
831 
getDisplayDirectory()832 rtl::OUString SAL_CALL SalGtkFilePicker::getDisplayDirectory() throw( uno::RuntimeException )
833 {
834     return implgetDisplayDirectory();
835 }
836 
getFiles()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 
getSelectedFiles()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 
setTitle(const rtl::OUString & rTitle)996 void SAL_CALL SalGtkFilePicker::setTitle( const rtl::OUString& rTitle ) throw( uno::RuntimeException )
997 {
998     implsetTitle(rTitle);
999 }
1000 
execute()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                                   OUStringToOString(
1051                                     aResProvider.getResString( FILE_PICKER_OVERWRITE ),
1052                                     RTL_TEXTENCODING_UTF8 ).getStr() );
1053 
1054                             gtk_window_set_title( GTK_WINDOW( dlg ),
1055                                 OUStringToOString(aResProvider.getResString(FILE_PICKER_TITLE_SAVE ),
1056                                 RTL_TEXTENCODING_UTF8 ).getStr() );
1057 
1058                             RunDialog* pAnotherDialog = new RunDialog(dlg, xToolkit);
1059                             uno::Reference < awt::XTopWindowListener > xAnotherLifeCycle(pAnotherDialog);
1060                             btn = pAnotherDialog->run();
1061 
1062                             gtk_widget_destroy( dlg );
1063                         }
1064 
1065                         if( btn == GTK_RESPONSE_YES )
1066                             retVal = ExecutableDialogResults::OK;
1067                     }
1068                 }
1069                 else
1070                     retVal = ExecutableDialogResults::OK;
1071                 break;
1072 
1073             case GTK_RESPONSE_CANCEL:
1074                 retVal = ExecutableDialogResults::CANCEL;
1075                 break;
1076 
1077             case 1: //PLAY
1078                 {
1079                     FilePickerEvent evt;
1080                     evt.ElementId = PUSHBUTTON_PLAY;
1081                     OSL_TRACE( "filter_changed, isn't it great %x\n", this);
1082                     controlStateChanged( evt );
1083                     btn = GTK_RESPONSE_NO;
1084                 }
1085                 break;
1086 
1087             default:
1088                 retVal = 0;
1089                 break;
1090         }
1091     }
1092 
1093     if (mnHID_FolderChange)
1094         g_signal_handler_disconnect(GTK_FILE_CHOOSER( m_pDialog ), mnHID_FolderChange);
1095     if (mnHID_SelectionChange)
1096         g_signal_handler_disconnect(GTK_FILE_CHOOSER( m_pDialog ), mnHID_SelectionChange);
1097 
1098     return retVal;
1099 }
1100 
1101 //------------------------------------------------------------------------------------
1102 
1103 // cf. offapi/com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.idl
getWidget(sal_Int16 nControlId,GType * pType)1104 GtkWidget *SalGtkFilePicker::getWidget( sal_Int16 nControlId, GType *pType )
1105 {
1106     OSL_TRACE("control id is %d", nControlId);
1107     GType      tType = GTK_TYPE_TOGGLE_BUTTON; //prevent waring by initializing
1108     GtkWidget *pWidget = 0;
1109 
1110 #define MAP_TOGGLE( elem ) \
1111         case ExtendedFilePickerElementIds::CHECKBOX_##elem: \
1112             pWidget = m_pToggles[elem]; tType = GTK_TYPE_TOGGLE_BUTTON; \
1113             break
1114 #define MAP_BUTTON( elem ) \
1115         case ExtendedFilePickerElementIds::PUSHBUTTON_##elem: \
1116             pWidget = m_pButtons[elem]; tType = GTK_TYPE_BUTTON; \
1117             break
1118 #define MAP_LIST( elem ) \
1119         case ExtendedFilePickerElementIds::LISTBOX_##elem: \
1120             pWidget = m_pLists[elem]; tType = GTK_TYPE_COMBO_BOX; \
1121             break
1122 #define MAP_LIST_LABEL( elem ) \
1123         case ExtendedFilePickerElementIds::LISTBOX_##elem##_LABEL: \
1124             pWidget = m_pListLabels[elem]; tType = GTK_TYPE_LABEL; \
1125             break
1126 
1127     switch( nControlId )
1128     {
1129         MAP_TOGGLE( AUTOEXTENSION );
1130         MAP_TOGGLE( PASSWORD );
1131         MAP_TOGGLE( FILTEROPTIONS );
1132         MAP_TOGGLE( READONLY );
1133         MAP_TOGGLE( LINK );
1134         MAP_TOGGLE( PREVIEW );
1135         MAP_TOGGLE( SELECTION );
1136         MAP_BUTTON( PLAY );
1137         MAP_LIST( VERSION );
1138         MAP_LIST( TEMPLATE );
1139         MAP_LIST( IMAGE_TEMPLATE );
1140         MAP_LIST_LABEL( VERSION );
1141         MAP_LIST_LABEL( TEMPLATE );
1142         MAP_LIST_LABEL( IMAGE_TEMPLATE );
1143     default:
1144         OSL_TRACE("Handle unknown control %d\n", nControlId);
1145         break;
1146     }
1147 #undef MAP
1148 
1149     if( pType )
1150         *pType = tType;
1151     return pWidget;
1152 }
1153 
1154 
1155 
1156 //------------------------------------------------------------------------------------
1157 // XFilePickerControlAccess functions
1158 //------------------------------------------------------------------------------------
1159 namespace
1160 {
HackWidthToFirst(GtkComboBox * pWidget)1161     void HackWidthToFirst(GtkComboBox *pWidget)
1162     {
1163         GdkThreadLock aLock;
1164 
1165         GtkRequisition requisition;
1166         gtk_widget_size_request(GTK_WIDGET(pWidget), &requisition);
1167         gtk_widget_set_size_request(GTK_WIDGET(pWidget), requisition.width, -1);
1168     }
1169 }
1170 
HandleSetListValue(GtkComboBox * pWidget,sal_Int16 nControlAction,const uno::Any & rValue)1171 void SalGtkFilePicker::HandleSetListValue(GtkComboBox *pWidget, sal_Int16 nControlAction, const uno::Any& rValue)
1172 {
1173     GdkThreadLock aLock;
1174 
1175     switch (nControlAction)
1176     {
1177         case ControlActions::ADD_ITEM:
1178             {
1179                 OUString sItem;
1180                 rValue >>= sItem;
1181                 gtk_combo_box_append_text(pWidget, rtl::OUStringToOString(sItem, RTL_TEXTENCODING_UTF8).getStr());
1182                 if (!bVersionWidthUnset)
1183                 {
1184                     HackWidthToFirst(pWidget);
1185                     bVersionWidthUnset = true;
1186                 }
1187             }
1188             break;
1189         case ControlActions::ADD_ITEMS:
1190             {
1191                 Sequence< OUString > aStringList;
1192                 rValue >>= aStringList;
1193                 sal_Int32 nItemCount = aStringList.getLength();
1194                 for (sal_Int32 i = 0; i < nItemCount; ++i)
1195                 {
1196                     gtk_combo_box_append_text(pWidget,
1197                         rtl::OUStringToOString(aStringList[i], RTL_TEXTENCODING_UTF8).getStr());
1198                     if (!bVersionWidthUnset)
1199                     {
1200                         HackWidthToFirst(pWidget);
1201                         bVersionWidthUnset = true;
1202                     }
1203                 }
1204             }
1205             break;
1206         case ControlActions::DELETE_ITEM:
1207             {
1208                 sal_Int32 nPos=0;
1209                 rValue >>= nPos;
1210                 gtk_combo_box_remove_text(pWidget, nPos);
1211             }
1212             break;
1213         case ControlActions::DELETE_ITEMS:
1214             {
1215                 gtk_combo_box_set_active(pWidget, -1);
1216                 gint nItems = 0;
1217                 do
1218                 {
1219                         nItems =
1220                                 gtk_tree_model_iter_n_children(
1221                                   gtk_combo_box_get_model(pWidget), NULL);
1222                         for (gint nI = 0; nI < nItems; ++nI)
1223                             gtk_combo_box_remove_text(pWidget, nI);
1224                 }
1225                 while (nItems);
1226             }
1227             break;
1228         case ControlActions::SET_SELECT_ITEM:
1229             {
1230                 sal_Int32 nPos=0;
1231                 rValue >>= nPos;
1232                 gtk_combo_box_set_active(pWidget, nPos);
1233             }
1234             break;
1235         default:
1236             OSL_TRACE("undocumented/unimplemented ControlAction for a list");
1237             break;
1238     }
1239 
1240     //I think its best to make it insensitive unless there is the chance to
1241     //actually select something from the list.
1242     gint nItems = gtk_tree_model_iter_n_children(
1243                     gtk_combo_box_get_model(pWidget), NULL);
1244     gtk_widget_set_sensitive(GTK_WIDGET(pWidget), nItems > 1 ? true : false);
1245 }
1246 
HandleGetListValue(GtkComboBox * pWidget,sal_Int16 nControlAction) const1247 uno::Any SalGtkFilePicker::HandleGetListValue(GtkComboBox *pWidget, sal_Int16 nControlAction) const
1248 {
1249     GdkThreadLock aLock;
1250 
1251     uno::Any aAny;
1252     switch (nControlAction)
1253     {
1254         case ControlActions::GET_ITEMS:
1255             {
1256                 Sequence< OUString > aItemList;
1257 
1258                 GtkTreeModel *pTree = gtk_combo_box_get_model(pWidget);
1259                 GtkTreeIter iter;
1260                 if (gtk_tree_model_get_iter_first(pTree, &iter))
1261                 {
1262                     sal_Int32 nSize = gtk_tree_model_iter_n_children(
1263                         pTree, NULL);
1264 
1265                     aItemList.realloc(nSize);
1266                     for (sal_Int32 i=0; i < nSize; ++i)
1267                     {
1268                         gchar *item;
1269                         gtk_tree_model_get(gtk_combo_box_get_model(pWidget),
1270                             &iter, 0, &item, -1);
1271                         aItemList[i] = OUString(item, strlen(item), RTL_TEXTENCODING_UTF8);
1272                         g_free(item);
1273                         gtk_tree_model_iter_next(pTree, &iter);
1274                     }
1275                 }
1276                 aAny <<= aItemList;
1277             }
1278             break;
1279         case ControlActions::GET_SELECTED_ITEM:
1280             {
1281                 GtkTreeIter iter;
1282                 if (gtk_combo_box_get_active_iter(pWidget, &iter))
1283                 {
1284                         gchar *item;
1285                         gtk_tree_model_get(gtk_combo_box_get_model(pWidget),
1286                             &iter, 0, &item, -1);
1287                         OUString sItem(item, strlen(item), RTL_TEXTENCODING_UTF8);
1288                         aAny <<= sItem;
1289                         g_free(item);
1290                 }
1291             }
1292             break;
1293         case ControlActions::GET_SELECTED_ITEM_INDEX:
1294             {
1295                 gint nActive = gtk_combo_box_get_active(pWidget);
1296                 aAny <<= static_cast< sal_Int32 >(nActive);
1297             }
1298             break;
1299         default:
1300             OSL_TRACE("undocumented/unimplemented ControlAction for a list");
1301             break;
1302     }
1303     return aAny;
1304 }
1305 
setValue(sal_Int16 nControlId,sal_Int16 nControlAction,const uno::Any & rValue)1306 void SAL_CALL SalGtkFilePicker::setValue( sal_Int16 nControlId, sal_Int16 nControlAction, const uno::Any& rValue )
1307     throw( uno::RuntimeException )
1308 {
1309     OSL_ASSERT( m_pDialog != NULL );
1310 
1311     OSL_TRACE( "SETTING VALUE %d\n", nControlAction );
1312     GType tType;
1313     GtkWidget *pWidget;
1314 
1315     GdkThreadLock aLock;
1316 
1317     if( !( pWidget = getWidget( nControlId, &tType ) ) )
1318         OSL_TRACE("enable unknown control %d\n", nControlId);
1319     else if( tType == GTK_TYPE_TOGGLE_BUTTON )
1320     {
1321         sal_Bool bChecked = false;
1322         rValue >>= bChecked;
1323         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( pWidget ), bChecked );
1324     }
1325     else if( tType == GTK_TYPE_COMBO_BOX )
1326         HandleSetListValue(GTK_COMBO_BOX(pWidget), nControlAction, rValue);
1327     else
1328     {
1329         OSL_TRACE("Can't set value on button / list %d %d\n",
1330             nControlId, nControlAction);
1331     }
1332 }
1333 
getValue(sal_Int16 nControlId,sal_Int16 nControlAction)1334 uno::Any SAL_CALL SalGtkFilePicker::getValue( sal_Int16 nControlId, sal_Int16 nControlAction )
1335     throw( uno::RuntimeException )
1336 {
1337     OSL_ASSERT( m_pDialog != NULL );
1338 
1339     uno::Any aRetval;
1340 
1341     GType tType;
1342     GtkWidget *pWidget;
1343 
1344     GdkThreadLock aLock;
1345 
1346     if( !( pWidget = getWidget( nControlId, &tType ) ) )
1347         OSL_TRACE("enable unknown control %d\n", nControlId);
1348     else if( tType == GTK_TYPE_TOGGLE_BUTTON )
1349         aRetval <<= (sal_Bool) gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( pWidget ) );
1350     else if( tType == GTK_TYPE_COMBO_BOX )
1351         aRetval = HandleGetListValue(GTK_COMBO_BOX(pWidget), nControlAction);
1352     else
1353         OSL_TRACE("Can't get value on button / list %d %d\n",
1354             nControlId, nControlAction );
1355 
1356     return aRetval;
1357 }
1358 
enableControl(sal_Int16 nControlId,sal_Bool bEnable)1359 void SAL_CALL SalGtkFilePicker::enableControl( sal_Int16 nControlId, sal_Bool bEnable )
1360 throw( uno::RuntimeException )
1361 {
1362     OSL_ASSERT( m_pDialog != NULL );
1363 
1364     GtkWidget *pWidget;
1365 
1366     GdkThreadLock aLock;
1367 
1368     if ( nControlId == ExtendedFilePickerElementIds::LISTBOX_FILTER_SELECTOR )
1369         gtk_expander_set_expanded( GTK_EXPANDER( m_pFilterExpander ), bEnable );
1370     else if( ( pWidget = getWidget( nControlId ) ) )
1371     {
1372         if( bEnable )
1373         {
1374             OSL_TRACE( "enable\n" );
1375             gtk_widget_set_sensitive( pWidget, sal_True );
1376         }
1377         else
1378         {
1379             OSL_TRACE( "disable\n" );
1380             gtk_widget_set_sensitive( pWidget, sal_False );
1381         }
1382     }
1383     else
1384         OSL_TRACE("enable unknown control %d\n", nControlId );
1385 }
1386 
setLabel(sal_Int16 nControlId,const::rtl::OUString & rLabel)1387 void SAL_CALL SalGtkFilePicker::setLabel( sal_Int16 nControlId, const ::rtl::OUString& rLabel )
1388     throw( uno::RuntimeException )
1389 {
1390     OSL_ASSERT( m_pDialog != NULL );
1391 
1392     GType tType;
1393     GtkWidget *pWidget;
1394 
1395     GdkThreadLock aLock;
1396 
1397     if( !( pWidget = getWidget( nControlId, &tType ) ) )
1398     {
1399         OSL_TRACE("Set label on unknown control %d\n", nControlId);
1400         return;
1401     }
1402 
1403     OString aTxt = OUStringToOString( rLabel.replace('~', '_'), RTL_TEXTENCODING_UTF8 );
1404     if (nControlId == ExtendedFilePickerElementIds::PUSHBUTTON_PLAY)
1405     {
1406 #ifdef GTK_STOCK_MEDIA_PLAY
1407         if (!msPlayLabel.getLength())
1408             msPlayLabel = rLabel;
1409         if (msPlayLabel == rLabel)
1410             gtk_button_set_label(GTK_BUTTON(pWidget), GTK_STOCK_MEDIA_PLAY);
1411         else
1412             gtk_button_set_label(GTK_BUTTON(pWidget), GTK_STOCK_MEDIA_STOP);
1413 #else
1414         gtk_button_set_label(GTK_BUTTON(pWidget), aTxt.getStr());
1415 #endif
1416     }
1417     else if( tType == GTK_TYPE_TOGGLE_BUTTON || tType == GTK_TYPE_BUTTON || tType == GTK_TYPE_LABEL )
1418         g_object_set( pWidget, "label", aTxt.getStr(),
1419                       "use_underline", sal_True, (char *)NULL );
1420     else
1421         OSL_TRACE("Can't set label on list\n");
1422 }
1423 
getLabel(sal_Int16 nControlId)1424 rtl::OUString SAL_CALL SalGtkFilePicker::getLabel( sal_Int16 nControlId )
1425     throw( uno::RuntimeException )
1426 {
1427     OSL_ASSERT( m_pDialog != NULL );
1428 
1429     GType tType;
1430     OString aTxt;
1431     GtkWidget *pWidget;
1432 
1433     GdkThreadLock aLock;
1434 
1435     if( !( pWidget = getWidget( nControlId, &tType ) ) )
1436         OSL_TRACE("Get label on unknown control %d\n", nControlId);
1437     else if( tType == GTK_TYPE_TOGGLE_BUTTON || tType == GTK_TYPE_BUTTON || tType == GTK_TYPE_LABEL )
1438         aTxt = gtk_button_get_label( GTK_BUTTON( pWidget ) );
1439     else
1440         OSL_TRACE("Can't get label on list\n");
1441 
1442     return OStringToOUString( aTxt, RTL_TEXTENCODING_UTF8 );
1443 }
1444 
1445 //------------------------------------------------------------------------------------
1446 // XFilePreview functions
1447 //------------------------------------------------------------------------------------
1448 
getSupportedImageFormats()1449 uno::Sequence<sal_Int16> SAL_CALL SalGtkFilePicker::getSupportedImageFormats() throw( uno::RuntimeException )
1450 {
1451     OSL_ASSERT( m_pDialog != NULL );
1452 
1453     // TODO return m_pImpl->getSupportedImageFormats();
1454     return uno::Sequence<sal_Int16>();
1455 }
1456 
getTargetColorDepth()1457 sal_Int32 SAL_CALL SalGtkFilePicker::getTargetColorDepth() throw( uno::RuntimeException )
1458 {
1459     OSL_ASSERT( m_pDialog != NULL );
1460 
1461     // TODO return m_pImpl->getTargetColorDepth();
1462     return 0;
1463 }
1464 
getAvailableWidth()1465 sal_Int32 SAL_CALL SalGtkFilePicker::getAvailableWidth() throw( uno::RuntimeException )
1466 {
1467     OSL_ASSERT( m_pDialog != NULL );
1468 
1469     return m_PreviewImageWidth;
1470 }
1471 
getAvailableHeight()1472 sal_Int32 SAL_CALL SalGtkFilePicker::getAvailableHeight() throw( uno::RuntimeException )
1473 {
1474     OSL_ASSERT( m_pDialog != NULL );
1475 
1476     return m_PreviewImageHeight;
1477 }
1478 
setImage(sal_Int16,const uno::Any &)1479 void SAL_CALL SalGtkFilePicker::setImage( sal_Int16 /*aImageFormat*/, const uno::Any& /*aImage*/ )
1480     throw( lang::IllegalArgumentException, uno::RuntimeException )
1481 {
1482     OSL_ASSERT( m_pDialog != NULL );
1483 
1484     // TODO m_pImpl->setImage( aImageFormat, aImage );
1485 }
1486 
implChangeType(GtkTreeSelection * selection)1487 void SalGtkFilePicker::implChangeType( GtkTreeSelection *selection )
1488 {
1489     CResourceProvider aResProvider;
1490     OUString aLabel = aResProvider.getResString( FILE_PICKER_FILE_TYPE );
1491 
1492     GdkThreadLock aLock;
1493 
1494     GtkTreeIter iter;
1495     GtkTreeModel *model;
1496     if (gtk_tree_selection_get_selected (selection, &model, &iter))
1497     {
1498         gchar *title;
1499         gtk_tree_model_get (model, &iter, 2, &title, -1);
1500         aLabel += rtl::OUString::createFromAscii( ": " );
1501         aLabel += rtl::OUString( title, strlen(title), RTL_TEXTENCODING_UTF8 );
1502         g_free (title);
1503     }
1504     gtk_expander_set_label (GTK_EXPANDER (m_pFilterExpander),
1505         OUStringToOString( aLabel, RTL_TEXTENCODING_UTF8 ).getStr());
1506     FilePickerEvent evt;
1507     evt.ElementId = LISTBOX_FILTER;
1508     controlStateChanged( evt );
1509 }
1510 
type_changed_cb(GtkTreeSelection * selection,SalGtkFilePicker * pobjFP)1511 void SalGtkFilePicker::type_changed_cb( GtkTreeSelection *selection, SalGtkFilePicker *pobjFP )
1512 {
1513     pobjFP->implChangeType(selection);
1514 }
1515 
unselect_type()1516 void SalGtkFilePicker::unselect_type()
1517 {
1518     GdkThreadLock aLock;
1519 
1520     gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(m_pFilterView)));
1521 }
1522 
expander_changed_cb(GtkExpander * expander,SalGtkFilePicker * pobjFP)1523 void SalGtkFilePicker::expander_changed_cb( GtkExpander *expander, SalGtkFilePicker *pobjFP )
1524 {
1525     if (gtk_expander_get_expanded(expander))
1526         pobjFP->unselect_type();
1527 }
1528 
filter_changed_cb(GtkFileChooser *,GParamSpec *,SalGtkFilePicker * pobjFP)1529 void SalGtkFilePicker::filter_changed_cb( GtkFileChooser *, GParamSpec *,
1530     SalGtkFilePicker *pobjFP )
1531 {
1532     FilePickerEvent evt;
1533     evt.ElementId = LISTBOX_FILTER;
1534     OSL_TRACE( "filter_changed, isn't it great %x\n", pobjFP );
1535     pobjFP->controlStateChanged( evt );
1536 }
1537 
folder_changed_cb(GtkFileChooser *,SalGtkFilePicker * pobjFP)1538 void SalGtkFilePicker::folder_changed_cb( GtkFileChooser *, SalGtkFilePicker *pobjFP )
1539 {
1540     FilePickerEvent evt;
1541     OSL_TRACE( "folder_changed, isn't it great %x\n", pobjFP );
1542     pobjFP->directoryChanged( evt );
1543 }
1544 
selection_changed_cb(GtkFileChooser *,SalGtkFilePicker * pobjFP)1545 void SalGtkFilePicker::selection_changed_cb( GtkFileChooser *, SalGtkFilePicker *pobjFP )
1546 {
1547     FilePickerEvent evt;
1548     OSL_TRACE( "selection_changed, isn't it great %x\n", pobjFP );
1549     pobjFP->fileSelectionChanged( evt );
1550 }
1551 
update_preview_cb(GtkFileChooser * file_chooser,SalGtkFilePicker * pobjFP)1552 void SalGtkFilePicker::update_preview_cb( GtkFileChooser *file_chooser, SalGtkFilePicker* pobjFP )
1553 {
1554     GtkWidget *preview;
1555     char *filename;
1556     GdkPixbuf *pixbuf;
1557     gboolean have_preview = sal_False;
1558 
1559     preview = pobjFP->m_pPreview;
1560     filename = gtk_file_chooser_get_preview_filename( file_chooser );
1561 
1562     if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( pobjFP->m_pToggles[PREVIEW] ) ) && g_file_test( filename, G_FILE_TEST_IS_REGULAR ) )
1563     {
1564         pixbuf = gdk_pixbuf_new_from_file_at_size(
1565                 filename,
1566                 pobjFP->m_PreviewImageWidth,
1567                 pobjFP->m_PreviewImageHeight, NULL );
1568 
1569         have_preview = ( pixbuf != NULL );
1570 
1571         gtk_image_set_from_pixbuf( GTK_IMAGE( preview ), pixbuf );
1572         if( pixbuf )
1573             gdk_pixbuf_unref( pixbuf );
1574 
1575     }
1576 
1577     gtk_file_chooser_set_preview_widget_active( file_chooser, have_preview );
1578 
1579     if( filename )
1580         g_free( filename );
1581 }
1582 
setShowState(sal_Bool bShowState)1583 sal_Bool SAL_CALL SalGtkFilePicker::setShowState( sal_Bool bShowState ) throw( uno::RuntimeException )
1584 {
1585     OSL_ASSERT( m_pDialog != NULL );
1586 
1587     // TODO return m_pImpl->setShowState( bShowState );
1588     if( bShowState != mbPreviewState )
1589     {
1590         GdkThreadLock aLock;
1591 
1592         if( bShowState )
1593         {
1594             // Show
1595             if( !mHID_Preview )
1596             {
1597                 mHID_Preview = g_signal_connect(
1598                     GTK_FILE_CHOOSER( m_pDialog ), "update-preview",
1599                     G_CALLBACK( update_preview_cb ), ( gpointer )this );
1600             }
1601             gtk_widget_show( m_pPreview );
1602         }
1603         else
1604         {
1605             // Hide
1606             gtk_widget_hide( m_pPreview );
1607         }
1608 
1609         // also emit the signal
1610         g_signal_emit_by_name( GTK_OBJECT( m_pDialog ), "update-preview" );
1611 
1612         mbPreviewState = bShowState;
1613     }
1614     return true;
1615 }
1616 
getShowState()1617 sal_Bool SAL_CALL SalGtkFilePicker::getShowState() throw( uno::RuntimeException )
1618 {
1619     OSL_ASSERT( m_pDialog != NULL );
1620 
1621     return mbPreviewState;
1622 }
1623 
1624 //------------------------------------------------------------------------------------
1625 // XInitialization
1626 //------------------------------------------------------------------------------------
1627 
initialize(const uno::Sequence<uno::Any> & aArguments)1628 void SAL_CALL SalGtkFilePicker::initialize( const uno::Sequence<uno::Any>& aArguments )
1629     throw( uno::Exception, uno::RuntimeException )
1630 {
1631     // parameter checking
1632     uno::Any aAny;
1633     if( 0 == aArguments.getLength() )
1634         throw lang::IllegalArgumentException(
1635             rtl::OUString::createFromAscii( "no arguments" ),
1636             static_cast<XFilePicker2*>( this ), 1 );
1637 
1638     aAny = aArguments[0];
1639 
1640     if( ( aAny.getValueType() != ::getCppuType( ( sal_Int16* )0 ) ) &&
1641          (aAny.getValueType() != ::getCppuType( ( sal_Int8* )0 ) ) )
1642          throw lang::IllegalArgumentException(
1643             rtl::OUString::createFromAscii( "invalid argument type" ),
1644             static_cast<XFilePicker2*>( this ), 1 );
1645 
1646     sal_Int16 templateId = -1;
1647     aAny >>= templateId;
1648 
1649     GtkFileChooserAction eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1650     const gchar *first_button_text = GTK_STOCK_OPEN;
1651 
1652 
1653     //   TODO: extract full semantic from
1654     //   svtools/source/filepicker/filepicker.cxx (getWinBits)
1655     switch( templateId )
1656     {
1657         case FILEOPEN_SIMPLE:
1658             eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1659             first_button_text = GTK_STOCK_OPEN;
1660             OSL_TRACE( "3all true\n" );
1661             break;
1662         case FILESAVE_SIMPLE:
1663             eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1664             first_button_text = GTK_STOCK_SAVE;
1665             OSL_TRACE( "2all true\n" );
1666                 break;
1667         case FILESAVE_AUTOEXTENSION_PASSWORD:
1668             eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1669             first_button_text = GTK_STOCK_SAVE;
1670             mbToggleVisibility[PASSWORD] = true;
1671             OSL_TRACE( "1all true\n" );
1672             // TODO
1673             break;
1674         case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS:
1675             eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1676             first_button_text = GTK_STOCK_SAVE;
1677             mbToggleVisibility[PASSWORD] = true;
1678             mbToggleVisibility[FILTEROPTIONS] = true;
1679             OSL_TRACE( "4all true\n" );
1680             // TODO
1681                 break;
1682         case FILESAVE_AUTOEXTENSION_SELECTION:
1683             eAction = GTK_FILE_CHOOSER_ACTION_SAVE; // SELECT_FOLDER ?
1684             first_button_text = GTK_STOCK_SAVE;
1685             mbToggleVisibility[SELECTION] = true;
1686             OSL_TRACE( "5all true\n" );
1687             // TODO
1688                 break;
1689         case FILESAVE_AUTOEXTENSION_TEMPLATE:
1690             eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1691             first_button_text = GTK_STOCK_SAVE;
1692             mbListVisibility[TEMPLATE] = true;
1693             OSL_TRACE( "6all true\n" );
1694             // TODO
1695                 break;
1696         case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE:
1697             eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1698             first_button_text = GTK_STOCK_OPEN;
1699             mbToggleVisibility[LINK] = true;
1700             mbToggleVisibility[PREVIEW] = true;
1701             mbListVisibility[IMAGE_TEMPLATE] = true;
1702             // TODO
1703                 break;
1704         case FILEOPEN_PLAY:
1705             eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1706             first_button_text = GTK_STOCK_OPEN;
1707             mbButtonVisibility[PLAY] = true;
1708             // TODO
1709                 break;
1710         case FILEOPEN_READONLY_VERSION:
1711             eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1712             first_button_text = GTK_STOCK_OPEN;
1713             mbToggleVisibility[READONLY] = true;
1714             mbListVisibility[VERSION] = true;
1715             break;
1716         case FILEOPEN_LINK_PREVIEW:
1717             eAction = GTK_FILE_CHOOSER_ACTION_OPEN;
1718             first_button_text = GTK_STOCK_OPEN;
1719             mbToggleVisibility[LINK] = true;
1720             mbToggleVisibility[PREVIEW] = true;
1721             // TODO
1722                 break;
1723         case FILESAVE_AUTOEXTENSION:
1724             eAction = GTK_FILE_CHOOSER_ACTION_SAVE;
1725             first_button_text = GTK_STOCK_SAVE;
1726             OSL_TRACE( "7all true\n" );
1727             // TODO
1728                 break;
1729         default:
1730                 throw lang::IllegalArgumentException(
1731                 rtl::OUString::createFromAscii( "Unknown template" ),
1732                 static_cast< XFilePicker2* >( this ),
1733                 1 );
1734     }
1735 
1736     GdkThreadLock aLock;
1737 
1738     if( GTK_FILE_CHOOSER_ACTION_SAVE == eAction )
1739     {
1740         CResourceProvider aResProvider;
1741         OUString aFilePickerTitle(aResProvider.getResString( FILE_PICKER_TITLE_SAVE ));
1742         gtk_window_set_title ( GTK_WINDOW( m_pDialog ),
1743             OUStringToOString( aFilePickerTitle, RTL_TEXTENCODING_UTF8 ).getStr() );
1744     }
1745 
1746     gtk_file_chooser_set_action( GTK_FILE_CHOOSER( m_pDialog ), eAction);
1747     dialog_remove_buttons( GTK_DIALOG( m_pDialog ) );
1748     gtk_dialog_add_button( GTK_DIALOG( m_pDialog ), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL );
1749     for( int nTVIndex = 0; nTVIndex < BUTTON_LAST; nTVIndex++ )
1750     {
1751         if( mbButtonVisibility[nTVIndex] )
1752         {
1753 #ifdef GTK_STOCK_MEDIA_PLAY
1754             m_pButtons[ nTVIndex ] = gtk_dialog_add_button( GTK_DIALOG( m_pDialog ), GTK_STOCK_MEDIA_PLAY, 1 );
1755 #else
1756             CResourceProvider aResProvider;
1757             OString aPlay = OUStringToOString( aResProvider.getResString( PUSHBUTTON_PLAY ), RTL_TEXTENCODING_UTF8 );
1758             m_pButtons[ nTVIndex ] = gtk_dialog_add_button( GTK_DIALOG( m_pDialog ), aPlay.getStr(), 1 );
1759 #endif
1760         }
1761     }
1762     gtk_dialog_add_button( GTK_DIALOG( m_pDialog ), first_button_text, GTK_RESPONSE_ACCEPT );
1763 
1764     gtk_dialog_set_default_response( GTK_DIALOG (m_pDialog), GTK_RESPONSE_ACCEPT );
1765 
1766     // Setup special flags
1767     for( int nTVIndex = 0; nTVIndex < TOGGLE_LAST; nTVIndex++ )
1768     {
1769         if( mbToggleVisibility[nTVIndex] )
1770             gtk_widget_show( m_pToggles[ nTVIndex ] );
1771     }
1772 
1773     for( int nTVIndex = 0; nTVIndex < LIST_LAST; nTVIndex++ )
1774     {
1775         if( mbListVisibility[nTVIndex] )
1776         {
1777             gtk_widget_set_sensitive( m_pLists[ nTVIndex ], false );
1778             gtk_widget_show( m_pLists[ nTVIndex ] );
1779             gtk_widget_show( m_pListLabels[ nTVIndex ] );
1780             gtk_widget_show( m_pAligns[ nTVIndex ] );
1781             gtk_widget_show( m_pHBoxs[ nTVIndex ] );
1782         }
1783     }
1784 }
1785 
preview_toggled_cb(GtkObject * cb,SalGtkFilePicker * pobjFP)1786 void SalGtkFilePicker::preview_toggled_cb( GtkObject *cb, SalGtkFilePicker* pobjFP )
1787 {
1788     if( pobjFP->mbToggleVisibility[PREVIEW] )
1789         pobjFP->setShowState( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( cb ) ) );
1790 }
1791 
1792 //------------------------------------------------------------------------------------
1793 // XCancellable
1794 //------------------------------------------------------------------------------------
1795 
cancel()1796 void SAL_CALL SalGtkFilePicker::cancel() throw( uno::RuntimeException )
1797 {
1798     OSL_ASSERT( m_pDialog != NULL );
1799 
1800     // TODO m_pImpl->cancel();
1801 }
1802 
1803 // -------------------------------------------------
1804 // XServiceInfo
1805 // -------------------------------------------------
1806 
getImplementationName()1807 rtl::OUString SAL_CALL SalGtkFilePicker::getImplementationName()
1808     throw( uno::RuntimeException )
1809 {
1810     return rtl::OUString::createFromAscii( FILE_PICKER_IMPL_NAME );
1811 }
1812 
1813 // -------------------------------------------------
1814 //  XServiceInfo
1815 // -------------------------------------------------
1816 
supportsService(const rtl::OUString & ServiceName)1817 sal_Bool SAL_CALL SalGtkFilePicker::supportsService( const rtl::OUString& ServiceName )
1818     throw( uno::RuntimeException )
1819 {
1820     uno::Sequence <rtl::OUString> SupportedServicesNames = FilePicker_getSupportedServiceNames();
1821 
1822     for( sal_Int32 n = SupportedServicesNames.getLength(); n--; )
1823         if( SupportedServicesNames[n].compareTo( ServiceName ) == 0)
1824             return sal_True;
1825 
1826     return sal_False;
1827 }
1828 
1829 // -------------------------------------------------
1830 //  XServiceInfo
1831 // -------------------------------------------------
1832 
getSupportedServiceNames()1833 uno::Sequence<rtl::OUString> SAL_CALL SalGtkFilePicker::getSupportedServiceNames()
1834     throw( uno::RuntimeException )
1835 {
1836     return FilePicker_getSupportedServiceNames();
1837 }
1838 
1839 
1840 //--------------------------------------------------
1841 // Misc
1842 //-------------------------------------------------
SetCurFilter(const OUString & rFilter)1843 void SalGtkFilePicker::SetCurFilter( const OUString& rFilter )
1844 {
1845     GdkThreadLock aLock;
1846 
1847     // Get all the filters already added
1848     GSList *filters = gtk_file_chooser_list_filters ( GTK_FILE_CHOOSER( m_pDialog ) );
1849     bool bFound = false;
1850 
1851     for( GSList *iter = filters; !bFound && iter; iter = iter->next )
1852     {
1853         GtkFileFilter* pFilter = reinterpret_cast<GtkFileFilter *>( iter->data );
1854         G_CONST_RETURN gchar * filtername = gtk_file_filter_get_name( pFilter );
1855         OUString sFilterName( filtername, strlen( filtername ), RTL_TEXTENCODING_UTF8 );
1856 
1857         OUString aShrunkName = shrinkFilterName( rFilter );
1858         if( aShrunkName.equals( sFilterName) )
1859         {
1860             OSL_TRACE( "actually setting %s\n", filtername );
1861             gtk_file_chooser_set_filter( GTK_FILE_CHOOSER( m_pDialog ), pFilter );
1862             bFound = true;
1863         }
1864     }
1865 
1866     g_slist_free( filters );
1867 }
1868 
1869 extern "C"
1870 {
1871 static gboolean
case_insensitive_filter(const GtkFileFilterInfo * filter_info,gpointer data)1872 case_insensitive_filter (const GtkFileFilterInfo *filter_info, gpointer data)
1873 {
1874     gboolean bRetval = sal_False;
1875     const char *pFilter = (const char *) data;
1876 
1877     g_return_val_if_fail( data != NULL, sal_False );
1878     g_return_val_if_fail( filter_info != NULL, sal_False );
1879 
1880     if( !filter_info->uri )
1881         return sal_False;
1882 
1883     const char *pExtn = strrchr( filter_info->uri, '.' );
1884     if( !pExtn )
1885         return sal_False;
1886     pExtn++;
1887 
1888     if( !g_ascii_strcasecmp( pFilter, pExtn ) )
1889         bRetval = sal_True;
1890 
1891 #ifdef DEBUG
1892     fprintf( stderr, "'%s' match extn '%s' vs '%s' yeilds %d\n",
1893         filter_info->uri, pExtn, pFilter, bRetval );
1894 #endif
1895 
1896     return bRetval;
1897 }
1898 }
1899 
implAddFilter(const OUString & rFilter,const OUString & rType)1900 GtkFileFilter* SalGtkFilePicker::implAddFilter( const OUString& rFilter, const OUString& rType )
1901 {
1902     GdkThreadLock aLock;
1903 
1904     GtkFileFilter *filter = gtk_file_filter_new();
1905 
1906     OUString aShrunkName = shrinkFilterName( rFilter );
1907     OString aFilterName = rtl::OUStringToOString( aShrunkName, RTL_TEXTENCODING_UTF8 );
1908     gtk_file_filter_set_name( filter, aFilterName.getStr() );
1909 
1910     static const OUString aStarDot = OUString::createFromAscii( "*." );
1911     OUString aTokens;
1912 
1913     bool bAllGlob = !rType.compareToAscii( "*.*" ) || !rType.compareToAscii( "*" );
1914     if (bAllGlob)
1915         gtk_file_filter_add_pattern( filter, "*" );
1916     else
1917     {
1918         sal_Int32 nIndex = 0;
1919         rtl::OUString aToken;
1920         do
1921         {
1922             aToken = rType.getToken( 0, ';', nIndex );
1923             // Assume all have the "*.<extn>" syntax
1924             aToken = aToken.copy( aToken.lastIndexOf( aStarDot ) + 2 );
1925             if (aToken.getLength())
1926             {
1927                 if (aTokens.getLength())
1928                     aTokens += OUString::createFromAscii(",");
1929                 aTokens = aTokens += aToken;
1930                 gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_URI,
1931                     case_insensitive_filter,
1932                     g_strdup( rtl::OUStringToOString( aToken, RTL_TEXTENCODING_UTF8).getStr() ),
1933                     (GDestroyNotify) g_free );
1934 
1935                 OSL_TRACE( "fustering with %s\n", rtl::OUStringToOString( aToken, RTL_TEXTENCODING_UTF8 ).getStr());
1936             }
1937 #ifdef DEBUG
1938             else
1939             {
1940                 g_warning( "Duff filter token '%s'\n",
1941                     rtl::OUStringToOString( rType.getToken( 0, ';', nIndex ), RTL_TEXTENCODING_UTF8 ).getStr());
1942             }
1943 #endif
1944         }
1945         while( nIndex >= 0 );
1946     }
1947 
1948     gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( m_pDialog ), filter );
1949 
1950     if (!bAllGlob)
1951     {
1952         GtkTreeIter iter;
1953         gtk_list_store_append (m_pFilterStore, &iter);
1954         gtk_list_store_set (m_pFilterStore, &iter,
1955             0, OUStringToOString(shrinkFilterName( rFilter, true ), RTL_TEXTENCODING_UTF8).getStr(),
1956             1, OUStringToOString(aTokens, RTL_TEXTENCODING_UTF8).getStr(),
1957             2, aFilterName.getStr(),
1958             3, OUStringToOString(rType, RTL_TEXTENCODING_UTF8).getStr(),
1959             -1);
1960     }
1961     return filter;
1962 }
1963 
implAddFilterGroup(const OUString &,const Sequence<StringPair> & _rFilters)1964 void SalGtkFilePicker::implAddFilterGroup( const OUString& /*_rFilter*/, const Sequence< StringPair >& _rFilters )
1965 {
1966     // Gtk+ has no filter group concept I think so ...
1967     // implAddFilter( _rFilter, String() );
1968     const StringPair* pSubFilters   = _rFilters.getConstArray();
1969     const StringPair* pSubFiltersEnd = pSubFilters + _rFilters.getLength();
1970     for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters )
1971         implAddFilter( pSubFilters->First, pSubFilters->Second );
1972 }
1973 
SetFilters()1974 void SalGtkFilePicker::SetFilters()
1975 {
1976     GdkThreadLock aLock;
1977 
1978     if (!m_aInitialFilter.getLength())
1979         m_aInitialFilter = m_aCurrentFilter;
1980 
1981     rtl::OUString sPseudoFilter;
1982     if( GTK_FILE_CHOOSER_ACTION_SAVE == gtk_file_chooser_get_action( GTK_FILE_CHOOSER( m_pDialog ) ) )
1983     {
1984         std::set<OUString> aAllFormats;
1985         if( m_pFilterList && !m_pFilterList->empty() )
1986         {
1987             for (   FilterList::iterator aListIter = m_pFilterList->begin();
1988                     aListIter != m_pFilterList->end();
1989                     ++aListIter
1990                 )
1991             {
1992                 if( aListIter->hasSubFilters() )
1993                 {   // it's a filter group
1994                     UnoFilterList aSubFilters;
1995                     aListIter->getSubFilters( aSubFilters );
1996                     const StringPair* pSubFilters   = aSubFilters.getConstArray();
1997                     const StringPair* pSubFiltersEnd = pSubFilters + aSubFilters.getLength();
1998                     for( ; pSubFilters != pSubFiltersEnd; ++pSubFilters )
1999                         aAllFormats.insert(pSubFilters->Second);
2000                 }
2001                 else
2002                     aAllFormats.insert(aListIter->getFilter());
2003             }
2004         }
2005         if (aAllFormats.size() > 1)
2006         {
2007             rtl::OUString sAllFilter;
2008             std::set<OUString>::const_iterator aEnd = aAllFormats.end();
2009             for (std::set<OUString>::const_iterator aIter = aAllFormats.begin(); aIter != aEnd; ++aIter)
2010             {
2011                 if (sAllFilter.getLength())
2012                     sAllFilter += OUString(sal_Unicode(';'));
2013                 sAllFilter += *aIter;
2014             }
2015             CResourceProvider aResProvider;
2016             sPseudoFilter = aResProvider.getResString(FILE_PICKER_ALLFORMATS);
2017             m_pPseudoFilter = implAddFilter( sPseudoFilter, sAllFilter );
2018         }
2019     }
2020 
2021     if( m_pFilterList && !m_pFilterList->empty() )
2022     {
2023         for (   FilterList::iterator aListIter = m_pFilterList->begin();
2024                 aListIter != m_pFilterList->end();
2025                 ++aListIter
2026             )
2027         {
2028             if( aListIter->hasSubFilters() )
2029             {   // it's a filter group
2030 
2031                 UnoFilterList aSubFilters;
2032                 aListIter->getSubFilters( aSubFilters );
2033 
2034                 implAddFilterGroup( aListIter->getTitle(), aSubFilters );
2035             }
2036             else
2037             {
2038                 // it's a single filter
2039 
2040                 implAddFilter( aListIter->getTitle(), aListIter->getFilter() );
2041             }
2042         }
2043     }
2044 
2045     if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(m_pFilterStore), NULL)) //If m_pFilterStore is not empty
2046         gtk_widget_show( m_pFilterExpander );
2047     else
2048         gtk_widget_hide( m_pFilterExpander );
2049 
2050     // set the default filter
2051     if (sPseudoFilter.getLength())
2052         SetCurFilter( sPseudoFilter );
2053     else if(m_aCurrentFilter.getLength())
2054         SetCurFilter( m_aCurrentFilter );
2055 
2056     OSL_TRACE( "end setting filters\n");
2057 }
2058 
~SalGtkFilePicker()2059 SalGtkFilePicker::~SalGtkFilePicker()
2060 {
2061     int i;
2062 
2063     for( i = 0; i < TOGGLE_LAST; i++ )
2064         gtk_widget_destroy( m_pToggles[i] );
2065 
2066     for( i = 0; i < LIST_LAST; i++ )
2067     {
2068         gtk_widget_destroy( m_pListLabels[i] );
2069         gtk_widget_destroy( m_pAligns[i] ); //m_pAligns[i] owns m_pLists[i]
2070         gtk_widget_destroy( m_pHBoxs[i] );
2071     }
2072 
2073     delete m_pFilterList;
2074 
2075     gtk_widget_destroy( m_pVBox );
2076 }
2077 
2078 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
2079