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