1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_fpicker.hxx" 30 31 #include "commonpicker.hxx" 32 #include <com/sun/star/beans/PropertyAttribute.hpp> 33 #include <com/sun/star/beans/NamedValue.hpp> 34 #include <vcl/svapp.hxx> 35 #include <vos/mutex.hxx> 36 #include <toolkit/helper/vclunohelper.hxx> 37 #include <comphelper/weakeventlistener.hxx> 38 #include <comphelper/types.hxx> 39 #include <vcl/msgbox.hxx> 40 #include "iodlg.hxx" 41 42 //......................................................................... 43 namespace svt 44 { 45 //......................................................................... 46 47 #define PROPERTY_ID_HELPURL 1 48 #define PROPERTY_ID_WINDOW 2 49 50 // using -------------------------------------------------------------- 51 52 using namespace ::com::sun::star::lang; 53 using namespace ::com::sun::star::ui::dialogs; 54 using namespace ::com::sun::star::uno; 55 using namespace ::com::sun::star::beans; 56 using namespace ::comphelper; 57 58 //--------------------------------------------------------------------- 59 OCommonPicker::OCommonPicker( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxFactory ) 60 :OCommonPicker_Base( m_aMutex ) 61 ,OPropertyContainer( GetBroadcastHelper() ) 62 ,m_xORB( _rxFactory ) 63 ,m_pDlg( NULL ) 64 ,m_nCancelEvent( 0 ) 65 ,m_bExecuting( sal_False ) 66 { 67 // the two properties we have 68 registerProperty( 69 ::rtl::OUString::createFromAscii( "HelpURL" ), PROPERTY_ID_HELPURL, 70 PropertyAttribute::TRANSIENT, 71 &m_sHelpURL, ::getCppuType( &m_sHelpURL ) 72 ); 73 74 registerProperty( 75 ::rtl::OUString::createFromAscii( "Window" ), PROPERTY_ID_WINDOW, 76 PropertyAttribute::TRANSIENT | PropertyAttribute::READONLY, 77 &m_xWindow, ::getCppuType( &m_xWindow ) 78 ); 79 } 80 81 //--------------------------------------------------------------------- 82 OCommonPicker::~OCommonPicker() 83 { 84 if ( !GetBroadcastHelper().bDisposed ) 85 { 86 acquire(); 87 dispose(); 88 } 89 } 90 91 //--------------------------------------------------------------------- 92 // disambiguate XInterface 93 //--------------------------------------------------------------------- 94 IMPLEMENT_FORWARD_XINTERFACE2( OCommonPicker, OCommonPicker_Base, OPropertyContainer ) 95 96 //--------------------------------------------------------------------- 97 // disambiguate XTypeProvider 98 //--------------------------------------------------------------------- 99 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCommonPicker, OCommonPicker_Base, OPropertyContainer ) 100 101 //--------------------------------------------------------------------- 102 // XComponent related methods 103 //--------------------------------------------------------------------- 104 void OCommonPicker::checkAlive() const SAL_THROW( (DisposedException) ) 105 { 106 if ( GetBroadcastHelper().bInDispose || GetBroadcastHelper().bDisposed ) 107 throw DisposedException(); 108 } 109 110 void OCommonPicker::prepareDialog() 111 { 112 if ( !getDialog() ) 113 createPicker(); 114 115 // set the title 116 if ( m_aTitle.getLength() > 0 ) 117 getDialog()->SetText( m_aTitle ); 118 } 119 120 //--------------------------------------------------------------------- 121 void SAL_CALL OCommonPicker::disposing() 122 { 123 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 124 125 stopWindowListening(); 126 127 if ( m_nCancelEvent ) 128 Application::RemoveUserEvent( m_nCancelEvent ); 129 130 { 131 ::osl::MutexGuard aOwnGuard( m_aMutex ); 132 if ( m_bExecuting && m_pDlg ) 133 m_pDlg->EndDialog( RET_CANCEL ); 134 } 135 136 delete m_pDlg; 137 m_pDlg = NULL; 138 m_xWindow = NULL; 139 m_xDialogParent = NULL; 140 } 141 142 //--------------------------------------------------------------------- 143 void OCommonPicker::stopWindowListening() 144 { 145 disposeComponent( m_xWindowListenerAdapter ); 146 disposeComponent( m_xParentListenerAdapter ); 147 } 148 149 //--------------------------------------------------------------------- 150 // XEventListener 151 //--------------------------------------------------------------------- 152 void SAL_CALL OCommonPicker::disposing( const EventObject& _rSource ) throw (RuntimeException) 153 { 154 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 155 sal_Bool bDialogDying = _rSource.Source == m_xWindow; 156 sal_Bool bParentDying = _rSource.Source == m_xDialogParent; 157 158 if ( bDialogDying || bParentDying ) 159 { 160 stopWindowListening(); 161 162 if ( !bDialogDying ) // it's the parent which is dying -> delete the dialog 163 delete m_pDlg; 164 165 m_pDlg = NULL; 166 m_xWindow = NULL; 167 m_xDialogParent = NULL; 168 } 169 else 170 { 171 DBG_ERROR( "OCommonPicker::disposing: where did this come from?" ); 172 } 173 } 174 175 //--------------------------------------------------------------------- 176 // property set related methods 177 //--------------------------------------------------------------------- 178 ::cppu::IPropertyArrayHelper* OCommonPicker::createArrayHelper( ) const 179 { 180 Sequence< Property > aProps; 181 describeProperties( aProps ); 182 return new cppu::OPropertyArrayHelper( aProps ); 183 } 184 185 //--------------------------------------------------------------------- 186 ::cppu::IPropertyArrayHelper& SAL_CALL OCommonPicker::getInfoHelper() 187 { 188 return *const_cast< OCommonPicker* >( this )->getArrayHelper(); 189 } 190 191 //--------------------------------------------------------------------- 192 Reference< XPropertySetInfo > SAL_CALL OCommonPicker::getPropertySetInfo( ) throw(RuntimeException) 193 { 194 return ::cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() ); 195 } 196 197 //--------------------------------------------------------------------- 198 void SAL_CALL OCommonPicker::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw (Exception) 199 { 200 OPropertyContainer::setFastPropertyValue_NoBroadcast( _nHandle, _rValue ); 201 202 // if the HelpURL changed, forward this to the dialog 203 if ( PROPERTY_ID_HELPURL == _nHandle ) 204 if ( m_pDlg ) 205 OControlAccess::setHelpURL( m_pDlg, m_sHelpURL, sal_False ); 206 } 207 208 209 //--------------------------------------------------------------------- 210 sal_Bool OCommonPicker::createPicker() 211 { 212 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 213 214 if ( !m_pDlg ) 215 { 216 m_pDlg = implCreateDialog( VCLUnoHelper::GetWindow( m_xDialogParent ) ); 217 DBG_ASSERT( m_pDlg, "OCommonPicker::createPicker: invalid dialog returned!" ); 218 219 if ( m_pDlg ) 220 { 221 // synchronize the help id of the dialog with out help URL property 222 if ( m_sHelpURL.getLength() ) 223 { // somebody already set the help URL while we had no dialog yet 224 OControlAccess::setHelpURL( m_pDlg, m_sHelpURL, sal_False ); 225 } 226 else 227 { 228 m_sHelpURL = OControlAccess::getHelpURL( m_pDlg, sal_False ); 229 } 230 231 m_xWindow = VCLUnoHelper::GetInterface( m_pDlg ); 232 233 // add as event listener to the window 234 Reference< XComponent > xWindowComp( m_xWindow, UNO_QUERY ); 235 OSL_ENSURE( xWindowComp.is(), "OCommonPicker::createFileDialog: invalid window component!" ); 236 if ( xWindowComp.is() ) 237 { 238 m_xWindowListenerAdapter = new OWeakEventListenerAdapter( this, xWindowComp ); 239 // the adapter will add itself as listener, and forward notifications 240 } 241 242 // _and_ add as event listener to the parent - in case the parent is destroyed 243 // before we are disposed, our disposal would access dead VCL windows then .... 244 m_xDialogParent = VCLUnoHelper::GetInterface( m_pDlg->GetParent() ); 245 xWindowComp = xWindowComp.query( m_xDialogParent ); 246 OSL_ENSURE( xWindowComp.is() || !m_pDlg->GetParent(), "OCommonPicker::createFileDialog: invalid window component (the parent this time)!" ); 247 if ( xWindowComp.is() ) 248 { 249 m_xParentListenerAdapter = new OWeakEventListenerAdapter( this, xWindowComp ); 250 // the adapter will add itself as listener, and forward notifications 251 } 252 } 253 } 254 255 return NULL != m_pDlg; 256 } 257 258 //--------------------------------------------------------------------- 259 // XControlAccess functions 260 //--------------------------------------------------------------------- 261 void SAL_CALL OCommonPicker::setControlProperty( const ::rtl::OUString& aControlName, const ::rtl::OUString& aControlProperty, const Any& aValue ) throw (IllegalArgumentException, RuntimeException) 262 { 263 checkAlive(); 264 265 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 266 if ( createPicker() ) 267 { 268 ::svt::OControlAccess aAccess( m_pDlg, m_pDlg->GetView() ); 269 aAccess.setControlProperty( aControlName, aControlProperty, aValue ); 270 } 271 } 272 273 //--------------------------------------------------------------------- 274 Any SAL_CALL OCommonPicker::getControlProperty( const ::rtl::OUString& aControlName, const ::rtl::OUString& aControlProperty ) throw (IllegalArgumentException, RuntimeException) 275 { 276 checkAlive(); 277 278 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 279 if ( createPicker() ) 280 { 281 ::svt::OControlAccess aAccess( m_pDlg, m_pDlg->GetView() ); 282 return aAccess.getControlProperty( aControlName, aControlProperty ); 283 } 284 285 return Any(); 286 } 287 288 //--------------------------------------------------------------------- 289 // XControlInformation functions 290 //--------------------------------------------------------------------- 291 Sequence< ::rtl::OUString > SAL_CALL OCommonPicker::getSupportedControls( ) throw (RuntimeException) 292 { 293 checkAlive(); 294 295 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 296 if ( createPicker() ) 297 { 298 ::svt::OControlAccess aAccess( m_pDlg, m_pDlg->GetView() ); 299 return aAccess.getSupportedControls( ); 300 } 301 302 return Sequence< ::rtl::OUString >(); 303 } 304 305 //--------------------------------------------------------------------- 306 sal_Bool SAL_CALL OCommonPicker::isControlSupported( const ::rtl::OUString& aControlName ) throw (RuntimeException) 307 { 308 checkAlive(); 309 310 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 311 if ( createPicker() ) 312 { 313 ::svt::OControlAccess aAccess( m_pDlg, m_pDlg->GetView() ); 314 return aAccess.isControlSupported( aControlName ); 315 } 316 317 return sal_False; 318 } 319 320 //--------------------------------------------------------------------- 321 Sequence< ::rtl::OUString > SAL_CALL OCommonPicker::getSupportedControlProperties( const ::rtl::OUString& aControlName ) throw (IllegalArgumentException, RuntimeException) 322 { 323 checkAlive(); 324 325 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 326 if ( createPicker() ) 327 { 328 ::svt::OControlAccess aAccess( m_pDlg, m_pDlg->GetView() ); 329 return aAccess.getSupportedControlProperties( aControlName ); 330 } 331 332 return Sequence< ::rtl::OUString >(); 333 } 334 335 //--------------------------------------------------------------------- 336 sal_Bool SAL_CALL OCommonPicker::isControlPropertySupported( const ::rtl::OUString& aControlName, const ::rtl::OUString& aControlProperty ) throw (IllegalArgumentException, RuntimeException) 337 { 338 checkAlive(); 339 340 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 341 if ( createPicker() ) 342 { 343 ::svt::OControlAccess aAccess( m_pDlg, m_pDlg->GetView() ); 344 return aAccess.isControlPropertySupported( aControlName, aControlProperty ); 345 } 346 347 return sal_False; 348 } 349 350 //--------------------------------------------------------------------- 351 // XExecutableDialog functions 352 //--------------------------------------------------------------------- 353 void SAL_CALL OCommonPicker::setTitle( const rtl::OUString& _rTitle ) throw( RuntimeException ) 354 { 355 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 356 m_aTitle = _rTitle; 357 } 358 359 //--------------------------------------------------------------------- 360 sal_Int16 OCommonPicker::execute() throw (RuntimeException) 361 { 362 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 363 364 prepareDialog(); 365 366 { 367 ::osl::MutexGuard aOwnGuard( m_aMutex ); 368 m_bExecuting = sal_True; 369 } 370 sal_Int16 nResult = implExecutePicker(); 371 { 372 ::osl::MutexGuard aOwnGuard( m_aMutex ); 373 m_bExecuting = sal_False; 374 } 375 376 return nResult; 377 } 378 379 //--------------------------------------------------------------------- 380 // XCancellable functions 381 //--------------------------------------------------------------------- 382 void SAL_CALL OCommonPicker::cancel( ) throw (RuntimeException) 383 { 384 { 385 ::osl::MutexGuard aGuard( m_aMutex ); 386 if ( m_nCancelEvent ) 387 // nothing to do - the event for cancelling the dialog is already on the way 388 return; 389 } 390 391 // The thread which executes our dialog has locked the solar mutex for 392 // sure. Cancelling the dialog should be done with a locked solar mutex, too. 393 // Thus we post ourself a message for cancelling the dialog. This way, the message 394 // is either handled in the thread which opened the dialog (which may even be 395 // this thread here), or, if no dialog is open, in the thread doing scheduling 396 // currently. Both is okay for us .... 397 // 398 // Note that we could do check if we are really executing the dialog currently. 399 // but the information would be potentially obsolete at the moment our event 400 // arrives, so we need to check it there, anyway ... 401 m_nCancelEvent = Application::PostUserEvent( LINK( this, OCommonPicker, OnCancelPicker ) ); 402 } 403 404 //--------------------------------------------------------------------- 405 IMPL_LINK( OCommonPicker, OnCancelPicker, void*, EMPTYARG ) 406 { 407 // By definition, the solar mutex is locked when we arrive here. Note that this 408 // is important, as for instance the consistency of m_pDlg depends on this mutex. 409 ::osl::MutexGuard aGuard( m_aMutex ); 410 m_nCancelEvent = 0; 411 412 if ( !m_bExecuting ) 413 // nothing to do. This may be because the dialog was cancelled after our cancel method 414 // posted this async event, or because somebody called cancel without the dialog 415 // being executed at this time. 416 return 0; 417 418 OSL_ENSURE( getDialog(), "OCommonPicker::OnCancelPicker: executing, but no dialog!" ); 419 if ( getDialog() ) 420 getDialog()->EndDialog( RET_CANCEL ); 421 422 return 0L; 423 } 424 425 //------------------------------------------------------------------------------------ 426 // XInitialization functions 427 //------------------------------------------------------------------------------------ 428 void SAL_CALL OCommonPicker::initialize( const Sequence< Any >& _rArguments ) 429 throw ( Exception, RuntimeException ) 430 { 431 checkAlive(); 432 433 ::rtl::OUString sSettingName; 434 Any aSettingValue; 435 436 PropertyValue aPropArg; 437 NamedValue aPairArg; 438 439 440 const Any* pArguments = _rArguments.getConstArray(); 441 const Any* pArgumentsEnd = _rArguments.getConstArray() + _rArguments.getLength(); 442 for ( const Any* pArgument = pArguments; 443 pArgument != pArgumentsEnd; 444 ++pArgument 445 ) 446 { 447 if ( *pArgument >>= aPropArg ) 448 { 449 if ( aPropArg.Name.getLength() <= 0) 450 continue; 451 452 sSettingName = aPropArg.Name; 453 aSettingValue = aPropArg.Value; 454 } 455 else if ( *pArgument >>= aPairArg ) 456 { 457 if ( aPairArg.Name.getLength() <= 0) 458 continue; 459 460 sSettingName = aPairArg.Name; 461 aSettingValue = aPairArg.Value; 462 463 464 } 465 else 466 { 467 DBG_ERROR( 468 ( ::rtl::OString( "OCommonPicker::initialize: unknown argument type at position " ) 469 += ::rtl::OString::valueOf( (sal_Int32)( pArguments - _rArguments.getConstArray() ) ) 470 ).getStr() 471 ); 472 continue; 473 } 474 475 #ifdef DBG_UTIL 476 sal_Bool bKnownSetting = 477 #endif 478 implHandleInitializationArgument( sSettingName, aSettingValue ); 479 DBG_ASSERT( bKnownSetting, 480 ( ::rtl::OString( "OCommonPicker::initialize: unknown argument \"" ) 481 += ::rtl::OString( sSettingName.getStr(), sSettingName.getLength(), osl_getThreadTextEncoding() ) 482 += ::rtl::OString( "\"!" ) 483 ).getStr() 484 ); 485 } 486 } 487 488 //--------------------------------------------------------------------- 489 sal_Bool OCommonPicker::implHandleInitializationArgument( const ::rtl::OUString& _rName, const Any& _rValue ) SAL_THROW( ( Exception, RuntimeException ) ) 490 { 491 sal_Bool bKnown = sal_True; 492 if ( _rName.equalsAscii( "ParentWindow" ) ) 493 { 494 m_xDialogParent.clear(); 495 OSL_VERIFY( _rValue >>= m_xDialogParent ); 496 OSL_ENSURE( VCLUnoHelper::GetWindow( m_xDialogParent ), "OCommonPicker::implHandleInitializationArgument: invalid parent window given!" ); 497 } 498 else 499 bKnown = sal_False; 500 return bKnown; 501 } 502 503 //......................................................................... 504 } // namespace svt 505 //......................................................................... 506 507