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