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