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/Introspection.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 : DBG_NAME( rpt_OXUndoEnvironment );
127 : //------------------------------------------------------------------------------
128 0 : OXUndoEnvironment::OXUndoEnvironment(OReportModel& _rModel)
129 0 : :m_pImpl(new OXUndoEnvironmentImpl(_rModel) )
130 : {
131 : DBG_CTOR( rpt_OXUndoEnvironment,NULL);
132 0 : StartListening(m_pImpl->m_rModel);
133 0 : }
134 :
135 : //------------------------------------------------------------------------------
136 0 : OXUndoEnvironment::~OXUndoEnvironment()
137 : {
138 : DBG_DTOR( rpt_OXUndoEnvironment,NULL);
139 0 : }
140 : // -----------------------------------------------------------------------------
141 0 : void OXUndoEnvironment::Lock()
142 : {
143 : OSL_ENSURE(m_refCount,"Illegal call to dead object!");
144 0 : osl_atomic_increment( &m_pImpl->m_nLocks );
145 0 : }
146 0 : void OXUndoEnvironment::UnLock()
147 : {
148 : OSL_ENSURE(m_refCount,"Illegal call to dead object!");
149 :
150 0 : osl_atomic_decrement( &m_pImpl->m_nLocks );
151 0 : }
152 0 : sal_Bool OXUndoEnvironment::IsLocked() const { return m_pImpl->m_nLocks != 0; }
153 : // -----------------------------------------------------------------------------
154 0 : void OXUndoEnvironment::RemoveSection(OReportPage* _pPage)
155 : {
156 0 : if ( _pPage )
157 : {
158 0 : Reference< XInterface > xSection(_pPage->getSection());
159 0 : if ( xSection.is() )
160 0 : RemoveElement( xSection );
161 : }
162 0 : }
163 : //------------------------------------------------------------------------------
164 0 : void OXUndoEnvironment::Clear(const Accessor& /*_r*/)
165 : {
166 0 : OUndoEnvLock aLock(*this);
167 :
168 0 : m_pImpl->m_aPropertySetCache.clear();
169 :
170 0 : sal_uInt16 nCount = m_pImpl->m_rModel.GetPageCount();
171 : sal_uInt16 i;
172 0 : for (i = 0; i < nCount; i++)
173 : {
174 0 : OReportPage* pPage = PTR_CAST( OReportPage, m_pImpl->m_rModel.GetPage(i) );
175 0 : RemoveSection(pPage);
176 : }
177 :
178 0 : nCount = m_pImpl->m_rModel.GetMasterPageCount();
179 0 : for (i = 0; i < nCount; i++)
180 : {
181 0 : OReportPage* pPage = PTR_CAST( OReportPage, m_pImpl->m_rModel.GetMasterPage(i) );
182 0 : RemoveSection(pPage);
183 : }
184 :
185 0 : m_pImpl->m_aSections.clear();
186 :
187 0 : if (IsListening(m_pImpl->m_rModel))
188 0 : EndListening(m_pImpl->m_rModel);
189 0 : }
190 :
191 : //------------------------------------------------------------------------------
192 0 : void OXUndoEnvironment::ModeChanged()
193 : {
194 0 : m_pImpl->m_bReadOnly = !m_pImpl->m_bReadOnly;
195 :
196 0 : if (!m_pImpl->m_bReadOnly)
197 0 : StartListening(m_pImpl->m_rModel);
198 : else
199 0 : EndListening(m_pImpl->m_rModel);
200 0 : }
201 :
202 : //------------------------------------------------------------------------------
203 0 : void OXUndoEnvironment::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
204 : {
205 0 : if (rHint.ISA(SfxSimpleHint) && ((SfxSimpleHint&)rHint).GetId() == SFX_HINT_MODECHANGED )
206 0 : ModeChanged();
207 0 : }
208 : // -----------------------------------------------------------------------------
209 : // XEventListener
210 : //------------------------------------------------------------------------------
211 0 : void SAL_CALL OXUndoEnvironment::disposing(const EventObject& e) throw( RuntimeException )
212 : {
213 : // check if it's an object we have cached information about
214 0 : Reference< XPropertySet > xSourceSet(e.Source, UNO_QUERY);
215 0 : if ( xSourceSet.is() )
216 : {
217 0 : uno::Reference< report::XSection> xSection(xSourceSet,uno::UNO_QUERY);
218 0 : if ( xSection.is() )
219 0 : RemoveSection(xSection);
220 : else
221 0 : RemoveElement(xSourceSet);
222 0 : }
223 0 : }
224 :
225 : // XPropertyChangeListener
226 : //------------------------------------------------------------------------------
227 0 : void SAL_CALL OXUndoEnvironment::propertyChange( const PropertyChangeEvent& _rEvent ) throw(uno::RuntimeException)
228 : {
229 :
230 0 : ::osl::ClearableMutexGuard aGuard( m_pImpl->m_aMutex );
231 :
232 0 : if ( IsLocked() )
233 0 : return;
234 :
235 0 : Reference< XPropertySet > xSet( _rEvent.Source, UNO_QUERY );
236 0 : if (!xSet.is())
237 0 : return;
238 :
239 0 : dbaui::DBSubComponentController* pController = m_pImpl->m_rModel.getController();
240 0 : if ( !pController )
241 0 : return;
242 :
243 : // no Undo for transient and readonly props.
244 : // let's see if we know something about the set
245 0 : PropertySetInfoCache::iterator objectPos = m_pImpl->m_aPropertySetCache.find(xSet);
246 0 : if (objectPos == m_pImpl->m_aPropertySetCache.end())
247 : {
248 0 : objectPos = m_pImpl->m_aPropertySetCache.insert( PropertySetInfoCache::value_type(
249 : xSet, ObjectInfo()
250 0 : ) ).first;
251 : DBG_ASSERT(objectPos != m_pImpl->m_aPropertySetCache.end(), "OXUndoEnvironment::propertyChange : just inserted it ... why it's not there ?");
252 : }
253 0 : if ( objectPos == m_pImpl->m_aPropertySetCache.end() )
254 0 : return;
255 :
256 : // now we have access to the cached info about the set
257 : // let's see what we know about the property
258 0 : ObjectInfo& rObjectInfo = objectPos->second;
259 0 : PropertiesInfo::iterator aPropertyPos = rObjectInfo.aProperties.find( _rEvent.PropertyName );
260 0 : if ( aPropertyPos == rObjectInfo.aProperties.end() )
261 : { // nothing 'til now ... have to change this ....
262 : // the attributes
263 0 : Reference< XPropertySetInfo > xPSI( xSet->getPropertySetInfo(), UNO_SET_THROW );
264 0 : sal_Int32 nPropertyAttributes = 0;
265 : try
266 : {
267 0 : if ( xPSI->hasPropertyByName( _rEvent.PropertyName ) )
268 : {
269 0 : nPropertyAttributes = xPSI->getPropertyByName( _rEvent.PropertyName ).Attributes;
270 : }
271 : else
272 : {
273 : // it's perfectly valid for a component to notify a change in a property which it doesn't have - as long
274 : // as it has an attribute with this name
275 0 : if ( !rObjectInfo.xPropertyIntrospection.is() )
276 : {
277 0 : if ( !m_pImpl->m_xIntrospection.is() )
278 : {
279 0 : m_pImpl->m_xIntrospection = Introspection::create( m_pImpl->m_rModel.getController()->getORB() );
280 : }
281 : Reference< XIntrospectionAccess > xIntrospection(
282 0 : m_pImpl->m_xIntrospection->inspect( makeAny( _rEvent.Source ) ),
283 : UNO_SET_THROW
284 0 : );
285 0 : rObjectInfo.xPropertyIntrospection.set( xIntrospection->queryAdapter( XPropertySet::static_type() ), UNO_QUERY_THROW );
286 : }
287 0 : if ( rObjectInfo.xPropertyIntrospection.is() )
288 : {
289 0 : xPSI.set( rObjectInfo.xPropertyIntrospection->getPropertySetInfo(), UNO_SET_THROW );
290 0 : nPropertyAttributes = xPSI->getPropertyByName( _rEvent.PropertyName ).Attributes;
291 : }
292 : }
293 : }
294 0 : catch( const Exception& )
295 : {
296 : DBG_UNHANDLED_EXCEPTION();
297 : }
298 : const bool bTransReadOnly =
299 0 : ( ( nPropertyAttributes & PropertyAttribute::READONLY ) != 0 )
300 0 : || ( ( nPropertyAttributes & PropertyAttribute::TRANSIENT ) != 0 );
301 :
302 : // insert the new entry
303 : aPropertyPos = rObjectInfo.aProperties.insert( PropertiesInfo::value_type(
304 : _rEvent.PropertyName,
305 : PropertyInfo( bTransReadOnly )
306 0 : ) ).first;
307 0 : DBG_ASSERT(aPropertyPos != rObjectInfo.aProperties.end(), "OXUndoEnvironment::propertyChange : just inserted it ... why it's not there ?");
308 : }
309 :
310 0 : implSetModified();
311 :
312 : // now we have access to the cached info about the property affected
313 : // and are able to decide whether or not we need an undo action
314 :
315 : // no UNDO for transient/readonly properties
316 0 : if ( aPropertyPos->second.bIsReadonlyOrTransient )
317 0 : return;
318 :
319 : // give components with sub responsibilities a chance
320 0 : m_pImpl->m_aFormatNormalizer.notifyPropertyChange( _rEvent );
321 0 : m_pImpl->m_aConditionUpdater.notifyPropertyChange( _rEvent );
322 :
323 0 : aGuard.clear();
324 : // TODO: this is a potential race condition: two threads here could in theory
325 : // add their undo actions out-of-order
326 :
327 0 : SolarMutexGuard aSolarGuard;
328 0 : ORptUndoPropertyAction* pUndo = NULL;
329 : try
330 : {
331 0 : uno::Reference< report::XSection> xSection( xSet, uno::UNO_QUERY );
332 0 : if ( xSection.is() )
333 : {
334 0 : uno::Reference< report::XGroup> xGroup = xSection->getGroup();
335 0 : if ( xGroup.is() )
336 0 : pUndo = new OUndoPropertyGroupSectionAction( m_pImpl->m_rModel, _rEvent, OGroupHelper::getMemberFunction( xSection ), xGroup );
337 : else
338 0 : pUndo = new OUndoPropertyReportSectionAction( m_pImpl->m_rModel, _rEvent, OReportHelper::getMemberFunction( xSection ), xSection->getReportDefinition() );
339 0 : }
340 : }
341 0 : catch(const Exception&)
342 : {
343 : DBG_UNHANDLED_EXCEPTION();
344 : }
345 :
346 0 : if ( pUndo == NULL )
347 0 : pUndo = new ORptUndoPropertyAction( m_pImpl->m_rModel, _rEvent );
348 :
349 0 : m_pImpl->m_rModel.GetSdrUndoManager()->AddUndoAction( pUndo );
350 0 : pController->InvalidateAll();
351 : }
352 : // -----------------------------------------------------------------------------
353 0 : ::std::vector< uno::Reference< container::XChild> >::const_iterator OXUndoEnvironment::getSection(const Reference<container::XChild>& _xContainer) const
354 : {
355 0 : ::std::vector< uno::Reference< container::XChild> >::const_iterator aFind = m_pImpl->m_aSections.end();
356 0 : if ( _xContainer.is() )
357 : {
358 0 : aFind = ::std::find(m_pImpl->m_aSections.begin(),m_pImpl->m_aSections.end(),_xContainer);
359 :
360 0 : if ( aFind == m_pImpl->m_aSections.end() )
361 : {
362 0 : Reference<container::XChild> xParent(_xContainer->getParent(),uno::UNO_QUERY);
363 0 : aFind = getSection(xParent);
364 : }
365 : }
366 0 : return aFind;
367 : }
368 : // XContainerListener
369 : //------------------------------------------------------------------------------
370 0 : void SAL_CALL OXUndoEnvironment::elementInserted(const ContainerEvent& evt) throw(uno::RuntimeException)
371 : {
372 0 : SolarMutexGuard aSolarGuard;
373 0 : ::osl::MutexGuard aGuard( m_pImpl->m_aMutex );
374 :
375 : // neues Object zum lauschen
376 0 : Reference< uno::XInterface > xIface( evt.Element, UNO_QUERY );
377 0 : if ( !IsLocked() )
378 : {
379 0 : Reference< report::XReportComponent > xReportComponent( xIface, UNO_QUERY );
380 0 : if ( xReportComponent.is() )
381 : {
382 0 : Reference< report::XSection > xContainer(evt.Source,uno::UNO_QUERY);
383 :
384 0 : ::std::vector< uno::Reference< container::XChild> >::const_iterator aFind = getSection(xContainer.get());
385 :
386 0 : if ( aFind != m_pImpl->m_aSections.end() )
387 : {
388 0 : OUndoEnvLock aLock(*this);
389 : try
390 : {
391 0 : OReportPage* pPage = m_pImpl->m_rModel.getPage(uno::Reference< report::XSection>(*aFind,uno::UNO_QUERY));
392 : OSL_ENSURE(pPage,"No page could be found for section!");
393 0 : if ( pPage )
394 0 : pPage->insertObject(xReportComponent);
395 : }
396 0 : catch(uno::Exception&)
397 : {
398 : DBG_UNHANDLED_EXCEPTION();
399 0 : }
400 :
401 0 : }
402 : }
403 : else
404 : {
405 0 : uno::Reference< report::XFunctions> xContainer(evt.Source,uno::UNO_QUERY);
406 0 : if ( xContainer.is() )
407 : {
408 0 : m_pImpl->m_rModel.GetSdrUndoManager()->AddUndoAction(
409 0 : new OUndoContainerAction( m_pImpl->m_rModel, rptui::Inserted, xContainer.get(),
410 0 : xIface, RID_STR_UNDO_ADDFUNCTION ) );
411 0 : }
412 0 : }
413 : }
414 :
415 0 : AddElement(xIface);
416 :
417 0 : implSetModified();
418 0 : }
419 :
420 : //------------------------------------------------------------------------------
421 0 : void OXUndoEnvironment::implSetModified()
422 : {
423 0 : m_pImpl->m_rModel.SetModified( sal_True );
424 0 : }
425 :
426 : //------------------------------------------------------------------------------
427 0 : void SAL_CALL OXUndoEnvironment::elementReplaced(const ContainerEvent& evt) throw(uno::RuntimeException)
428 : {
429 0 : SolarMutexGuard aSolarGuard;
430 0 : ::osl::MutexGuard aGuard( m_pImpl->m_aMutex );
431 :
432 0 : Reference< XInterface > xIface(evt.ReplacedElement,uno::UNO_QUERY);
433 : OSL_ENSURE(xIface.is(), "OXUndoEnvironment::elementReplaced: invalid container notification!");
434 0 : RemoveElement(xIface);
435 :
436 0 : xIface.set(evt.Element,uno::UNO_QUERY);
437 0 : AddElement(xIface);
438 :
439 0 : implSetModified();
440 0 : }
441 :
442 : //------------------------------------------------------------------------------
443 0 : void SAL_CALL OXUndoEnvironment::elementRemoved(const ContainerEvent& evt) throw(uno::RuntimeException)
444 : {
445 0 : SolarMutexGuard aSolarGuard;
446 0 : ::osl::MutexGuard aGuard( m_pImpl->m_aMutex );
447 :
448 0 : Reference< uno::XInterface > xIface( evt.Element, UNO_QUERY );
449 0 : if ( !IsLocked() )
450 : {
451 0 : Reference< report::XSection > xContainer(evt.Source,uno::UNO_QUERY);
452 0 : ::std::vector< uno::Reference< container::XChild> >::const_iterator aFind = getSection(xContainer.get());
453 :
454 0 : Reference< report::XReportComponent > xReportComponent( xIface, UNO_QUERY );
455 0 : if ( aFind != m_pImpl->m_aSections.end() && xReportComponent.is() )
456 : {
457 0 : OXUndoEnvironment::OUndoEnvLock aLock(*this);
458 : try
459 : {
460 0 : OReportPage* pPage = m_pImpl->m_rModel.getPage(uno::Reference< report::XSection >( *aFind, uno::UNO_QUERY_THROW ) );
461 : OSL_ENSURE( pPage, "OXUndoEnvironment::elementRemoved: no page for the section!" );
462 0 : if ( pPage )
463 0 : pPage->removeSdrObject(xReportComponent);
464 : }
465 0 : catch(const uno::Exception&)
466 : {
467 : DBG_UNHANDLED_EXCEPTION();
468 0 : }
469 : }
470 : else
471 : {
472 0 : uno::Reference< report::XFunctions> xFunctions(evt.Source,uno::UNO_QUERY);
473 0 : if ( xFunctions.is() )
474 : {
475 0 : m_pImpl->m_rModel.GetSdrUndoManager()->AddUndoAction( new OUndoContainerAction(
476 0 : m_pImpl->m_rModel, rptui::Removed, xFunctions.get(), xIface, RID_STR_UNDO_ADDFUNCTION ) );
477 0 : }
478 0 : }
479 : }
480 :
481 0 : if ( xIface.is() )
482 0 : RemoveElement(xIface);
483 :
484 0 : implSetModified();
485 0 : }
486 :
487 : //------------------------------------------------------------------------------
488 0 : void SAL_CALL OXUndoEnvironment::modified( const EventObject& /*aEvent*/ ) throw (RuntimeException)
489 : {
490 0 : implSetModified();
491 0 : }
492 :
493 : //------------------------------------------------------------------------------
494 0 : void OXUndoEnvironment::AddSection(const Reference< report::XSection > & _xSection)
495 : {
496 0 : OUndoEnvLock aLock(*this);
497 : try
498 : {
499 0 : uno::Reference<container::XChild> xChild = _xSection.get();
500 0 : uno::Reference<report::XGroup> xGroup(xChild->getParent(),uno::UNO_QUERY);
501 0 : m_pImpl->m_aSections.push_back(xChild);
502 0 : Reference< XInterface > xInt(_xSection);
503 0 : AddElement(xInt);
504 : }
505 0 : catch(const uno::Exception&)
506 : {
507 : DBG_UNHANDLED_EXCEPTION();
508 0 : }
509 0 : }
510 :
511 : //------------------------------------------------------------------------------
512 0 : void OXUndoEnvironment::RemoveSection(const Reference< report::XSection > & _xSection)
513 : {
514 0 : OUndoEnvLock aLock(*this);
515 : try
516 : {
517 0 : uno::Reference<container::XChild> xChild(_xSection.get());
518 0 : m_pImpl->m_aSections.erase(::std::remove(m_pImpl->m_aSections.begin(),m_pImpl->m_aSections.end(),
519 0 : xChild), m_pImpl->m_aSections.end());
520 0 : Reference< XInterface > xInt(_xSection);
521 0 : RemoveElement(xInt);
522 : }
523 0 : catch(uno::Exception&){}
524 0 : }
525 :
526 : //------------------------------------------------------------------------------
527 0 : void OXUndoEnvironment::TogglePropertyListening(const Reference< XInterface > & Element)
528 : {
529 : // am Container horchen
530 0 : Reference< XIndexAccess > xContainer(Element, UNO_QUERY);
531 0 : if (xContainer.is())
532 : {
533 0 : Reference< XInterface > xInterface;
534 0 : sal_Int32 nCount = xContainer->getCount();
535 0 : for(sal_Int32 i = 0;i != nCount;++i)
536 : {
537 0 : xInterface.set(xContainer->getByIndex( i ),uno::UNO_QUERY);
538 0 : TogglePropertyListening(xInterface);
539 0 : }
540 : }
541 :
542 0 : Reference< XPropertySet > xSet(Element, UNO_QUERY);
543 0 : if (xSet.is())
544 : {
545 0 : if (!m_pImpl->m_bReadOnly)
546 0 : xSet->addPropertyChangeListener( OUString(), this );
547 : else
548 0 : xSet->removePropertyChangeListener( OUString(), this );
549 0 : }
550 0 : }
551 :
552 :
553 : //------------------------------------------------------------------------------
554 0 : void OXUndoEnvironment::switchListening( const Reference< XIndexAccess >& _rxContainer, bool _bStartListening ) SAL_THROW(())
555 : {
556 : OSL_PRECOND( _rxContainer.is(), "OXUndoEnvironment::switchListening: invalid container!" );
557 0 : if ( !_rxContainer.is() )
558 0 : return;
559 :
560 : try
561 : {
562 : // also handle all children of this element
563 0 : Reference< XInterface > xInterface;
564 0 : sal_Int32 nCount = _rxContainer->getCount();
565 0 : for(sal_Int32 i = 0;i != nCount;++i)
566 : {
567 0 : xInterface.set(_rxContainer->getByIndex( i ),uno::UNO_QUERY);
568 0 : if ( _bStartListening )
569 0 : AddElement( xInterface );
570 : else
571 0 : RemoveElement( xInterface );
572 : }
573 :
574 : // be notified of any changes in the container elements
575 0 : Reference< XContainer > xSimpleContainer( _rxContainer, UNO_QUERY );
576 0 : if ( xSimpleContainer.is() )
577 : {
578 0 : if ( _bStartListening )
579 0 : xSimpleContainer->addContainerListener( this );
580 : else
581 0 : xSimpleContainer->removeContainerListener( this );
582 0 : }
583 : }
584 0 : catch( const Exception& )
585 : {
586 : DBG_UNHANDLED_EXCEPTION();
587 : }
588 : }
589 :
590 : //------------------------------------------------------------------------------
591 0 : void OXUndoEnvironment::switchListening( const Reference< XInterface >& _rxObject, bool _bStartListening ) SAL_THROW(())
592 : {
593 : OSL_PRECOND( _rxObject.is(), "OXUndoEnvironment::switchListening: how should I listen at a NULL object?" );
594 :
595 : try
596 : {
597 0 : if ( !m_pImpl->m_bReadOnly )
598 : {
599 0 : Reference< XPropertySet > xProps( _rxObject, UNO_QUERY );
600 0 : if ( xProps.is() )
601 : {
602 0 : if ( _bStartListening )
603 0 : xProps->addPropertyChangeListener( OUString(), this );
604 : else
605 0 : xProps->removePropertyChangeListener( OUString(), this );
606 0 : }
607 : }
608 :
609 0 : Reference< XModifyBroadcaster > xBroadcaster( _rxObject, UNO_QUERY );
610 0 : if ( xBroadcaster.is() )
611 : {
612 0 : if ( _bStartListening )
613 0 : xBroadcaster->addModifyListener( this );
614 : else
615 0 : xBroadcaster->removeModifyListener( this );
616 0 : }
617 : }
618 0 : catch( const Exception& )
619 : {
620 : }
621 0 : }
622 :
623 : //------------------------------------------------------------------------------
624 0 : void OXUndoEnvironment::AddElement(const Reference< XInterface >& _rxElement )
625 : {
626 0 : if ( !IsLocked() )
627 0 : m_pImpl->m_aFormatNormalizer.notifyElementInserted( _rxElement );
628 :
629 : // if it's a container, start listening at all elements
630 0 : Reference< XIndexAccess > xContainer( _rxElement, UNO_QUERY );
631 0 : if ( xContainer.is() )
632 0 : switchListening( xContainer, true );
633 :
634 0 : switchListening( _rxElement, true );
635 0 : }
636 :
637 : //------------------------------------------------------------------------------
638 0 : void OXUndoEnvironment::RemoveElement(const Reference< XInterface >& _rxElement)
639 : {
640 0 : uno::Reference<beans::XPropertySet> xProp(_rxElement,uno::UNO_QUERY);
641 0 : if (!m_pImpl->m_aPropertySetCache.empty())
642 0 : m_pImpl->m_aPropertySetCache.erase(xProp);
643 0 : switchListening( _rxElement, false );
644 :
645 0 : Reference< XIndexAccess > xContainer( _rxElement, UNO_QUERY );
646 0 : if ( xContainer.is() )
647 0 : switchListening( xContainer, false );
648 0 : }
649 :
650 0 : void OXUndoEnvironment::SetUndoMode(sal_Bool _bUndo)
651 : {
652 0 : m_pImpl->m_bIsUndo = _bUndo;
653 0 : }
654 :
655 0 : sal_Bool OXUndoEnvironment::IsUndoMode() const
656 : {
657 0 : return m_pImpl->m_bIsUndo;
658 : }
659 : //============================================================================
660 0 : } // rptui
661 : //============================================================================
662 :
663 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|