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