1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_comphelper.hxx"
26 #include <comphelper/composedprops.hxx>
27 #include <com/sun/star/container/XChild.hpp>
28 #include <com/sun/star/beans/XPropertySetInfo.hpp>
29 #include <cppuhelper/implbase1.hxx>
30 
31 //.........................................................................
32 namespace comphelper
33 {
34 //.........................................................................
35 
36 	using namespace ::com::sun::star::uno;
37 	using namespace ::com::sun::star::beans;
38 	using namespace ::com::sun::star::lang;
39 
40 	//=====================================================================
41 	//= OComposedPropertySetInfo
42 	//=====================================================================
43 	class OComposedPropertySetInfo : public ::cppu::WeakImplHelper1< XPropertySetInfo >
44 	{
45 	private:
46 		Sequence< Property>		m_aProperties;
47 
48 	public:
49 		OComposedPropertySetInfo(const Sequence< Property>& _rProperties);
50 
51 		virtual Sequence< Property > SAL_CALL getProperties(  ) throw(RuntimeException);
52 		virtual Property SAL_CALL getPropertyByName( const ::rtl::OUString& _rName ) throw(UnknownPropertyException, RuntimeException);
53 		virtual sal_Bool SAL_CALL hasPropertyByName( const ::rtl::OUString& _rName ) throw(RuntimeException);
54 	};
55 
56 	//=====================================================================
57 	//= OComposedPropertySet
58 	//=====================================================================
59 	//---------------------------------------------------------------------
OComposedPropertySet(const Sequence<Reference<XPropertySet>> & _rElements,const IPropertySetComposerCallback * _pPropertyMetaData)60 	OComposedPropertySet::OComposedPropertySet(
61 			const Sequence< Reference< XPropertySet> > & _rElements,
62 			const IPropertySetComposerCallback* _pPropertyMetaData)
63 		:m_pInfo(NULL)
64 	{
65 		// copy the sequence
66 		sal_Int32 nSingleSets = _rElements.getLength();
67 		if (nSingleSets)
68 		{
69 			m_aSingleSets.resize(nSingleSets);
70 			const Reference< XPropertySet >* pSingleSets = _rElements.getConstArray();
71 			::std::copy(pSingleSets, pSingleSets + nSingleSets, m_aSingleSets.begin());
72 		}
73 
74 		// impl ctor
75 		compose(_pPropertyMetaData);
76 	}
77 
78 	//---------------------------------------------------------------------
~OComposedPropertySet()79 	OComposedPropertySet::~OComposedPropertySet()
80 	{
81 		if (m_pInfo)
82 			m_pInfo->release();
83 	}
84 
85 	//---------------------------------------------------------------------
compose(const IPropertySetComposerCallback * _pMetaData)86 	void OComposedPropertySet::compose(const IPropertySetComposerCallback* _pMetaData)
87 	{
88 		sal_Int32 nSingleSets = m_aSingleSets.size();
89 
90 		if (nSingleSets>0)
91 		{
92 			// get the properties of the first set
93 			Reference< XPropertySet > xMasterSet = m_aSingleSets[0];
94 			Sequence< Property> aMasterProps;
95 			if (xMasterSet.is())
96 				aMasterProps = xMasterSet->getPropertySetInfo()->getProperties();
97 			sal_Int32 nMasterPropsCount = aMasterProps.getLength();
98 			const Property*	pMasterProps = aMasterProps.getConstArray();
99 
100 			// check which of the master properties should be included
101 			Sequence<sal_Bool> aInclusionFlags(nMasterPropsCount);
102 			sal_Bool* pInclusionFlags = aInclusionFlags.getArray();
103 
104 			// the states of all these properties
105 			Sequence< PropertyState > aPropertyStates(nMasterPropsCount);
106 
107 			for (sal_Int32 i=0; i<nMasterPropsCount; ++i)
108 				pInclusionFlags[i] = sal_True;
109 
110 			Reference< XPropertySet >  xSecondarySet;
111 			sal_Int32 nSecondaryPropertyCount;
112 			Sequence< Property > aSecondaryProperties;
113 			const Property* pPrimaryProperty = aMasterProps.getConstArray();
114 			for (sal_Int32 nPrimary=0; nPrimary<nMasterPropsCount; ++nPrimary, ++pPrimaryProperty)
115 			{
116 				if (_pMetaData && !_pMetaData->isComposeable(pPrimaryProperty->Name))
117 					// do not include this property
118 					pInclusionFlags[nPrimary] = sal_False;
119 				else
120 				{
121 					// search the property in all secondary sets
122 					for (sal_Int32 i=1; i<nSingleSets; ++i)
123 					{
124 						xSecondarySet = m_aSingleSets[i];
125 						aSecondaryProperties = xSecondarySet->getPropertySetInfo()->getProperties();
126 						nSecondaryPropertyCount = aSecondaryProperties.getLength();
127 						const Property*	pSecondaryProperties = aSecondaryProperties.getConstArray();
128 
129 						// search the current primary property in the secondary property sequence
130 						sal_Int32 k=0;
131 						while (k<nSecondaryPropertyCount && (pSecondaryProperties[k].Name != pPrimaryProperty->Name))
132 							++k;
133 
134 						if (k >= nSecondaryPropertyCount)
135 							// not found -> do not include
136 							pInclusionFlags[nPrimary] = sal_False;
137 					}
138 				}
139 			}
140 
141 			// count what's left ....
142 			sal_Int32 nOverallProperties = 0;
143 			for (sal_Int32 nCounter=0; nCounter<nMasterPropsCount; ++nCounter)
144 			{
145 				if (pInclusionFlags[nCounter])
146 					++nOverallProperties;
147 			}
148 
149 			// and finally construct our sequence
150 			m_aProperties = Sequence< Property >(nOverallProperties);
151 			Property* pProperties = m_aProperties.getArray();
152 			const Property* pMasterProperties = pMasterProps;
153 			sal_Int32 nOwnProperties = 0;
154 			for (sal_Int32 nCopy = 0; nCopy < nMasterPropsCount; ++nCopy, ++pMasterProperties)
155 			{
156 				if (pInclusionFlags[nCopy])
157 					pProperties[nOwnProperties++] = *pMasterProperties;
158 			}
159 		}
160 	}
161 
162 	//------------------------------------------------------------------------------
getPropertySetInfo()163 	Reference< XPropertySetInfo > SAL_CALL OComposedPropertySet::getPropertySetInfo(  ) throw(RuntimeException)
164 	{
165 		::osl::MutexGuard aGuard(m_aMutex);
166 		if (!m_pInfo)
167 		{
168 			m_pInfo = new OComposedPropertySetInfo(m_aProperties);
169 			m_pInfo->acquire();
170 		}
171 		return m_pInfo;
172 	}
173 
174 	//------------------------------------------------------------------------------
getPropertyState(const::rtl::OUString & _rPropertyName)175 	PropertyState SAL_CALL OComposedPropertySet::getPropertyState( const ::rtl::OUString& _rPropertyName ) throw(UnknownPropertyException, RuntimeException)
176 	{
177 		// assume DIRECT for the moment
178 		PropertyState eState = PropertyState_DIRECT_VALUE;
179 
180 		sal_Int32 nSingleSets = m_aSingleSets.size();
181 		if (nSingleSets>0)
182 		{
183 			// check the master state
184 			Reference< XPropertySet >  xMasterSet(m_aSingleSets[0]);
185 			Any aPrimaryValue;
186 			if (xMasterSet.is())
187 			{
188 				Reference< XPropertyState >  xMasterState(xMasterSet,UNO_QUERY);
189 				aPrimaryValue = xMasterSet->getPropertyValue(_rPropertyName);
190 
191 				if (xMasterState.is())
192 					eState = xMasterState->getPropertyState(_rPropertyName);
193 			}
194 
195 			// loop through the secondary sets
196 			PropertyState eSecondaryState;
197 			for (sal_Int32 i=1; i<nSingleSets; ++i)
198 			{
199 				Reference< XPropertySet >	xSecondary(m_aSingleSets[i]);
200 				Reference< XPropertyState >	xSecondaryState(xSecondary, UNO_QUERY);
201 
202 				// the secondary state
203 				eSecondaryState = PropertyState_DIRECT_VALUE;
204 				if(xSecondaryState.is())
205 					eSecondaryState = xSecondaryState->getPropertyState(_rPropertyName);
206 
207 				// the secondary value
208 				Any aSecondaryValue(xSecondary->getPropertyValue(_rPropertyName));
209 
210 				if	(	(PropertyState_AMBIGUOUS_VALUE == eSecondaryState)		// secondary is ambiguous
211 					||	!::comphelper::compare(aPrimaryValue, aSecondaryValue)	// unequal values
212 					)
213 				{
214 					eState = PropertyState_AMBIGUOUS_VALUE;
215 					break;
216 				}
217 			}
218 		}
219 		else
220 		{
221 			throw UnknownPropertyException(  _rPropertyName, *this  );
222 		}
223 
224 		return eState;
225 	}
226 
227 	//---------------------------------------------------------------------
getPropertyStates(const Sequence<::rtl::OUString> & _rPropertyName)228 	Sequence< PropertyState > SAL_CALL OComposedPropertySet::getPropertyStates( const Sequence< ::rtl::OUString >& _rPropertyName ) throw(UnknownPropertyException, RuntimeException)
229 	{
230 		sal_Int32 nCount = _rPropertyName.getLength();
231 		Sequence< PropertyState > aReturn(nCount);
232 		const ::rtl::OUString* pNames = _rPropertyName.getConstArray();
233 		PropertyState* pStates = aReturn.getArray();
234 		for (sal_Int32 i=0; i<nCount; ++i, ++pNames, ++pStates)
235 			*pStates = getPropertyState(*pNames);
236 		return aReturn;
237 	}
238 
239 	//---------------------------------------------------------------------
setPropertyToDefault(const::rtl::OUString & _rPropertyName)240 	void SAL_CALL OComposedPropertySet::setPropertyToDefault( const ::rtl::OUString& _rPropertyName ) throw(UnknownPropertyException, RuntimeException)
241 	{
242 		sal_Int32 nSingleSets = m_aSingleSets.size();
243 		for (sal_Int32 i=0; i<nSingleSets; ++i)
244 		{
245 			Reference< XPropertyState >	xState(m_aSingleSets[i], UNO_QUERY);
246 			if(xState.is())
247 				xState->setPropertyToDefault(_rPropertyName);
248 		}
249 	}
250 
251 	//---------------------------------------------------------------------
getPropertyDefault(const::rtl::OUString &)252 	Any SAL_CALL OComposedPropertySet::getPropertyDefault( const ::rtl::OUString& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
253 	{
254 		return Any();
255 	}
256 
257 	//------------------------------------------------------------------------------
setPropertyValue(const::rtl::OUString & _rPropertyName,const Any & _rValue)258 	void SAL_CALL OComposedPropertySet::setPropertyValue( const ::rtl::OUString& _rPropertyName, const Any& _rValue ) throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
259 	{
260 		sal_Int32 nSingleSets = m_aSingleSets.size();
261 		for (sal_Int32 i=0; i<nSingleSets; ++i)
262 		{
263 			if (m_aSingleSets[i].is())
264 				m_aSingleSets[i]->setPropertyValue(_rPropertyName, _rValue);
265 		}
266 	}
267 
268 	//------------------------------------------------------------------------------
getPropertyValue(const::rtl::OUString & _rPropertyName)269 	Any SAL_CALL OComposedPropertySet::getPropertyValue( const ::rtl::OUString& _rPropertyName ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
270 	{
271 		sal_Int32 nSingleSets = m_aSingleSets.size();
272 
273 		if ((nSingleSets>0) && (m_aSingleSets[0].is()))
274 			return m_aSingleSets[0]->getPropertyValue(_rPropertyName);
275 		return Any();
276 	}
277 
278 	//------------------------------------------------------------------------------
addPropertyChangeListener(const::rtl::OUString &,const Reference<XPropertyChangeListener> &)279 	void SAL_CALL OComposedPropertySet::addPropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
280 	{
281 		// TODO:
282 		// hold the single property sets weak
283 		// be a property change listener on all single property sets (for all composed properties)
284 		// upon property change
285 		//   determine the new state/value of the composed property
286 		//   broadcast the new composed property value
287 	}
288 
289 	//------------------------------------------------------------------------------
removePropertyChangeListener(const::rtl::OUString &,const Reference<XPropertyChangeListener> &)290 	void SAL_CALL OComposedPropertySet::removePropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
291 	{
292 		// TODO
293 	}
294 
295 	//------------------------------------------------------------------------------
addVetoableChangeListener(const::rtl::OUString &,const Reference<XVetoableChangeListener> &)296 	void SAL_CALL OComposedPropertySet::addVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
297 	{
298 		OSL_ENSURE(sal_False, "OComposedPropertySet::addVetoableChangeListener: no implemented (yet)!");
299 	}
300 
301 	//------------------------------------------------------------------------------
removeVetoableChangeListener(const::rtl::OUString &,const Reference<XVetoableChangeListener> &)302 	void SAL_CALL OComposedPropertySet::removeVetoableChangeListener( const ::rtl::OUString&, const Reference< XVetoableChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
303 	{
304 		OSL_ENSURE(sal_False, "OComposedPropertySet::removeVetoableChangeListener: no implemented (yet)!");
305 	}
306 
307 	//------------------------------------------------------------------------------
OComposedPropertySetInfo(const Sequence<Property> & rSeq)308 	OComposedPropertySetInfo::OComposedPropertySetInfo(const Sequence< Property>& rSeq)
309 		:m_aProperties(rSeq)
310 	{
311 	}
312 
313 	//------------------------------------------------------------------------------
getProperties()314 	Sequence< Property> SAL_CALL OComposedPropertySetInfo::getProperties() throw(RuntimeException)
315 	{
316 		return m_aProperties;
317 	}
318 
319 	//------------------------------------------------------------------------------
getPropertyByName(const::rtl::OUString & _rName)320 	Property SAL_CALL OComposedPropertySetInfo::getPropertyByName( const ::rtl::OUString& _rName ) throw(UnknownPropertyException, RuntimeException)
321 	{
322 		sal_Int32 nLength = m_aProperties.getLength();
323 		const Property*	pProps = m_aProperties.getConstArray();
324 		// TODO TODO TODO: this O(n) search really sucks ...
325 		for (sal_Int32 i=0; i<nLength; ++i, ++pProps)
326 		{
327 			if (pProps->Name == _rName)
328 				return *pProps;
329 		}
330 
331 		throw UnknownPropertyException( _rName, *this  );
332 	}
333 
334 	//------------------------------------------------------------------------------
hasPropertyByName(const::rtl::OUString & _rName)335 	sal_Bool SAL_CALL OComposedPropertySetInfo::hasPropertyByName( const ::rtl::OUString& _rName ) throw(RuntimeException)
336 	{
337 		sal_Int32 nLength = m_aProperties.getLength();
338 		const Property*	pProps = m_aProperties.getConstArray();
339 		// TODO TODO TODO: this O(n) search really sucks ...
340 		for( sal_Int32 i=0; i<nLength; ++i,++pProps )
341 		{
342 			if(pProps->Name == _rName)
343 				return sal_True;
344 		}
345 
346 		return sal_False;
347 	}
348 
349 //.........................................................................
350 }	// namespace comphelper
351 //.........................................................................
352 
353 
354