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