xref: /AOO41X/main/comphelper/source/property/composedprops.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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     //---------------------------------------------------------------------
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     //---------------------------------------------------------------------
79     OComposedPropertySet::~OComposedPropertySet()
80     {
81         if (m_pInfo)
82             m_pInfo->release();
83     }
84 
85     //---------------------------------------------------------------------
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     //------------------------------------------------------------------------------
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     //------------------------------------------------------------------------------
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     //---------------------------------------------------------------------
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     //---------------------------------------------------------------------
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     //---------------------------------------------------------------------
252     Any SAL_CALL OComposedPropertySet::getPropertyDefault( const ::rtl::OUString& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
253     {
254         return Any();
255     }
256 
257     //------------------------------------------------------------------------------
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     //------------------------------------------------------------------------------
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     //------------------------------------------------------------------------------
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     //------------------------------------------------------------------------------
290     void SAL_CALL OComposedPropertySet::removePropertyChangeListener( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
291     {
292         // TODO
293     }
294 
295     //------------------------------------------------------------------------------
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     //------------------------------------------------------------------------------
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     //------------------------------------------------------------------------------
308     OComposedPropertySetInfo::OComposedPropertySetInfo(const Sequence< Property>& rSeq)
309         :m_aProperties(rSeq)
310     {
311     }
312 
313     //------------------------------------------------------------------------------
314     Sequence< Property> SAL_CALL OComposedPropertySetInfo::getProperties() throw(RuntimeException)
315     {
316         return m_aProperties;
317     }
318 
319     //------------------------------------------------------------------------------
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     //------------------------------------------------------------------------------
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