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