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
PropertyInforptui::PropertyInfo75 PropertyInfo()
76 :bIsReadonlyOrTransient( false )
77 {
78 }
79
PropertyInforptui::PropertyInfo80 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
ObjectInforptui::ObjectInfo93 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
OXUndoEnvironmentImpl(OReportModel & _rModel)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 //------------------------------------------------------------------------------
OXUndoEnvironment(OReportModel & _rModel)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 //------------------------------------------------------------------------------
~OXUndoEnvironment()143 OXUndoEnvironment::~OXUndoEnvironment()
144 {
145 DBG_DTOR( rpt_OXUndoEnvironment,NULL);
146 }
147 // -----------------------------------------------------------------------------
Lock()148 void OXUndoEnvironment::Lock()
149 {
150 OSL_ENSURE(m_refCount,"Illegal call to dead object!");
151 osl_incrementInterlockedCount( &m_pImpl->m_nLocks );
152 }
UnLock()153 void OXUndoEnvironment::UnLock()
154 {
155 OSL_ENSURE(m_refCount,"Illegal call to dead object!");
156
157 osl_decrementInterlockedCount( &m_pImpl->m_nLocks );
158 }
IsLocked() const159 sal_Bool OXUndoEnvironment::IsLocked() const { return m_pImpl->m_nLocks != 0; }
160 // -----------------------------------------------------------------------------
RemoveSection(OReportPage * _pPage)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 //------------------------------------------------------------------------------
Clear(const Accessor &)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 //------------------------------------------------------------------------------
ModeChanged()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 //------------------------------------------------------------------------------
Notify(SfxBroadcaster &,const SfxHint & rHint)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 //------------------------------------------------------------------------------
disposing(const EventObject & e)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 //------------------------------------------------------------------------------
propertyChange(const PropertyChangeEvent & _rEvent)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 // -----------------------------------------------------------------------------
getSection(const Reference<container::XChild> & _xContainer) const383 ::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 //------------------------------------------------------------------------------
elementInserted(const ContainerEvent & evt)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 //------------------------------------------------------------------------------
implSetModified()451 void OXUndoEnvironment::implSetModified()
452 {
453 //if ( !IsLocked() )
454 m_pImpl->m_rModel.SetModified( sal_True );
455 }
456
457 //------------------------------------------------------------------------------
elementReplaced(const ContainerEvent & evt)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 //------------------------------------------------------------------------------
elementRemoved(const ContainerEvent & evt)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 //------------------------------------------------------------------------------
modified(const EventObject &)519 void SAL_CALL OXUndoEnvironment::modified( const EventObject& /*aEvent*/ ) throw (RuntimeException)
520 {
521 implSetModified();
522 }
523
524 //------------------------------------------------------------------------------
AddSection(const Reference<report::XSection> & _xSection)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 //------------------------------------------------------------------------------
RemoveSection(const Reference<report::XSection> & _xSection)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 //------------------------------------------------------------------------------
TogglePropertyListening(const Reference<XInterface> & Element)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 //------------------------------------------------------------------------------
switchListening(const Reference<XIndexAccess> & _rxContainer,bool _bStartListening)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 //------------------------------------------------------------------------------
switchListening(const Reference<XInterface> & _rxObject,bool _bStartListening)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 //------------------------------------------------------------------------------
AddElement(const Reference<XInterface> & _rxElement)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 //------------------------------------------------------------------------------
RemoveElement(const Reference<XInterface> & _rxElement)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
SetUndoMode(sal_Bool _bUndo)683 void OXUndoEnvironment::SetUndoMode(sal_Bool _bUndo)
684 {
685 m_pImpl->m_bIsUndo = _bUndo;
686 }
687
IsUndoMode() const688 sal_Bool OXUndoEnvironment::IsUndoMode() const
689 {
690 return m_pImpl->m_bIsUndo;
691 }
692 //============================================================================
693 } // rptui
694 //============================================================================
695