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