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