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