/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/ #include <UndoActions.hxx> #include <UndoEnv.hxx> #include"formatnormalizer.hxx" #include <conditionupdater.hxx> #include <RptPage.hxx> #include <strings.hrc> #include <RptModel.hxx>
void OXUndoEnvironment::Lock()
{
OSL_ENSURE(m_refCount,"Illegal call to dead object!");
osl_atomic_increment( &m_pImpl->m_nLocks );
} void OXUndoEnvironment::UnLock()
{
OSL_ENSURE(m_refCount,"Illegal call to dead object!");
void SAL_CALL OXUndoEnvironment::disposing(const EventObject& e)
{ // check if it's an object we have cached information about
Reference< XPropertySet > xSourceSet(e.Source, UNO_QUERY); if ( xSourceSet.is() )
{
uno::Reference< report::XSection> xSection(xSourceSet,uno::UNO_QUERY); if ( xSection.is() )
RemoveSection(xSection); else
RemoveElement(xSourceSet);
}
}
Reference< XPropertySet > xSet( _rEvent.Source, UNO_QUERY ); if (!xSet.is()) return;
dbaui::DBSubComponentController* pController = m_pImpl->m_rModel.getController(); if ( !pController ) return;
// no Undo for transient and readonly props. // let's see if we know something about the set
PropertySetInfoCache::iterator objectPos = m_pImpl->m_aPropertySetCache.find(xSet); if (objectPos == m_pImpl->m_aPropertySetCache.end())
{
objectPos = m_pImpl->m_aPropertySetCache.emplace( xSet, ObjectInfo() ).first;
DBG_ASSERT(objectPos != m_pImpl->m_aPropertySetCache.end(), "OXUndoEnvironment::propertyChange : just inserted it... why it's not there?");
} if ( objectPos == m_pImpl->m_aPropertySetCache.end() ) return;
// now we have access to the cached info about the set // let's see what we know about the property
ObjectInfo& rObjectInfo = objectPos->second;
PropertiesInfo::const_iterator aPropertyPos = rObjectInfo.aProperties.find( _rEvent.PropertyName ); if ( aPropertyPos == rObjectInfo.aProperties.end() )
{ // nothing 'til now... have to change this... // the attributes
Reference< XPropertySetInfo > xPSI( xSet->getPropertySetInfo(), UNO_SET_THROW );
sal_Int32 nPropertyAttributes = 0; try
{ if ( xPSI->hasPropertyByName( _rEvent.PropertyName ) )
{
nPropertyAttributes = xPSI->getPropertyByName( _rEvent.PropertyName ).Attributes;
} else
{ // it's perfectly valid for a component to notify a change in a property which it doesn't have - as long // as it has an attribute with this name if ( !rObjectInfo.xPropertyIntrospection.is() )
{ if ( !m_pImpl->m_xIntrospection.is() )
{
m_pImpl->m_xIntrospection = theIntrospection::get( m_pImpl->m_rModel.getController()->getORB() );
}
Reference< XIntrospectionAccess > xIntrospection(
m_pImpl->m_xIntrospection->inspect( Any( _rEvent.Source ) ),
UNO_SET_THROW
);
rObjectInfo.xPropertyIntrospection.set( xIntrospection->queryAdapter( cppu::UnoType<XPropertySet>::get() ), UNO_QUERY_THROW );
} if ( rObjectInfo.xPropertyIntrospection.is() )
{
xPSI.set( rObjectInfo.xPropertyIntrospection->getPropertySetInfo(), UNO_SET_THROW );
nPropertyAttributes = xPSI->getPropertyByName( _rEvent.PropertyName ).Attributes;
}
}
} catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("reportdesign");
} constbool bTransReadOnly =
( ( nPropertyAttributes & PropertyAttribute::READONLY ) != 0 )
|| ( ( nPropertyAttributes & PropertyAttribute::TRANSIENT ) != 0 );
// insert the new entry
aPropertyPos = rObjectInfo.aProperties.emplace(
_rEvent.PropertyName,
PropertyInfo( bTransReadOnly )
).first;
DBG_ASSERT(aPropertyPos != rObjectInfo.aProperties.end(), "OXUndoEnvironment::propertyChange : just inserted it ... why it's not there ?");
}
implSetModified();
// now we have access to the cached info about the property affected // and are able to decide whether or not we need an undo action
// no UNDO for transient/readonly properties if ( aPropertyPos->second.bIsReadonlyOrTransient ) return;
// give components with sub responsibilities a chance
m_pImpl->m_aFormatNormalizer.notifyPropertyChange( _rEvent );
m_pImpl->m_aConditionUpdater.notifyPropertyChange( _rEvent );
aGuard.clear(); // TODO: this is a potential race condition: two threads here could in theory // add their undo actions out-of-order
try
{ // also handle all children of this element
Reference< XInterface > xInterface;
sal_Int32 nCount = _rxContainer->getCount(); for(sal_Int32 i = 0;i != nCount;++i)
{
xInterface.set(_rxContainer->getByIndex( i ),uno::UNO_QUERY); if ( _bStartListening )
AddElement( xInterface ); else
RemoveElement( xInterface );
}
// be notified of any changes in the container elements
Reference< XContainer > xSimpleContainer( _rxContainer, UNO_QUERY ); if ( xSimpleContainer.is() )
{ if ( _bStartListening )
xSimpleContainer->addContainerListener( this ); else
xSimpleContainer->removeContainerListener( this );
}
} catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("reportdesign");
}
}
void OXUndoEnvironment::switchListening( const Reference< XInterface >& _rxObject, bool _bStartListening )
{
OSL_PRECOND( _rxObject.is(), "OXUndoEnvironment::switchListening: how should I listen at a NULL object?" );
try
{ if ( !m_pImpl->m_bReadOnly )
{
Reference< XPropertySet > xProps( _rxObject, UNO_QUERY ); if ( xProps.is() )
{ if ( _bStartListening )
xProps->addPropertyChangeListener( OUString(), this ); else
xProps->removePropertyChangeListener( OUString(), this );
}
}
Reference< XModifyBroadcaster > xBroadcaster( _rxObject, UNO_QUERY ); if ( xBroadcaster.is() )
{ if ( _bStartListening )
xBroadcaster->addModifyListener( this ); else
xBroadcaster->removeModifyListener( this );
}
} catch( const Exception& )
{
}
}
// if it's a container, start listening at all elements
Reference< XIndexAccess > xContainer( _rxElement, UNO_QUERY ); if ( xContainer.is() )
switchListening( xContainer, true );
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.