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