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_dbaccess.hxx" 30 31 #include "browserids.hxx" 32 #include "commontypes.hxx" 33 #include "dataview.hxx" 34 #include "dbu_misc.hrc" 35 #include "dbustrings.hrc" 36 #include "moduledbu.hxx" 37 #include "dbsubcomponentcontroller.hxx" 38 39 /** === begin UNO includes === **/ 40 #include <com/sun/star/frame/XUntitledNumbers.hpp> 41 #include <com/sun/star/beans/PropertyAttribute.hpp> 42 #include <com/sun/star/container/XChild.hpp> 43 #include <com/sun/star/container/XNameAccess.hpp> 44 #include <com/sun/star/sdb/XDocumentDataSource.hpp> 45 #include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp> 46 #include <com/sun/star/sdbc/XDataSource.hpp> 47 #include <com/sun/star/lang/IllegalArgumentException.hpp> 48 #include <com/sun/star/frame/XUntitledNumbers.hpp> 49 /** === end UNO includes === **/ 50 51 #include <comphelper/sequence.hxx> 52 #include <comphelper/types.hxx> 53 #include <connectivity/dbexception.hxx> 54 #include <connectivity/dbtools.hxx> 55 #include <cppuhelper/typeprovider.hxx> 56 #include <rtl/ustrbuf.hxx> 57 #include <toolkit/unohlp.hxx> 58 #include <tools/debug.hxx> 59 #include <tools/diagnose_ex.h> 60 #include <vcl/msgbox.hxx> 61 62 //........................................................................ 63 namespace dbaui 64 { 65 //........................................................................ 66 67 /** === begin UNO using === **/ 68 using ::com::sun::star::uno::Any; 69 using ::com::sun::star::uno::Reference; 70 using ::com::sun::star::beans::XPropertySet; 71 using ::com::sun::star::util::XNumberFormatter; 72 using ::com::sun::star::lang::XMultiServiceFactory; 73 using ::com::sun::star::uno::RuntimeException; 74 using ::com::sun::star::uno::Sequence; 75 using ::com::sun::star::uno::Type; 76 using ::com::sun::star::sdbc::XConnection; 77 using ::com::sun::star::uno::UNO_QUERY; 78 using ::com::sun::star::container::XChild; 79 using ::com::sun::star::sdbc::XDataSource; 80 using ::com::sun::star::util::XNumberFormatter; 81 using ::com::sun::star::util::XNumberFormatsSupplier; 82 using ::com::sun::star::frame::XFrame; 83 using ::com::sun::star::uno::Exception; 84 using ::com::sun::star::sdbc::SQLException; 85 using ::com::sun::star::lang::EventObject; 86 using ::com::sun::star::beans::PropertyValue; 87 using ::com::sun::star::frame::XModel; 88 using ::com::sun::star::sdb::XOfficeDatabaseDocument; 89 using ::com::sun::star::awt::XWindow; 90 using ::com::sun::star::sdbc::XDatabaseMetaData; 91 using ::com::sun::star::sdb::XDocumentDataSource; 92 using ::com::sun::star::document::XEmbeddedScripts; 93 using ::com::sun::star::lang::IllegalArgumentException; 94 using ::com::sun::star::uno::UNO_SET_THROW; 95 using ::com::sun::star::uno::UNO_QUERY_THROW; 96 using ::com::sun::star::frame::XUntitledNumbers; 97 using ::com::sun::star::beans::PropertyVetoException; 98 /** === end UNO using === **/ 99 100 class DataSourceHolder 101 { 102 public: 103 DataSourceHolder() 104 { 105 } 106 107 DataSourceHolder( const Reference< XDataSource >& _rxDataSource ) 108 { 109 m_xDataSource = _rxDataSource; 110 Reference< XDocumentDataSource > xDocDS( m_xDataSource, UNO_QUERY ); 111 if ( xDocDS.is() ) 112 m_xDocument = xDocDS->getDatabaseDocument(); 113 114 m_xDataSourceProps.set( m_xDataSource, UNO_QUERY ); 115 } 116 117 const Reference< XDataSource >& getDataSource() const { return m_xDataSource; } 118 const Reference< XPropertySet >& getDataSourceProps() const { return m_xDataSourceProps; } 119 const Reference< XOfficeDatabaseDocument > getDatabaseDocument() const { return m_xDocument; } 120 121 bool is() const { return m_xDataSource.is(); } 122 123 void clear() 124 { 125 m_xDataSource.clear(); 126 m_xDocument.clear(); 127 } 128 129 private: 130 Reference< XDataSource > m_xDataSource; 131 Reference< XPropertySet > m_xDataSourceProps; 132 Reference< XOfficeDatabaseDocument > m_xDocument; 133 }; 134 135 struct DBSubComponentController_Impl 136 { 137 private: 138 ::boost::optional< bool > m_aDocScriptSupport; 139 140 public: 141 OModuleClient m_aModuleClient; 142 ::dbtools::SQLExceptionInfo m_aCurrentError; 143 144 ::cppu::OInterfaceContainerHelper 145 m_aModifyListeners; 146 147 // <properties> 148 SharedConnection m_xConnection; 149 ::dbtools::DatabaseMetaData m_aSdbMetaData; 150 // </properties> 151 ::rtl::OUString m_sDataSourceName; // the data source we're working for 152 DataSourceHolder m_aDataSource; 153 Reference< XModel > m_xDocument; 154 Reference< XNumberFormatter > m_xFormatter; // a number formatter working with the connection's NumberFormatsSupplier 155 sal_Int32 m_nDocStartNumber; 156 sal_Bool m_bSuspended; // is true when the controller was already suspended 157 sal_Bool m_bEditable; // is the control readonly or not 158 sal_Bool m_bModified; // is the data modified 159 bool m_bNotAttached; 160 161 DBSubComponentController_Impl( ::osl::Mutex& i_rMutex ) 162 :m_aDocScriptSupport() 163 ,m_aModifyListeners( i_rMutex ) 164 ,m_nDocStartNumber(0) 165 ,m_bSuspended( sal_False ) 166 ,m_bEditable(sal_True) 167 ,m_bModified(sal_False) 168 ,m_bNotAttached(true) 169 { 170 } 171 172 bool documentHasScriptSupport() const 173 { 174 OSL_PRECOND( !!m_aDocScriptSupport, 175 "DBSubComponentController_Impl::documentHasScriptSupport: not completely initialized, yet - don't know!?" ); 176 return !!m_aDocScriptSupport && *m_aDocScriptSupport; 177 } 178 179 void setDocumentScriptSupport( const bool _bSupport ) 180 { 181 OSL_PRECOND( !m_aDocScriptSupport, 182 "DBSubComponentController_Impl::setDocumentScriptSupport: already initialized!" ); 183 m_aDocScriptSupport = ::boost::optional< bool >( _bSupport ); 184 } 185 }; 186 187 //==================================================================== 188 //= DBSubComponentController 189 //==================================================================== 190 //-------------------------------------------------------------------- 191 DBSubComponentController::DBSubComponentController(const Reference< XMultiServiceFactory >& _rxORB) 192 :DBSubComponentController_Base( _rxORB ) 193 ,m_pImpl( new DBSubComponentController_Impl( getMutex() ) ) 194 { 195 } 196 197 //-------------------------------------------------------------------- 198 DBSubComponentController::~DBSubComponentController() 199 { 200 } 201 202 //-------------------------------------------------------------------- 203 void DBSubComponentController::impl_initialize() 204 { 205 OGenericUnoController::impl_initialize(); 206 207 const ::comphelper::NamedValueCollection& rArguments( getInitParams() ); 208 209 Reference< XConnection > xConnection; 210 xConnection = rArguments.getOrDefault( (::rtl::OUString)PROPERTY_ACTIVE_CONNECTION, xConnection ); 211 212 if ( !xConnection.is() ) 213 ::dbtools::isEmbeddedInDatabase( getModel(), xConnection ); 214 215 if ( xConnection.is() ) 216 initializeConnection( xConnection ); 217 218 bool bShowError = true; 219 if ( !isConnected() ) 220 { 221 reconnect( sal_False ); 222 bShowError = false; 223 } 224 if ( !isConnected() ) 225 { 226 if ( bShowError ) 227 connectionLostMessage(); 228 throw IllegalArgumentException(); 229 } 230 } 231 232 //-------------------------------------------------------------------- 233 Any SAL_CALL DBSubComponentController::queryInterface(const Type& _rType) throw (RuntimeException) 234 { 235 if ( _rType.equals( XScriptInvocationContext::static_type() ) ) 236 { 237 if ( m_pImpl->documentHasScriptSupport() ) 238 return makeAny( Reference< XScriptInvocationContext >( this ) ); 239 return Any(); 240 } 241 242 return DBSubComponentController_Base::queryInterface( _rType ); 243 } 244 245 //-------------------------------------------------------------------- 246 Sequence< Type > SAL_CALL DBSubComponentController::getTypes( ) throw (RuntimeException) 247 { 248 Sequence< Type > aTypes( DBSubComponentController_Base::getTypes() ); 249 if ( !m_pImpl->documentHasScriptSupport() ) 250 { 251 Sequence< Type > aStrippedTypes( aTypes.getLength() - 1 ); 252 ::std::remove_copy_if( 253 aTypes.getConstArray(), 254 aTypes.getConstArray() + aTypes.getLength(), 255 aStrippedTypes.getArray(), 256 ::std::bind2nd( ::std::equal_to< Type >(), XScriptInvocationContext::static_type() ) 257 ); 258 aTypes = aStrippedTypes; 259 } 260 return aTypes; 261 } 262 263 //-------------------------------------------------------------------- 264 void DBSubComponentController::initializeConnection( const Reference< XConnection >& _rxForeignConn ) 265 { 266 DBG_ASSERT( !isConnected(), "DBSubComponentController::initializeConnection: not to be called when already connected!" ); 267 // usually this gets called from within initialize of derived classes ... 268 if ( isConnected() ) 269 disconnect(); 270 271 m_pImpl->m_xConnection.reset( _rxForeignConn, SharedConnection::NoTakeOwnership ); 272 m_pImpl->m_aSdbMetaData.reset( m_pImpl->m_xConnection ); 273 startConnectionListening( m_pImpl->m_xConnection ); 274 275 // get the data source the connection belongs to 276 try 277 { 278 // determine our data source 279 OSL_PRECOND( !m_pImpl->m_aDataSource.is(), "DBSubComponentController::initializeConnection: already a data source in this phase?" ); 280 { 281 Reference< XChild > xConnAsChild( m_pImpl->m_xConnection, UNO_QUERY ); 282 Reference< XDataSource > xDS; 283 if ( xConnAsChild.is() ) 284 xDS = Reference< XDataSource >( xConnAsChild->getParent(), UNO_QUERY ); 285 286 // (take the indirection through XDataSource to ensure we have a correct object ....) 287 m_pImpl->m_aDataSource = xDS; 288 } 289 OSL_POSTCOND( m_pImpl->m_aDataSource.is(), "DBSubComponentController::initializeConnection: unable to obtain the data source object!" ); 290 291 if ( m_pImpl->m_bNotAttached ) 292 { 293 Reference< XUntitledNumbers > xUntitledProvider( getDatabaseDocument(), UNO_QUERY ); 294 m_pImpl->m_nDocStartNumber = 1; 295 if ( xUntitledProvider.is() ) 296 m_pImpl->m_nDocStartNumber = xUntitledProvider->leaseNumber( static_cast< XWeak* >( this ) ); 297 } 298 299 // determine the availability of script support in our document. Our own XScriptInvocationContext 300 // interface depends on this 301 m_pImpl->setDocumentScriptSupport( Reference< XEmbeddedScripts >( getDatabaseDocument(), UNO_QUERY ).is() ); 302 303 // get a number formatter 304 Reference< XPropertySet > xDataSourceProps( m_pImpl->m_aDataSource.getDataSourceProps(), UNO_SET_THROW ); 305 xDataSourceProps->getPropertyValue( PROPERTY_NAME ) >>= m_pImpl->m_sDataSourceName; 306 DBG_ASSERT( m_pImpl->m_sDataSourceName.getLength(), "DBSubComponentController::initializeConnection: invalid data source name!" ); 307 Reference< XNumberFormatsSupplier> xSupplier = ::dbtools::getNumberFormats(m_pImpl->m_xConnection); 308 if(xSupplier.is()) 309 { 310 m_pImpl->m_xFormatter = Reference< XNumberFormatter >(getORB() 311 ->createInstance(::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatter")), UNO_QUERY); 312 m_pImpl->m_xFormatter->attachNumberFormatsSupplier(xSupplier); 313 } 314 OSL_ENSURE(m_pImpl->m_xFormatter.is(),"No NumberFormatter!"); 315 } 316 catch( const Exception& ) 317 { 318 DBG_UNHANDLED_EXCEPTION(); 319 } 320 } 321 322 //-------------------------------------------------------------------- 323 void DBSubComponentController::reconnect( sal_Bool _bUI ) 324 { 325 OSL_ENSURE(!m_pImpl->m_bSuspended, "Cannot reconnect while suspended!"); 326 327 stopConnectionListening( m_pImpl->m_xConnection ); 328 m_pImpl->m_aSdbMetaData.reset( NULL ); 329 m_pImpl->m_xConnection.clear(); 330 331 // reconnect 332 sal_Bool bReConnect = sal_True; 333 if ( _bUI ) 334 { 335 QueryBox aQuery( getView(), ModuleRes(QUERY_CONNECTION_LOST) ); 336 bReConnect = ( RET_YES == aQuery.Execute() ); 337 } 338 339 // now really reconnect ... 340 if ( bReConnect ) 341 { 342 m_pImpl->m_xConnection.reset( connect( m_pImpl->m_aDataSource.getDataSource(), NULL ), SharedConnection::TakeOwnership ); 343 m_pImpl->m_aSdbMetaData.reset( m_pImpl->m_xConnection ); 344 } 345 346 // invalidate all slots 347 InvalidateAll(); 348 } 349 350 //-------------------------------------------------------------------- 351 void DBSubComponentController::disconnect() 352 { 353 stopConnectionListening(m_pImpl->m_xConnection); 354 m_pImpl->m_aSdbMetaData.reset( NULL ); 355 m_pImpl->m_xConnection.clear(); 356 357 InvalidateAll(); 358 } 359 360 //-------------------------------------------------------------------- 361 void DBSubComponentController::losingConnection() 362 { 363 // our connection was disposed so we need a new one 364 reconnect( sal_True ); 365 InvalidateAll(); 366 } 367 368 //-------------------------------------------------------------------- 369 void SAL_CALL DBSubComponentController::disposing() 370 { 371 DBSubComponentController_Base::disposing(); 372 373 disconnect(); 374 375 attachFrame( Reference < XFrame >() ); 376 377 m_pImpl->m_aDataSource.clear(); 378 } 379 380 //-------------------------------------------------------------------- 381 void SAL_CALL DBSubComponentController::disposing(const EventObject& _rSource) throw( RuntimeException ) 382 { 383 if ( _rSource.Source == getConnection() ) 384 { 385 if ( !m_pImpl->m_bSuspended // when already suspended then we don't have to reconnect 386 && !getBroadcastHelper().bInDispose 387 && !getBroadcastHelper().bDisposed 388 && isConnected() 389 ) 390 { 391 losingConnection(); 392 } 393 else 394 { 395 m_pImpl->m_xConnection.reset( m_pImpl->m_xConnection, SharedConnection::NoTakeOwnership ); 396 // this prevents the "disposeComponent" call in disconnect 397 disconnect(); 398 } 399 } 400 else 401 DBSubComponentController_Base::disposing( _rSource ); 402 } 403 404 //-------------------------------------------------------------------- 405 void DBSubComponentController::appendError( const ::rtl::OUString& _rErrorMessage, const ::dbtools::StandardSQLState _eSQLState, 406 const sal_Int32 _nErrorCode ) 407 { 408 m_pImpl->m_aCurrentError.append( ::dbtools::SQLExceptionInfo::SQL_EXCEPTION, _rErrorMessage, getStandardSQLStateAscii( _eSQLState ), 409 _nErrorCode ); 410 } 411 //-------------------------------------------------------------------- 412 void DBSubComponentController::clearError() 413 { 414 m_pImpl->m_aCurrentError = ::dbtools::SQLExceptionInfo(); 415 } 416 417 //-------------------------------------------------------------------- 418 sal_Bool DBSubComponentController::hasError() const 419 { 420 return m_pImpl->m_aCurrentError.isValid(); 421 } 422 423 //-------------------------------------------------------------------- 424 const ::dbtools::SQLExceptionInfo& DBSubComponentController::getError() const 425 { 426 return m_pImpl->m_aCurrentError; 427 } 428 429 //-------------------------------------------------------------------- 430 void DBSubComponentController::displayError() 431 { 432 showError( m_pImpl->m_aCurrentError ); 433 } 434 435 //-------------------------------------------------------------------- 436 sal_Bool SAL_CALL DBSubComponentController::suspend(sal_Bool bSuspend) throw( RuntimeException ) 437 { 438 m_pImpl->m_bSuspended = bSuspend; 439 if ( !bSuspend && !isConnected() ) 440 reconnect(sal_True); 441 442 443 return sal_True; 444 } 445 446 // ----------------------------------------------------------------------------- 447 sal_Bool SAL_CALL DBSubComponentController::attachModel( const Reference< XModel > & _rxModel) throw( RuntimeException ) 448 { 449 if ( !_rxModel.is() ) 450 return sal_False; 451 if ( !DBSubComponentController_Base::attachModel( _rxModel ) ) 452 return sal_False; 453 454 m_pImpl->m_bNotAttached = false; 455 if ( m_pImpl->m_nDocStartNumber == 1 ) 456 releaseNumberForComponent(); 457 458 Reference< XUntitledNumbers > xUntitledProvider( _rxModel, UNO_QUERY ); 459 m_pImpl->m_nDocStartNumber = 1; 460 if ( xUntitledProvider.is() ) 461 m_pImpl->m_nDocStartNumber = xUntitledProvider->leaseNumber( static_cast< XWeak* >( this ) ); 462 463 return sal_True; 464 } 465 466 // ----------------------------------------------------------------------------- 467 void DBSubComponentController::Execute(sal_uInt16 _nId, const Sequence< PropertyValue >& _rArgs) 468 { 469 if ( _nId == ID_BROWSER_CLOSE ) 470 { 471 closeTask(); 472 return; 473 } 474 475 DBSubComponentController_Base::Execute( _nId, _rArgs ); 476 InvalidateFeature( _nId ); 477 } 478 479 // ----------------------------------------------------------------------------- 480 ::rtl::OUString DBSubComponentController::getDataSourceName() const 481 { 482 ::rtl::OUString sName; 483 Reference< XPropertySet > xDataSourceProps( m_pImpl->m_aDataSource.getDataSourceProps() ); 484 if ( xDataSourceProps.is() ) 485 xDataSourceProps->getPropertyValue(PROPERTY_NAME) >>= sName; 486 return sName; 487 } 488 // ----------------------------------------------------------------------------- 489 void DBSubComponentController::connectionLostMessage() const 490 { 491 String aMessage(ModuleRes(RID_STR_CONNECTION_LOST)); 492 Reference< XWindow > xWindow = getTopMostContainerWindow(); 493 Window* pWin = NULL; 494 if ( xWindow.is() ) 495 pWin = VCLUnoHelper::GetWindow(xWindow); 496 if ( !pWin ) 497 pWin = getView()->Window::GetParent(); 498 499 InfoBox(pWin, aMessage).Execute(); 500 } 501 // ----------------------------------------------------------------------------- 502 const Reference< XConnection >& DBSubComponentController::getConnection() const 503 { 504 return m_pImpl->m_xConnection; 505 } 506 507 // ----------------------------------------------------------------------------- 508 sal_Bool DBSubComponentController::isReadOnly() const 509 { 510 return !m_pImpl->m_bEditable; 511 } 512 513 // ----------------------------------------------------------------------------- 514 sal_Bool DBSubComponentController::isEditable() const 515 { 516 return m_pImpl->m_bEditable; 517 } 518 519 // ----------------------------------------------------------------------------- 520 void DBSubComponentController::setEditable(sal_Bool _bEditable) 521 { 522 m_pImpl->m_bEditable = _bEditable; 523 } 524 525 // ----------------------------------------------------------------------------- 526 const ::dbtools::DatabaseMetaData& DBSubComponentController::getSdbMetaData() const 527 { 528 return m_pImpl->m_aSdbMetaData; 529 } 530 531 // ----------------------------------------------------------------------------- 532 sal_Bool DBSubComponentController::isConnected() const 533 { 534 return m_pImpl->m_xConnection.is(); 535 } 536 537 // ----------------------------------------------------------------------------- 538 Reference< XDatabaseMetaData > DBSubComponentController::getMetaData( ) const 539 { 540 Reference< XDatabaseMetaData > xMeta; 541 try 542 { 543 if ( isConnected() ) 544 xMeta.set( m_pImpl->m_xConnection->getMetaData(), UNO_SET_THROW ); 545 } 546 catch( const Exception& ) 547 { 548 DBG_UNHANDLED_EXCEPTION(); 549 } 550 return xMeta; 551 } 552 553 // ----------------------------------------------------------------------------- 554 const Reference< XPropertySet >& DBSubComponentController::getDataSource() const 555 { 556 return m_pImpl->m_aDataSource.getDataSourceProps(); 557 } 558 559 // ----------------------------------------------------------------------------- 560 sal_Bool DBSubComponentController::haveDataSource() const 561 { 562 return m_pImpl->m_aDataSource.is(); 563 } 564 565 // ----------------------------------------------------------------------------- 566 Reference< XModel > DBSubComponentController::getDatabaseDocument() const 567 { 568 return Reference< XModel >( m_pImpl->m_aDataSource.getDatabaseDocument(), UNO_QUERY ); 569 } 570 571 // ----------------------------------------------------------------------------- 572 Reference< XNumberFormatter > DBSubComponentController::getNumberFormatter() const 573 { 574 return m_pImpl->m_xFormatter; 575 } 576 577 // ----------------------------------------------------------------------------- 578 Reference< XModel > DBSubComponentController::getPrivateModel() const 579 { 580 return getDatabaseDocument(); 581 } 582 // ----------------------------------------------------------------------------- 583 // XTitle 584 ::rtl::OUString SAL_CALL DBSubComponentController::getTitle() 585 throw (RuntimeException) 586 { 587 ::osl::MutexGuard aGuard( getMutex() ); 588 if ( m_bExternalTitle ) 589 return impl_getTitleHelper_throw()->getTitle (); 590 591 ::rtl::OUStringBuffer sTitle; 592 Reference< XTitle > xTitle(getPrivateModel(),UNO_QUERY); 593 if ( xTitle.is() ) 594 { 595 sTitle.append( xTitle->getTitle() ); 596 sTitle.appendAscii(" : "); 597 } 598 sTitle.append( getPrivateTitle() ); 599 return sTitle.makeStringAndClear(); 600 } 601 602 // ----------------------------------------------------------------------------- 603 sal_Int32 DBSubComponentController::getCurrentStartNumber() const 604 { 605 return m_pImpl->m_nDocStartNumber; 606 } 607 608 // ----------------------------------------------------------------------------- 609 Reference< XEmbeddedScripts > SAL_CALL DBSubComponentController::getScriptContainer() throw (RuntimeException) 610 { 611 ::osl::MutexGuard aGuard( getMutex() ); 612 if ( !m_pImpl->documentHasScriptSupport() ) 613 return NULL; 614 615 return Reference< XEmbeddedScripts >( getDatabaseDocument(), UNO_QUERY_THROW ); 616 } 617 618 // ----------------------------------------------------------------------------- 619 void SAL_CALL DBSubComponentController::addModifyListener( const Reference< XModifyListener >& i_Listener ) throw (RuntimeException) 620 { 621 ::osl::MutexGuard aGuard( getMutex() ); 622 m_pImpl->m_aModifyListeners.addInterface( i_Listener ); 623 } 624 625 // ----------------------------------------------------------------------------- 626 void SAL_CALL DBSubComponentController::removeModifyListener( const Reference< XModifyListener >& i_Listener ) throw (RuntimeException) 627 { 628 ::osl::MutexGuard aGuard( getMutex() ); 629 m_pImpl->m_aModifyListeners.removeInterface( i_Listener ); 630 } 631 632 // ----------------------------------------------------------------------------- 633 ::sal_Bool SAL_CALL DBSubComponentController::isModified( ) throw (RuntimeException) 634 { 635 ::osl::MutexGuard aGuard( getMutex() ); 636 return impl_isModified(); 637 } 638 639 // ----------------------------------------------------------------------------- 640 void SAL_CALL DBSubComponentController::setModified( ::sal_Bool i_bModified ) throw (PropertyVetoException, RuntimeException) 641 { 642 ::osl::ClearableMutexGuard aGuard( getMutex() ); 643 644 if ( m_pImpl->m_bModified == i_bModified ) 645 return; 646 647 m_pImpl->m_bModified = i_bModified; 648 impl_onModifyChanged(); 649 650 EventObject aEvent( *this ); 651 aGuard.clear(); 652 m_pImpl->m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent ); 653 } 654 655 // ----------------------------------------------------------------------------- 656 sal_Bool DBSubComponentController::impl_isModified() const 657 { 658 return m_pImpl->m_bModified; 659 } 660 661 // ----------------------------------------------------------------------------- 662 void DBSubComponentController::impl_onModifyChanged() 663 { 664 InvalidateFeature( ID_BROWSER_SAVEDOC ); 665 if ( isFeatureSupported( ID_BROWSER_SAVEASDOC ) ) 666 InvalidateFeature( ID_BROWSER_SAVEASDOC ); 667 } 668 669 //........................................................................ 670 } // namespace dbaui 671 //........................................................................ 672 673