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 #ifndef OOVBAAPI_VBA_COLLECTION_IMPL_HXX
25 #define OOVBAAPI_VBA_COLLECTION_IMPL_HXX
26 
27 #include <ooo/vba/XCollection.hpp>
28 #include <com/sun/star/container/XEnumerationAccess.hpp>
29 #include <com/sun/star/uno/XComponentContext.hpp>
30 #include <com/sun/star/script/XDefaultMethod.hpp>
31 #include <com/sun/star/container/XIndexAccess.hpp>
32 #include <com/sun/star/container/XNameAccess.hpp>
33 #include <com/sun/star/container/XNamed.hpp>
34 
35 #include <cppuhelper/implbase3.hxx>
36 #include <cppuhelper/implbase2.hxx>
37 #include <cppuhelper/implbase1.hxx>
38 
39 #include "vbahelper/vbahelper.hxx"
40 #include "vbahelper/vbahelperinterface.hxx"
41 
42 #include <vector>
43 
44 // ============================================================================
45 
46 typedef ::cppu::WeakImplHelper1< css::container::XEnumeration > EnumerationHelper_BASE;
47 
48 // ============================================================================
49 
50 /** A wrapper that holds a com.sun.star.container.XIndexAccess and provides a
51     com.sun.star.container.XEnumeration.
52 
53     Can be used to provide an enumeration from an index container that contains
54     completely constructed/initialized VBA implementation objects. CANNOT be
55     used to provide an enumeration from an index container with other objects
56     (e.g. UNO objects) where construction of the VBA objects is needed first.
57  */
58 class VBAHELPER_DLLPUBLIC SimpleIndexAccessToEnumeration : public EnumerationHelper_BASE
59 {
60 public:
SimpleIndexAccessToEnumeration(const css::uno::Reference<css::container::XIndexAccess> & rxIndexAccess)61     explicit SimpleIndexAccessToEnumeration(
62             const css::uno::Reference< css::container::XIndexAccess >& rxIndexAccess ) throw (css::uno::RuntimeException) :
63         mxIndexAccess( rxIndexAccess ), mnIndex( 0 ) {}
64 
hasMoreElements()65     virtual sal_Bool SAL_CALL hasMoreElements() throw (css::uno::RuntimeException)
66     {
67         return mnIndex < mxIndexAccess->getCount();
68     }
69 
nextElement()70     virtual css::uno::Any SAL_CALL nextElement() throw (css::container::NoSuchElementException, css::lang::WrappedTargetException, css::uno::RuntimeException)
71     {
72         if( !hasMoreElements() )
73             throw css::container::NoSuchElementException();
74         return mxIndexAccess->getByIndex( mnIndex++ );
75     }
76 
77 private:
78     css::uno::Reference< css::container::XIndexAccess > mxIndexAccess;
79     sal_Int32 mnIndex;
80 };
81 
82 // ============================================================================
83 
84 /** A wrapper that holds a com.sun.star.container.XEnumeration or a
85     com.sun.star.container.XIndexAccess and provides an enumeration of VBA objects.
86 
87     The method createCollectionObject() needs to be implemented by the derived
88     class. This class can be used to convert an enumeration or an index container
89     containing UNO objects to an enumeration providing the related VBA objects.
90  */
91 class VBAHELPER_DLLPUBLIC SimpleEnumerationBase : public EnumerationHelper_BASE
92 {
93 public:
SimpleEnumerationBase(const css::uno::Reference<ov::XHelperInterface> & rxParent,const css::uno::Reference<css::uno::XComponentContext> & rxContext,const css::uno::Reference<css::container::XEnumeration> & rxEnumeration)94     explicit SimpleEnumerationBase(
95             const css::uno::Reference< ov::XHelperInterface >& rxParent,
96             const css::uno::Reference< css::uno::XComponentContext >& rxContext,
97             const css::uno::Reference< css::container::XEnumeration >& rxEnumeration ) throw (css::uno::RuntimeException) :
98         mxParent( rxParent ), mxContext( rxContext ), mxEnumeration( rxEnumeration ) {}
99 
SimpleEnumerationBase(const css::uno::Reference<ov::XHelperInterface> & rxParent,const css::uno::Reference<css::uno::XComponentContext> & rxContext,const css::uno::Reference<css::container::XIndexAccess> & rxIndexAccess)100     explicit SimpleEnumerationBase(
101             const css::uno::Reference< ov::XHelperInterface >& rxParent,
102             const css::uno::Reference< css::uno::XComponentContext >& rxContext,
103             const css::uno::Reference< css::container::XIndexAccess >& rxIndexAccess ) throw (css::uno::RuntimeException) :
104         mxParent( rxParent ), mxContext( rxContext ), mxEnumeration( new SimpleIndexAccessToEnumeration( rxIndexAccess ) ) {}
105 
hasMoreElements()106     virtual sal_Bool SAL_CALL hasMoreElements() throw (css::uno::RuntimeException)
107     {
108         return mxEnumeration->hasMoreElements();
109     }
110 
nextElement()111     virtual css::uno::Any SAL_CALL nextElement() throw (css::container::NoSuchElementException, css::lang::WrappedTargetException, css::uno::RuntimeException)
112     {
113         return createCollectionObject( mxEnumeration->nextElement() );
114     }
115 
116     /** Derived classes implement creation of a VBA implementation object from
117         the passed container element. */
118     virtual css::uno::Any createCollectionObject( const css::uno::Any& rSource ) = 0;
119 
120 protected:
121     css::uno::Reference< ov::XHelperInterface > mxParent;
122     css::uno::Reference< css::uno::XComponentContext > mxContext;
123     css::uno::Reference< css::container::XEnumeration > mxEnumeration;
124 };
125 
126 // ============================================================================
127 
128 // deprecated, use SimpleEnumerationBase instead!
129 class VBAHELPER_DLLPUBLIC EnumerationHelperImpl : public EnumerationHelper_BASE
130 {
131 protected:
132 	css::uno::WeakReference< ov::XHelperInterface > m_xParent;
133 	css::uno::Reference< css::uno::XComponentContext > m_xContext;
134 	css::uno::Reference< css::container::XEnumeration > m_xEnumeration;
135 public:
136 
EnumerationHelperImpl(const css::uno::Reference<ov::XHelperInterface> & xParent,const css::uno::Reference<css::uno::XComponentContext> & xContext,const css::uno::Reference<css::container::XEnumeration> & xEnumeration)137 	EnumerationHelperImpl( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::container::XEnumeration >& xEnumeration ) throw ( css::uno::RuntimeException ) : m_xParent( xParent ), m_xContext( xContext ),  m_xEnumeration( xEnumeration ) { }
hasMoreElements()138 	virtual ::sal_Bool SAL_CALL hasMoreElements(  ) throw (css::uno::RuntimeException) { return m_xEnumeration->hasMoreElements(); }
139 };
140 
141 // a wrapper class for a providing a XIndexAccess, XNameAccess, XEnumerationAccess impl based on providing a vector of interfaces
142 // only requirement is the object needs to implement XName
143 
144 
145 
146 typedef ::cppu::WeakImplHelper3< css::container::XNameAccess, css::container::XIndexAccess, css::container::XEnumerationAccess > XNamedCollectionHelper_BASE;
147 
148 template< typename Ifc1 >
149 class XNamedObjectCollectionHelper : public XNamedCollectionHelper_BASE
150 {
151 public:
152 typedef std::vector< css::uno::Reference< Ifc1 > >  XNamedVec;
153 private:
154 
155 	class XNamedEnumerationHelper : public EnumerationHelper_BASE
156 	{
157 		XNamedVec mXNamedVec;
158 		typename XNamedVec::iterator mIt;
159 	public:
XNamedEnumerationHelper(const XNamedVec & sMap)160 	        XNamedEnumerationHelper( const XNamedVec& sMap ) : mXNamedVec( sMap ), mIt( mXNamedVec.begin() ) {}
161 
hasMoreElements()162 	        virtual ::sal_Bool SAL_CALL hasMoreElements(  ) throw (css::uno::RuntimeException)
163 	        {
164 			return ( mIt != mXNamedVec.end() );
165 	        }
166 
nextElement()167 	        virtual css::uno::Any SAL_CALL nextElement(  ) throw (css::container::NoSuchElementException, css::lang::WrappedTargetException, css::uno::RuntimeException)
168 	        {
169 	                if ( hasMoreElements() )
170 				return css::uno::makeAny( *mIt++ );
171 	                throw css::container::NoSuchElementException();
172 	        }
173 	};
174 
175 protected:
176 	XNamedVec mXNamedVec;
177 	typename XNamedVec::iterator cachePos;
178 public:
XNamedObjectCollectionHelper(const XNamedVec & sMap)179 	XNamedObjectCollectionHelper( const XNamedVec& sMap ) : mXNamedVec( sMap ), cachePos(mXNamedVec.begin()) {}
180 	// XElementAccess
getElementType()181 	virtual css::uno::Type SAL_CALL getElementType(  ) throw (css::uno::RuntimeException) { return  Ifc1::static_type(0); }
hasElements()182 	virtual ::sal_Bool SAL_CALL hasElements(  ) throw (css::uno::RuntimeException) { return ( mXNamedVec.size() > 0 ); }
183 	// XNameAcess
getByName(const::rtl::OUString & aName)184 	virtual css::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) throw (css::container::NoSuchElementException, css::lang::WrappedTargetException, css::uno::RuntimeException)
185 	{
186 		if ( !hasByName(aName) )
187 			throw css::container::NoSuchElementException();
188 		return css::uno::makeAny( *cachePos );
189 	}
getElementNames()190 	virtual css::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames(  ) throw (css::uno::RuntimeException)
191 	{
192 		css::uno::Sequence< rtl::OUString > sNames( mXNamedVec.size() );
193 		rtl::OUString* pString = sNames.getArray();
194 		typename XNamedVec::iterator it = mXNamedVec.begin();
195 		typename XNamedVec::iterator it_end = mXNamedVec.end();
196 
197 		for ( ; it != it_end; ++it, ++pString )
198 		{
199 			css::uno::Reference< css::container::XNamed > xName( *it, css::uno::UNO_QUERY_THROW );
200 			*pString = xName->getName();
201 		}
202 		return sNames;
203 	}
hasByName(const::rtl::OUString & aName)204 	virtual ::sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw (css::uno::RuntimeException)
205 	{
206 		cachePos = mXNamedVec.begin();
207 		typename XNamedVec::iterator it_end = mXNamedVec.end();
208 		for ( ; cachePos != it_end; ++cachePos )
209 		{
210 			css::uno::Reference< css::container::XNamed > xName( *cachePos, css::uno::UNO_QUERY_THROW );
211 			if ( aName.equals( xName->getName() ) )
212 				break;
213 		}
214 		return ( cachePos != it_end );
215 	}
216 
217 	// XElementAccess
getCount()218 	virtual ::sal_Int32 SAL_CALL getCount(  ) throw (css::uno::RuntimeException) { return mXNamedVec.size(); }
getByIndex(::sal_Int32 Index)219 	virtual css::uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) throw (css::lang::IndexOutOfBoundsException, css::lang::WrappedTargetException, css::uno::RuntimeException )
220 	{
221 		if ( Index < 0 || Index >= getCount() )
222 			throw css::lang::IndexOutOfBoundsException();
223 
224 		return css::uno::makeAny( mXNamedVec[ Index ] );
225 
226 	}
227 	// XEnumerationAccess
createEnumeration()228 	virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration(  ) throw (css::uno::RuntimeException)
229 	{
230 		return new XNamedEnumerationHelper( mXNamedVec );
231 	}
232 };
233 
234 // including a HelperInterface implementation
235 template< typename Ifc1 >
236 class ScVbaCollectionBase : public InheritedHelperInterfaceImpl< Ifc1 >
237 {
238 typedef InheritedHelperInterfaceImpl< Ifc1 > BaseColBase;
239 protected:
240 	css::uno::Reference< css::container::XIndexAccess > m_xIndexAccess;
241 	css::uno::Reference< css::container::XNameAccess > m_xNameAccess;
242 
getItemByStringIndex(const rtl::OUString & sIndex)243 	virtual css::uno::Any getItemByStringIndex( const rtl::OUString& sIndex ) throw (css::uno::RuntimeException)
244 	{
245 		if ( !m_xNameAccess.is() )
246 			throw css::uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScVbaCollectionBase string index access not supported by this object") ), css::uno::Reference< css::uno::XInterface >() );
247 
248 		return createCollectionObject( m_xNameAccess->getByName( sIndex ) );
249 	}
250 
getItemByIntIndex(const sal_Int32 nIndex)251 	virtual css::uno::Any getItemByIntIndex( const sal_Int32 nIndex ) throw (css::uno::RuntimeException)
252 	{
253 		if ( !m_xIndexAccess.is() )
254 			throw css::uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScVbaCollectionBase numeric index access not supported by this object") ), css::uno::Reference< css::uno::XInterface >() );
255 		if ( nIndex <= 0 )
256 		{
257 			throw  css::lang::IndexOutOfBoundsException(
258 				::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
259 				"index is 0 or negative" ) ),
260 				css::uno::Reference< css::uno::XInterface >() );
261 		}
262 		// need to adjust for vba index ( for which first element is 1 )
263 		return createCollectionObject( m_xIndexAccess->getByIndex( nIndex - 1 ) );
264 	}
265 
UpdateCollectionIndex(const css::uno::Reference<css::container::XIndexAccess> & xIndexAccess)266     virtual void UpdateCollectionIndex( const css::uno::Reference< css::container::XIndexAccess >& xIndexAccess )
267     {
268         css::uno::Reference< css::container::XNameAccess > xNameAccess( xIndexAccess, css::uno::UNO_QUERY_THROW );
269         m_xIndexAccess = xIndexAccess;
270         m_xNameAccess = xNameAccess;
271     }
272 
273 public:
ScVbaCollectionBase(const css::uno::Reference<ov::XHelperInterface> & xParent,const css::uno::Reference<css::uno::XComponentContext> & xContext,const css::uno::Reference<css::container::XIndexAccess> & xIndexAccess)274 	ScVbaCollectionBase( const css::uno::Reference< ov::XHelperInterface >& xParent,   const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::container::XIndexAccess >& xIndexAccess ) : BaseColBase( xParent, xContext ), m_xIndexAccess( xIndexAccess ){ m_xNameAccess.set(m_xIndexAccess, css::uno::UNO_QUERY); }
275 	//XCollection
getCount()276 	virtual ::sal_Int32 SAL_CALL getCount() throw (css::uno::RuntimeException)
277 	{
278 		return m_xIndexAccess->getCount();
279 	}
280 
Item(const css::uno::Any & Index1,const css::uno::Any &)281 	virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index1, const css::uno::Any& /*not processed in this base class*/ ) throw (css::uno::RuntimeException)
282 	{
283 		if ( Index1.getValueTypeClass() != css::uno::TypeClass_STRING )
284 		{
285 			sal_Int32 nIndex = 0;
286 
287 			if ( ( Index1 >>= nIndex ) != sal_True )
288 			{
289 				rtl::OUString message;
290 				message = rtl::OUString::createFromAscii(
291 					"Couldn't convert index to Int32");
292 				throw  css::lang::IndexOutOfBoundsException( message,
293 					css::uno::Reference< css::uno::XInterface >() );
294 			}
295 			return 	getItemByIntIndex( nIndex );
296 		}
297 		rtl::OUString aStringSheet;
298 
299 		Index1 >>= aStringSheet;
300 		return getItemByStringIndex( aStringSheet );
301 	}
302 	// XDefaultMethod
getDefaultMethodName()303 	::rtl::OUString SAL_CALL getDefaultMethodName(  ) throw (css::uno::RuntimeException)
304 	{
305 		const static rtl::OUString sName( RTL_CONSTASCII_USTRINGPARAM("Item") );
306 		return sName;
307 	}
308 	// XEnumerationAccess
309 	virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() throw (css::uno::RuntimeException) = 0;
310 
311 	// XElementAccess
312 	virtual css::uno::Type SAL_CALL getElementType() throw (css::uno::RuntimeException) = 0;
313 	// XElementAccess
hasElements()314 	virtual ::sal_Bool SAL_CALL hasElements() throw (css::uno::RuntimeException)
315 	{
316 		return ( m_xIndexAccess->getCount() > 0 );
317 	}
318 	virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) = 0;
319 
320 };
321 
322 typedef ::cppu::WeakImplHelper1<ov::XCollection> XCollection_InterfacesBASE;
323 
324 typedef ScVbaCollectionBase< XCollection_InterfacesBASE > CollImplBase1;
325 // compatible with the old collections ( pre XHelperInterface base class ) ( some internal objects still use this )
326 class VBAHELPER_DLLPUBLIC ScVbaCollectionBaseImpl : public CollImplBase1
327 {
328 public:
ScVbaCollectionBaseImpl(const css::uno::Reference<ov::XHelperInterface> xParent,const css::uno::Reference<css::uno::XComponentContext> & xContext,const css::uno::Reference<css::container::XIndexAccess> & xIndexAccess)329 	ScVbaCollectionBaseImpl( const css::uno::Reference< ov::XHelperInterface > xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::container::XIndexAccess >& xIndexAccess ) throw( css::uno::RuntimeException ) : CollImplBase1( xParent, xContext, xIndexAccess){}
330 
331 };
332 
333 template <typename Ifc> // where Ifc must implement XCollectionTest
334 class CollTestImplHelper :  public ScVbaCollectionBase< ::cppu::WeakImplHelper1< Ifc > >
335 {
336 typedef ScVbaCollectionBase< ::cppu::WeakImplHelper1< Ifc >  > ImplBase1;
337 
338 public:
CollTestImplHelper(const css::uno::Reference<ov::XHelperInterface> & xParent,const css::uno::Reference<css::uno::XComponentContext> & xContext,const css::uno::Reference<css::container::XIndexAccess> & xIndexAccess)339 	CollTestImplHelper( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext,  const css::uno::Reference< css::container::XIndexAccess >& xIndexAccess ) throw( css::uno::RuntimeException ) : ImplBase1( xParent, xContext, xIndexAccess ) {}
340 };
341 
342 
343 #endif //SC_VBA_COLLECTION_IMPL_HXX
344