blob: ce5af5adcbac9bf0f731fb6243d4e4a1afd51593 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_comphelper.hxx"
#include <comphelper/composedprops.hxx>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <cppuhelper/implbase1.hxx>
//.........................................................................
namespace comphelper
{
//.........................................................................
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::lang;
//=====================================================================
//= OComposedPropertySetInfo
//=====================================================================
class OComposedPropertySetInfo : public ::cppu::WeakImplHelper1< XPropertySetInfo >
{
private:
Sequence< Property> m_aProperties;
public:
OComposedPropertySetInfo(const Sequence< Property>& _rProperties);
virtual Sequence< Property > SAL_CALL getProperties( ) throw(RuntimeException);
virtual Property SAL_CALL getPropertyByName( const ::rtl::OUString& _rName ) throw(UnknownPropertyException, RuntimeException);
virtual sal_Bool SAL_CALL hasPropertyByName( const ::rtl::OUString& _rName ) throw(RuntimeException);
};
//=====================================================================
//= OComposedPropertySet
//=====================================================================
//---------------------------------------------------------------------
OComposedPropertySet::OComposedPropertySet(
const Sequence< Reference< XPropertySet> > & _rElements,
const IPropertySetComposerCallback* _pPropertyMetaData)
:m_pInfo(NULL)
{
// copy the sequence
sal_Int32 nSingleSets = _rElements.getLength();
if (nSingleSets)
{
m_aSingleSets.resize(nSingleSets);
const Reference< XPropertySet >* pSingleSets = _rElements.getConstArray();
::std::copy(pSingleSets, pSingleSets + nSingleSets, m_aSingleSets.begin());
}
// impl ctor
compose(_pPropertyMetaData);
}
//---------------------------------------------------------------------
OComposedPropertySet::~OComposedPropertySet()
{
if (m_pInfo)
m_pInfo->release();
}
//---------------------------------------------------------------------
void OComposedPropertySet::compose(const IPropertySetComposerCallback* _pMetaData)
{
sal_Int32 nSingleSets = m_aSingleSets.size();
if (nSingleSets>0)
{
// get the properties of the first set
Reference< XPropertySet > xMasterSet = m_aSingleSets[0];
Sequence< Property> aMasterProps;
if (xMasterSet.is())
aMasterProps = xMasterSet->getPropertySetInfo()->getProperties();
sal_Int32 nMasterPropsCount = aMasterProps.getLength();
const Property* pMasterProps = aMasterProps.getConstArray();
// check which of the master properties should be included
Sequence<sal_Bool> aInclusionFlags(nMasterPropsCount);
sal_Bool* pInclusionFlags = aInclusionFlags.getArray();
// the states of all these properties
Sequence< PropertyState > aPropertyStates(nMasterPropsCount);
for (sal_Int32 i=0; i<nMasterPropsCount; ++i)
pInclusionFlags[i] = sal_True;
Reference< XPropertySet > xSecondarySet;
sal_Int32 nSecondaryPropertyCount;
Sequence< Property > aSecondaryProperties;
const Property* pPrimaryProperty = aMasterProps.getConstArray();
for (sal_Int32 nPrimary=0; nPrimary<nMasterPropsCount; ++nPrimary, ++pPrimaryProperty)
{
if (_pMetaData && !_pMetaData->isComposeable(pPrimaryProperty->Name))
// do not include this property
pInclusionFlags[nPrimary] = sal_False;
else
{
// search the property in all secondary sets
for (sal_Int32 i=1; i<nSingleSets; ++i)
{
xSecondarySet = m_aSingleSets[i];
aSecondaryProperties = xSecondarySet->getPropertySetInfo()->getProperties();
nSecondaryPropertyCount = aSecondaryProperties.getLength();
const Property* pSecondaryProperties = aSecondaryProperties.getConstArray();
// search the current primary property in the secondary property sequence
sal_Int32 k=0;
while (k<nSecondaryPropertyCount && (pSecondaryProperties[k].Name != pPrimaryProperty->Name))
++k;
if (k >= nSecondaryPropertyCount)
// not found -> do not include
pInclusionFlags[nPrimary] = sal_False;
}
}
}
// count what's left ....
sal_Int32 nOverallProperties = 0;
for (sal_Int32 nCounter=0; nCounter<nMasterPropsCount; ++nCounter)
{
if (pInclusionFlags[nCounter])
++nOverallProperties;
}
// and finally construct our sequence
m_aProperties = Sequence< Property >(nOverallProperties);
Property* pProperties = m_aProperties.getArray();
const Property* pMasterProperties = pMasterProps;
sal_Int32 nOwnProperties = 0;
for (sal_Int32 nCopy = 0; nCopy < nMasterPropsCount; ++nCopy, ++pMasterProperties)
{
if (pInclusionFlags[nCopy])
pProperties[nOwnProperties++] = *pMasterProperties;
}
}
}
//------------------------------------------------------------------------------
Reference< XPropertySetInfo > SAL_CALL OComposedPropertySet::getPropertySetInfo( ) throw(RuntimeException)
{
::osl::MutexGuard aGuard(m_aMutex);
if (!m_pInfo)
{
m_pInfo = new OComposedPropertySetInfo(m_aProperties);
m_pInfo->acquire();
}
return m_pInfo;
}
//------------------------------------------------------------------------------
PropertyState SAL_CALL OComposedPropertySet::getPropertyState( const ::rtl::OUString& _rPropertyName ) throw(UnknownPropertyException, RuntimeException)
{
// assume DIRECT for the moment
PropertyState eState = PropertyState_DIRECT_VALUE;
sal_Int32 nSingleSets = m_aSingleSets.size();
if (nSingleSets>0)
{
// check the master state
Reference< XPropertySet > xMasterSet(m_aSingleSets[0]);
Any aPrimaryValue;
if (xMasterSet.is())
{
Reference< XPropertyState > xMasterState(xMasterSet,UNO_QUERY);
aPrimaryValue = xMasterSet->getPropertyValue(_rPropertyName);
if (xMasterState.is())
eState = xMasterState->getPropertyState(_rPropertyName);
}
// loop through the secondary sets
PropertyState eSecondaryState;
for (sal_Int32 i=1; i<nSingleSets; ++i)
{
Reference< XPropertySet > xSecondary(m_aSingleSets[i]);
Reference< XPropertyState > xSecondaryState(xSecondary, UNO_QUERY);
// the secondary state
eSecondaryState = PropertyState_DIRECT_VALUE;
if(xSecondaryState.is())
eSecondaryState = xSecondaryState->getPropertyState(_rPropertyName);
// the secondary value
Any aSecondaryValue(xSecondary->getPropertyValue(_rPropertyName));
if ( (PropertyState_AMBIGUOUS_VALUE == eSecondaryState) // secondary is ambiguous
|| !::comphelper::compare(aPrimaryValue, aSecondaryValue) // unequal values
)
{
eState = PropertyState_AMBIGUOUS_VALUE;
break;
}
}
}
else
{
throw UnknownPropertyException( _rPropertyName, *this );
}
return eState;
}
//---------------------------------------------------------------------
Sequence< PropertyState > SAL_CALL OComposedPropertySet::getPropertyStates( const Sequence< ::rtl::OUString >& _rPropertyName ) throw(UnknownPropertyException, RuntimeException)
{
sal_Int32 nCount = _rPropertyName.getLength();
Sequence< PropertyState > aReturn(nCount);
const ::rtl::OUString* pNames = _rPropertyName.getConstArray();
PropertyState* pStates = aReturn.getArray();
for (sal_Int32 i=0; i<nCount; ++i, ++pNames, ++pStates)
*pStates = getPropertyState(*pNames);
return aReturn;
}
//---------------------------------------------------------------------
void SAL_CALL OComposedPropertySet::setPropertyToDefault( const ::rtl::OUString& _rPropertyName ) throw(UnknownPropertyException, RuntimeException)
{
sal_Int32 nSingleSets = m_aSingleSets.size();
for (sal_Int32 i=0; i<nSingleSets; ++i)
{
Reference< XPropertyState > xState(m_aSingleSets[i], UNO_QUERY);
if(xState.is())
xState->setPropertyToDefault(_rPropertyName);
}
}
//---------------------------------------------------------------------
Any SAL_CALL OComposedPropertySet::getPropertyDefault( const ::rtl::OUString& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
{
return Any();
}
//------------------------------------------------------------------------------
void SAL_CALL OComposedPropertySet::setPropertyValue( const ::rtl::OUString& _rPropertyName, const Any& _rValue ) throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
{
sal_Int32 nSingleSets = m_aSingleSets.size();
for (sal_Int32 i=0; i<nSingleSets; ++i)
{
if (m_aSingleSets[i].is())
m_aSingleSets[i]->setPropertyValue(_rPropertyName, _rValue);
}
}
//------------------------------------------------------------------------------
Any SAL_CALL OComposedPropertySet::getPropertyValue( const ::rtl::OUString& _rPropertyName ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
{
sal_Int32 nSingleSets = m_aSingleSets.size();
if ((nSingleSets>0) && (m_aSingleSets[0].is()))
return m_aSingleSets[0]->getPropertyValue(_rPropertyName);
return Any();
}
//------------------------------------------------------------------------------
void SAL_CALL OComposedPropertySet::addPropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
{
// TODO:
// hold the single property sets weak
// be a property change listener on all single property sets (for all composed properties)
// upon property change
// determine the new state/value of the composed property
// broadcast the new composed property value
}
//------------------------------------------------------------------------------
void SAL_CALL OComposedPropertySet::removePropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
{
// TODO
}
//------------------------------------------------------------------------------
void SAL_CALL OComposedPropertySet::addVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
{
OSL_ENSURE(sal_False, "OComposedPropertySet::addVetoableChangeListener: no implemented (yet)!");
}
//------------------------------------------------------------------------------
void SAL_CALL OComposedPropertySet::removeVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
{
OSL_ENSURE(sal_False, "OComposedPropertySet::removeVetoableChangeListener: no implemented (yet)!");
}
//------------------------------------------------------------------------------
OComposedPropertySetInfo::OComposedPropertySetInfo(const Sequence< Property>& rSeq)
:m_aProperties(rSeq)
{
}
//------------------------------------------------------------------------------
Sequence< Property> SAL_CALL OComposedPropertySetInfo::getProperties() throw(RuntimeException)
{
return m_aProperties;
}
//------------------------------------------------------------------------------
Property SAL_CALL OComposedPropertySetInfo::getPropertyByName( const ::rtl::OUString& _rName ) throw(UnknownPropertyException, RuntimeException)
{
sal_Int32 nLength = m_aProperties.getLength();
const Property* pProps = m_aProperties.getConstArray();
// TODO TODO TODO: this O(n) search really sucks ...
for (sal_Int32 i=0; i<nLength; ++i, ++pProps)
{
if (pProps->Name == _rName)
return *pProps;
}
throw UnknownPropertyException( _rName, *this );
}
//------------------------------------------------------------------------------
sal_Bool SAL_CALL OComposedPropertySetInfo::hasPropertyByName( const ::rtl::OUString& _rName ) throw(RuntimeException)
{
sal_Int32 nLength = m_aProperties.getLength();
const Property* pProps = m_aProperties.getConstArray();
// TODO TODO TODO: this O(n) search really sucks ...
for( sal_Int32 i=0; i<nLength; ++i,++pProps )
{
if(pProps->Name == _rName)
return sal_True;
}
return sal_False;
}
//.........................................................................
} // namespace comphelper
//.........................................................................