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