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 #include "UndoActions.hxx" 29 #include "UndoEnv.hxx" 30 #include "formatnormalizer.hxx" 31 #include "conditionupdater.hxx" 32 #include "corestrings.hrc" 33 #include "rptui_slotid.hrc" 34 #include "RptDef.hxx" 35 #include "ModuleHelper.hxx" 36 #include "RptObject.hxx" 37 #include "RptPage.hxx" 38 #include "RptResId.hrc" 39 #include "RptModel.hxx" 40 41 /** === begin UNO includes === **/ 42 #include <com/sun/star/script/XEventAttacherManager.hpp> 43 #include <com/sun/star/container/XChild.hpp> 44 #include <com/sun/star/container/XNameContainer.hpp> 45 #include <com/sun/star/beans/PropertyAttribute.hpp> 46 #include <com/sun/star/util/XModifyBroadcaster.hpp> 47 #include <com/sun/star/beans/XIntrospectionAccess.hpp> 48 #include <com/sun/star/beans/XIntrospection.hpp> 49 /** === end UNO includes === **/ 50 51 #include <connectivity/dbtools.hxx> 52 #include <svl/smplhint.hxx> 53 #include <tools/diagnose_ex.h> 54 #include <comphelper/stl_types.hxx> 55 #include <comphelper/componentcontext.hxx> 56 #include <vcl/svapp.hxx> 57 #include <dbaccess/dbsubcomponentcontroller.hxx> 58 #include <svx/unoshape.hxx> 59 #include <vos/mutex.hxx> 60 61 namespace rptui 62 { 63 using namespace ::com::sun::star; 64 using namespace uno; 65 using namespace lang; 66 using namespace script; 67 using namespace beans; 68 using namespace awt; 69 using namespace util; 70 using namespace container; 71 using namespace report; 72 //---------------------------------------------------------------------------- 73 74 75 struct PropertyInfo 76 { 77 bool bIsReadonlyOrTransient; 78 79 PropertyInfo() 80 :bIsReadonlyOrTransient( false ) 81 { 82 } 83 84 PropertyInfo( const bool i_bIsTransientOrReadOnly ) 85 :bIsReadonlyOrTransient( i_bIsTransientOrReadOnly ) 86 { 87 } 88 }; 89 90 typedef ::std::hash_map< ::rtl::OUString, PropertyInfo, ::rtl::OUStringHash > PropertiesInfo; 91 92 struct ObjectInfo 93 { 94 PropertiesInfo aProperties; 95 Reference< XPropertySet > xPropertyIntrospection; 96 97 ObjectInfo() 98 :aProperties() 99 ,xPropertyIntrospection() 100 { 101 } 102 }; 103 104 typedef ::std::map< Reference< XPropertySet >, ObjectInfo, ::comphelper::OInterfaceCompare< XPropertySet > > PropertySetInfoCache; 105 106 // ----------------------------------------------------------------------------- 107 108 class OXUndoEnvironmentImpl 109 { 110 OXUndoEnvironmentImpl(OXUndoEnvironmentImpl&); 111 void operator =(OXUndoEnvironmentImpl&); 112 public: 113 OReportModel& m_rModel; 114 PropertySetInfoCache m_aPropertySetCache; 115 FormatNormalizer m_aFormatNormalizer; 116 ConditionUpdater m_aConditionUpdater; 117 ::osl::Mutex m_aMutex; 118 ::std::vector< uno::Reference< container::XChild> > m_aSections; 119 Reference< XIntrospection > m_xIntrospection; 120 oslInterlockedCount m_nLocks; 121 sal_Bool m_bReadOnly; 122 sal_Bool m_bIsUndo; 123 124 OXUndoEnvironmentImpl(OReportModel& _rModel); 125 }; 126 127 OXUndoEnvironmentImpl::OXUndoEnvironmentImpl(OReportModel& _rModel) : m_rModel(_rModel) 128 ,m_aFormatNormalizer( _rModel ) 129 ,m_aConditionUpdater() 130 ,m_nLocks(0) 131 ,m_bReadOnly(sal_False) 132 ,m_bIsUndo(sal_False) 133 { 134 } 135 136 //------------------------------------------------------------------------------ 137 DBG_NAME( rpt_OXUndoEnvironment ); 138 //------------------------------------------------------------------------------ 139 OXUndoEnvironment::OXUndoEnvironment(OReportModel& _rModel) 140 :m_pImpl(new OXUndoEnvironmentImpl(_rModel) ) 141 { 142 DBG_CTOR( rpt_OXUndoEnvironment,NULL); 143 StartListening(m_pImpl->m_rModel); 144 } 145 146 //------------------------------------------------------------------------------ 147 OXUndoEnvironment::~OXUndoEnvironment() 148 { 149 DBG_DTOR( rpt_OXUndoEnvironment,NULL); 150 } 151 // ----------------------------------------------------------------------------- 152 void OXUndoEnvironment::Lock() 153 { 154 OSL_ENSURE(m_refCount,"Illegal call to dead object!"); 155 osl_incrementInterlockedCount( &m_pImpl->m_nLocks ); 156 } 157 void OXUndoEnvironment::UnLock() 158 { 159 OSL_ENSURE(m_refCount,"Illegal call to dead object!"); 160 161 osl_decrementInterlockedCount( &m_pImpl->m_nLocks ); 162 } 163 sal_Bool OXUndoEnvironment::IsLocked() const { return m_pImpl->m_nLocks != 0; } 164 // ----------------------------------------------------------------------------- 165 void OXUndoEnvironment::RemoveSection(OReportPage* _pPage) 166 { 167 if ( _pPage ) 168 { 169 Reference< XInterface > xSection(_pPage->getSection()); 170 if ( xSection.is() ) 171 RemoveElement( xSection ); 172 } 173 } 174 //------------------------------------------------------------------------------ 175 void OXUndoEnvironment::Clear(const Accessor& /*_r*/) 176 { 177 OUndoEnvLock aLock(*this); 178 179 #if OSL_DEBUG_LEVEL > 0 180 // TODO: LLA->OJ please describe what you are doing in this code fragment. 181 PropertySetInfoCache::iterator aIter = m_pImpl->m_aPropertySetCache.begin(); 182 PropertySetInfoCache::iterator aEnd = m_pImpl->m_aPropertySetCache.end(); 183 int ndbg_len = m_pImpl->m_aPropertySetCache.size(); 184 ndbg_len = ndbg_len; 185 for (int idbg_ = 0; aIter != aEnd; ++aIter,++idbg_) 186 { 187 uno::Reference<beans::XPropertySet> xProp(aIter->first,uno::UNO_QUERY); 188 xProp->getPropertySetInfo(); 189 int nlen = aIter->second.aProperties.size(); 190 nlen = nlen; 191 } 192 #endif 193 m_pImpl->m_aPropertySetCache.clear(); 194 195 sal_uInt16 nCount = m_pImpl->m_rModel.GetPageCount(); 196 sal_uInt16 i; 197 for (i = 0; i < nCount; i++) 198 { 199 OReportPage* pPage = PTR_CAST( OReportPage, m_pImpl->m_rModel.GetPage(i) ); 200 RemoveSection(pPage); 201 } 202 203 nCount = m_pImpl->m_rModel.GetMasterPageCount(); 204 for (i = 0; i < nCount; i++) 205 { 206 OReportPage* pPage = PTR_CAST( OReportPage, m_pImpl->m_rModel.GetMasterPage(i) ); 207 RemoveSection(pPage); 208 } 209 210 m_pImpl->m_aSections.clear(); 211 212 if (IsListening(m_pImpl->m_rModel)) 213 EndListening(m_pImpl->m_rModel); 214 } 215 216 //------------------------------------------------------------------------------ 217 void OXUndoEnvironment::ModeChanged() 218 { 219 m_pImpl->m_bReadOnly = !m_pImpl->m_bReadOnly; 220 221 if (!m_pImpl->m_bReadOnly) 222 StartListening(m_pImpl->m_rModel); 223 else 224 EndListening(m_pImpl->m_rModel); 225 } 226 227 //------------------------------------------------------------------------------ 228 void OXUndoEnvironment::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) 229 { 230 if (rHint.ISA(SfxSimpleHint) && ((SfxSimpleHint&)rHint).GetId() == SFX_HINT_MODECHANGED ) 231 ModeChanged(); 232 } 233 // ----------------------------------------------------------------------------- 234 // XEventListener 235 //------------------------------------------------------------------------------ 236 void SAL_CALL OXUndoEnvironment::disposing(const EventObject& e) throw( RuntimeException ) 237 { 238 // check if it's an object we have cached informations about 239 Reference< XPropertySet > xSourceSet(e.Source, UNO_QUERY); 240 if ( xSourceSet.is() ) 241 { 242 uno::Reference< report::XSection> xSection(xSourceSet,uno::UNO_QUERY); 243 if ( xSection.is() ) 244 RemoveSection(xSection); 245 else 246 RemoveElement(xSourceSet); 247 /*if (!m_pImpl->m_aPropertySetCache.empty()) 248 m_pImpl->m_aPropertySetCache.erase(xSourceSet);*/ 249 } 250 } 251 252 // XPropertyChangeListener 253 //------------------------------------------------------------------------------ 254 void SAL_CALL OXUndoEnvironment::propertyChange( const PropertyChangeEvent& _rEvent ) throw(uno::RuntimeException) 255 { 256 ::osl::ClearableMutexGuard aGuard( m_pImpl->m_aMutex ); 257 258 if ( IsLocked() ) 259 return; 260 261 Reference< XPropertySet > xSet( _rEvent.Source, UNO_QUERY ); 262 if (!xSet.is()) 263 return; 264 265 dbaui::DBSubComponentController* pController = m_pImpl->m_rModel.getController(); 266 if ( !pController ) 267 return; 268 269 // no Undo for transient and readonly props. 270 // let's see if we know something about the set 271 #if OSL_DEBUG_LEVEL > 0 272 int nlen = m_pImpl->m_aPropertySetCache.size(); 273 nlen = nlen; 274 #endif 275 PropertySetInfoCache::iterator objectPos = m_pImpl->m_aPropertySetCache.find(xSet); 276 if (objectPos == m_pImpl->m_aPropertySetCache.end()) 277 { 278 objectPos = m_pImpl->m_aPropertySetCache.insert( PropertySetInfoCache::value_type( 279 xSet, ObjectInfo() 280 ) ).first; 281 DBG_ASSERT(objectPos != m_pImpl->m_aPropertySetCache.end(), "OXUndoEnvironment::propertyChange : just inserted it ... why it's not there ?"); 282 } 283 if ( objectPos == m_pImpl->m_aPropertySetCache.end() ) 284 return; 285 286 // now we have access to the cached info about the set 287 // let's see what we know about the property 288 ObjectInfo& rObjectInfo = objectPos->second; 289 PropertiesInfo::iterator aPropertyPos = rObjectInfo.aProperties.find( _rEvent.PropertyName ); 290 if ( aPropertyPos == rObjectInfo.aProperties.end() ) 291 { // nothing 'til now ... have to change this .... 292 // the attributes 293 Reference< XPropertySetInfo > xPSI( xSet->getPropertySetInfo(), UNO_SET_THROW ); 294 sal_Int32 nPropertyAttributes = 0; 295 try 296 { 297 if ( xPSI->hasPropertyByName( _rEvent.PropertyName ) ) 298 { 299 nPropertyAttributes = xPSI->getPropertyByName( _rEvent.PropertyName ).Attributes; 300 } 301 else 302 { 303 // it's perfectly valid for a component to notify a change in a property which it doesn't have - as long 304 // as it has an attribute with this name 305 if ( !rObjectInfo.xPropertyIntrospection.is() ) 306 { 307 if ( !m_pImpl->m_xIntrospection.is() ) 308 { 309 ::comphelper::ComponentContext aContext( m_pImpl->m_rModel.getController()->getORB() ); 310 OSL_VERIFY( aContext.createComponent( "com.sun.star.beans.Introspection", m_pImpl->m_xIntrospection ) ); 311 } 312 if ( m_pImpl->m_xIntrospection.is() ) 313 { 314 Reference< XIntrospectionAccess > xIntrospection( 315 m_pImpl->m_xIntrospection->inspect( makeAny( _rEvent.Source ) ), 316 UNO_SET_THROW 317 ); 318 rObjectInfo.xPropertyIntrospection.set( xIntrospection->queryAdapter( XPropertySet::static_type() ), UNO_QUERY_THROW ); 319 } 320 } 321 if ( rObjectInfo.xPropertyIntrospection.is() ) 322 { 323 xPSI.set( rObjectInfo.xPropertyIntrospection->getPropertySetInfo(), UNO_SET_THROW ); 324 nPropertyAttributes = xPSI->getPropertyByName( _rEvent.PropertyName ).Attributes; 325 } 326 } 327 } 328 catch( const Exception& ) 329 { 330 DBG_UNHANDLED_EXCEPTION(); 331 } 332 const bool bTransReadOnly = 333 ( ( nPropertyAttributes & PropertyAttribute::READONLY ) != 0 ) 334 || ( ( nPropertyAttributes & PropertyAttribute::TRANSIENT ) != 0 ); 335 336 // insert the new entry 337 aPropertyPos = rObjectInfo.aProperties.insert( PropertiesInfo::value_type( 338 _rEvent.PropertyName, 339 PropertyInfo( bTransReadOnly ) 340 ) ).first; 341 DBG_ASSERT(aPropertyPos != rObjectInfo.aProperties.end(), "OXUndoEnvironment::propertyChange : just inserted it ... why it's not there ?"); 342 } 343 344 implSetModified(); 345 346 // now we have access to the cached info about the property affected 347 // and are able to decide wether or not we need an undo action 348 349 // no UNDO for transient/readonly properties 350 if ( aPropertyPos->second.bIsReadonlyOrTransient ) 351 return; 352 353 // give components with sub responsibilities a chance 354 m_pImpl->m_aFormatNormalizer.notifyPropertyChange( _rEvent ); 355 m_pImpl->m_aConditionUpdater.notifyPropertyChange( _rEvent ); 356 357 aGuard.clear(); 358 // TODO: this is a potential race condition: two threads here could in theory 359 // add their undo actions out-of-order 360 361 ::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() ); 362 ORptUndoPropertyAction* pUndo = NULL; 363 try 364 { 365 uno::Reference< report::XSection> xSection( xSet, uno::UNO_QUERY ); 366 if ( xSection.is() ) 367 { 368 uno::Reference< report::XGroup> xGroup = xSection->getGroup(); 369 if ( xGroup.is() ) 370 pUndo = new OUndoPropertyGroupSectionAction( m_pImpl->m_rModel, _rEvent, OGroupHelper::getMemberFunction( xSection ), xGroup ); 371 else 372 pUndo = new OUndoPropertyReportSectionAction( m_pImpl->m_rModel, _rEvent, OReportHelper::getMemberFunction( xSection ), xSection->getReportDefinition() ); 373 } 374 } 375 catch(const Exception&) 376 { 377 DBG_UNHANDLED_EXCEPTION(); 378 } 379 380 if ( pUndo == NULL ) 381 pUndo = new ORptUndoPropertyAction( m_pImpl->m_rModel, _rEvent ); 382 383 m_pImpl->m_rModel.GetSdrUndoManager()->AddUndoAction( pUndo ); 384 pController->InvalidateAll(); 385 } 386 // ----------------------------------------------------------------------------- 387 ::std::vector< uno::Reference< container::XChild> >::const_iterator OXUndoEnvironment::getSection(const Reference<container::XChild>& _xContainer) const 388 { 389 ::std::vector< uno::Reference< container::XChild> >::const_iterator aFind = m_pImpl->m_aSections.end(); 390 if ( _xContainer.is() ) 391 { 392 aFind = ::std::find(m_pImpl->m_aSections.begin(),m_pImpl->m_aSections.end(),_xContainer); 393 394 if ( aFind == m_pImpl->m_aSections.end() ) 395 { 396 Reference<container::XChild> xParent(_xContainer->getParent(),uno::UNO_QUERY); 397 aFind = getSection(xParent); 398 } 399 } 400 return aFind; 401 } 402 // XContainerListener 403 //------------------------------------------------------------------------------ 404 void SAL_CALL OXUndoEnvironment::elementInserted(const ContainerEvent& evt) throw(uno::RuntimeException) 405 { 406 ::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() ); 407 ::osl::MutexGuard aGuard( m_pImpl->m_aMutex ); 408 409 // neues Object zum lauschen 410 Reference< uno::XInterface > xIface( evt.Element, UNO_QUERY ); 411 if ( !IsLocked() ) 412 { 413 Reference< report::XReportComponent > xReportComponent( xIface, UNO_QUERY ); 414 if ( xReportComponent.is() ) 415 { 416 Reference< report::XSection > xContainer(evt.Source,uno::UNO_QUERY); 417 418 ::std::vector< uno::Reference< container::XChild> >::const_iterator aFind = getSection(xContainer.get()); 419 420 if ( aFind != m_pImpl->m_aSections.end() ) 421 { 422 OUndoEnvLock aLock(*this); 423 try 424 { 425 OReportPage* pPage = m_pImpl->m_rModel.getPage(uno::Reference< report::XSection>(*aFind,uno::UNO_QUERY)); 426 OSL_ENSURE(pPage,"No page could be found for section!"); 427 if ( pPage ) 428 pPage->insertObject(xReportComponent); 429 } 430 catch(uno::Exception&) 431 { 432 DBG_UNHANDLED_EXCEPTION(); 433 } 434 435 } 436 } 437 else 438 { 439 uno::Reference< report::XFunctions> xContainer(evt.Source,uno::UNO_QUERY); 440 if ( xContainer.is() ) 441 { 442 m_pImpl->m_rModel.GetSdrUndoManager()->AddUndoAction( 443 new OUndoContainerAction( m_pImpl->m_rModel, rptui::Inserted, xContainer.get(), 444 xIface, RID_STR_UNDO_ADDFUNCTION ) ); 445 } 446 } 447 } 448 449 AddElement(xIface); 450 451 implSetModified(); 452 } 453 454 //------------------------------------------------------------------------------ 455 void OXUndoEnvironment::implSetModified() 456 { 457 //if ( !IsLocked() ) 458 m_pImpl->m_rModel.SetModified( sal_True ); 459 } 460 461 //------------------------------------------------------------------------------ 462 void SAL_CALL OXUndoEnvironment::elementReplaced(const ContainerEvent& evt) throw(uno::RuntimeException) 463 { 464 ::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() ); 465 ::osl::MutexGuard aGuard( m_pImpl->m_aMutex ); 466 467 Reference< XInterface > xIface(evt.ReplacedElement,uno::UNO_QUERY); 468 OSL_ENSURE(xIface.is(), "OXUndoEnvironment::elementReplaced: invalid container notification!"); 469 RemoveElement(xIface); 470 471 xIface.set(evt.Element,uno::UNO_QUERY); 472 AddElement(xIface); 473 474 implSetModified(); 475 } 476 477 //------------------------------------------------------------------------------ 478 void SAL_CALL OXUndoEnvironment::elementRemoved(const ContainerEvent& evt) throw(uno::RuntimeException) 479 { 480 ::vos::OClearableGuard aSolarGuard( Application::GetSolarMutex() ); 481 ::osl::MutexGuard aGuard( m_pImpl->m_aMutex ); 482 483 Reference< uno::XInterface > xIface( evt.Element, UNO_QUERY ); 484 if ( !IsLocked() ) 485 { 486 Reference< report::XSection > xContainer(evt.Source,uno::UNO_QUERY); 487 ::std::vector< uno::Reference< container::XChild> >::const_iterator aFind = getSection(xContainer.get()); 488 489 Reference< report::XReportComponent > xReportComponent( xIface, UNO_QUERY ); 490 if ( aFind != m_pImpl->m_aSections.end() && xReportComponent.is() ) 491 { 492 OXUndoEnvironment::OUndoEnvLock aLock(*this); 493 try 494 { 495 OReportPage* pPage = m_pImpl->m_rModel.getPage(uno::Reference< report::XSection >( *aFind, uno::UNO_QUERY_THROW ) ); 496 OSL_ENSURE( pPage, "OXUndoEnvironment::elementRemoved: no page for the section!" ); 497 if ( pPage ) 498 pPage->removeSdrObject(xReportComponent); 499 } 500 catch(const uno::Exception&) 501 { 502 DBG_UNHANDLED_EXCEPTION(); 503 } 504 } 505 else 506 { 507 uno::Reference< report::XFunctions> xFunctions(evt.Source,uno::UNO_QUERY); 508 if ( xFunctions.is() ) 509 { 510 m_pImpl->m_rModel.GetSdrUndoManager()->AddUndoAction( new OUndoContainerAction( 511 m_pImpl->m_rModel, rptui::Removed, xFunctions.get(), xIface, RID_STR_UNDO_ADDFUNCTION ) ); 512 } 513 } 514 } 515 516 if ( xIface.is() ) 517 RemoveElement(xIface); 518 519 implSetModified(); 520 } 521 522 //------------------------------------------------------------------------------ 523 void SAL_CALL OXUndoEnvironment::modified( const EventObject& /*aEvent*/ ) throw (RuntimeException) 524 { 525 implSetModified(); 526 } 527 528 //------------------------------------------------------------------------------ 529 void OXUndoEnvironment::AddSection(const Reference< report::XSection > & _xSection) 530 { 531 OUndoEnvLock aLock(*this); 532 try 533 { 534 uno::Reference<container::XChild> xChild = _xSection.get(); 535 uno::Reference<report::XGroup> xGroup(xChild->getParent(),uno::UNO_QUERY); 536 m_pImpl->m_aSections.push_back(xChild); 537 Reference< XInterface > xInt(_xSection); 538 AddElement(xInt); 539 } 540 catch(const uno::Exception&) 541 { 542 DBG_UNHANDLED_EXCEPTION(); 543 } 544 } 545 546 //------------------------------------------------------------------------------ 547 void OXUndoEnvironment::RemoveSection(const Reference< report::XSection > & _xSection) 548 { 549 OUndoEnvLock aLock(*this); 550 try 551 { 552 uno::Reference<container::XChild> xChild(_xSection.get()); 553 m_pImpl->m_aSections.erase(::std::remove(m_pImpl->m_aSections.begin(),m_pImpl->m_aSections.end(), 554 xChild), m_pImpl->m_aSections.end()); 555 Reference< XInterface > xInt(_xSection); 556 RemoveElement(xInt); 557 } 558 catch(uno::Exception&){} 559 } 560 561 //------------------------------------------------------------------------------ 562 void OXUndoEnvironment::TogglePropertyListening(const Reference< XInterface > & Element) 563 { 564 // am Container horchen 565 Reference< XIndexAccess > xContainer(Element, UNO_QUERY); 566 if (xContainer.is()) 567 { 568 Reference< XInterface > xInterface; 569 sal_Int32 nCount = xContainer->getCount(); 570 for(sal_Int32 i = 0;i != nCount;++i) 571 { 572 xInterface.set(xContainer->getByIndex( i ),uno::UNO_QUERY); 573 TogglePropertyListening(xInterface); 574 } 575 } 576 577 Reference< XPropertySet > xSet(Element, UNO_QUERY); 578 if (xSet.is()) 579 { 580 if (!m_pImpl->m_bReadOnly) 581 xSet->addPropertyChangeListener( ::rtl::OUString(), this ); 582 else 583 xSet->removePropertyChangeListener( ::rtl::OUString(), this ); 584 } 585 } 586 587 588 //------------------------------------------------------------------------------ 589 void OXUndoEnvironment::switchListening( const Reference< XIndexAccess >& _rxContainer, bool _bStartListening ) SAL_THROW(()) 590 { 591 OSL_PRECOND( _rxContainer.is(), "OXUndoEnvironment::switchListening: invalid container!" ); 592 if ( !_rxContainer.is() ) 593 return; 594 595 try 596 { 597 // also handle all children of this element 598 Reference< XInterface > xInterface; 599 sal_Int32 nCount = _rxContainer->getCount(); 600 for(sal_Int32 i = 0;i != nCount;++i) 601 { 602 xInterface.set(_rxContainer->getByIndex( i ),uno::UNO_QUERY); 603 if ( _bStartListening ) 604 AddElement( xInterface ); 605 else 606 RemoveElement( xInterface ); 607 } 608 609 // be notified of any changes in the container elements 610 Reference< XContainer > xSimpleContainer( _rxContainer, UNO_QUERY ); 611 // OSL_ENSURE( xSimpleContainer.is(), "OXUndoEnvironment::switchListening: how are we expected to be notified of changes in the container?" ); 612 if ( xSimpleContainer.is() ) 613 { 614 if ( _bStartListening ) 615 xSimpleContainer->addContainerListener( this ); 616 else 617 xSimpleContainer->removeContainerListener( this ); 618 } 619 } 620 catch( const Exception& ) 621 { 622 DBG_UNHANDLED_EXCEPTION(); 623 } 624 } 625 626 //------------------------------------------------------------------------------ 627 void OXUndoEnvironment::switchListening( const Reference< XInterface >& _rxObject, bool _bStartListening ) SAL_THROW(()) 628 { 629 OSL_PRECOND( _rxObject.is(), "OXUndoEnvironment::switchListening: how should I listen at a NULL object?" ); 630 631 try 632 { 633 if ( !m_pImpl->m_bReadOnly ) 634 { 635 Reference< XPropertySet > xProps( _rxObject, UNO_QUERY ); 636 if ( xProps.is() ) 637 { 638 if ( _bStartListening ) 639 xProps->addPropertyChangeListener( ::rtl::OUString(), this ); 640 else 641 xProps->removePropertyChangeListener( ::rtl::OUString(), this ); 642 } 643 } 644 645 Reference< XModifyBroadcaster > xBroadcaster( _rxObject, UNO_QUERY ); 646 if ( xBroadcaster.is() ) 647 { 648 if ( _bStartListening ) 649 xBroadcaster->addModifyListener( this ); 650 else 651 xBroadcaster->removeModifyListener( this ); 652 } 653 } 654 catch( const Exception& ) 655 { 656 //OSL_ENSURE( sal_False, "OXUndoEnvironment::switchListening: caught an exception!" ); 657 } 658 } 659 660 //------------------------------------------------------------------------------ 661 void OXUndoEnvironment::AddElement(const Reference< XInterface >& _rxElement ) 662 { 663 if ( !IsLocked() ) 664 m_pImpl->m_aFormatNormalizer.notifyElementInserted( _rxElement ); 665 666 // if it's a container, start listening at all elements 667 Reference< XIndexAccess > xContainer( _rxElement, UNO_QUERY ); 668 if ( xContainer.is() ) 669 switchListening( xContainer, true ); 670 671 switchListening( _rxElement, true ); 672 } 673 674 //------------------------------------------------------------------------------ 675 void OXUndoEnvironment::RemoveElement(const Reference< XInterface >& _rxElement) 676 { 677 uno::Reference<beans::XPropertySet> xProp(_rxElement,uno::UNO_QUERY); 678 if (!m_pImpl->m_aPropertySetCache.empty()) 679 m_pImpl->m_aPropertySetCache.erase(xProp); 680 switchListening( _rxElement, false ); 681 682 Reference< XIndexAccess > xContainer( _rxElement, UNO_QUERY ); 683 if ( xContainer.is() ) 684 switchListening( xContainer, false ); 685 } 686 687 void OXUndoEnvironment::SetUndoMode(sal_Bool _bUndo) 688 { 689 m_pImpl->m_bIsUndo = _bUndo; 690 } 691 692 sal_Bool OXUndoEnvironment::IsUndoMode() const 693 { 694 return m_pImpl->m_bIsUndo; 695 } 696 //============================================================================ 697 } // rptui 698 //============================================================================ 699