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