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 _COLLECTION_HXX
25 #define _COLLECTION_HXX
26 
27 #include "enumeration.hxx"
28 
29 #include <cppuhelper/implbase3.hxx>
30 #include <com/sun/star/container/ElementExistException.hpp>
31 #include <com/sun/star/container/NoSuchElementException.hpp>
32 #include <com/sun/star/container/XEnumeration.hpp>
33 #include <com/sun/star/container/XIndexReplace.hpp>
34 #include <com/sun/star/container/XSet.hpp>
35 #include <com/sun/star/container/XContainer.hpp>
36 #include <com/sun/star/container/XContainerListener.hpp>
37 #include <com/sun/star/lang/IllegalArgumentException.hpp>
38 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
39 #include <com/sun/star/lang/WrappedTargetException.hpp>
40 #include <com/sun/star/uno/Any.hxx>
41 #include <com/sun/star/uno/Reference.hxx>
42 #include <com/sun/star/uno/RuntimeException.hpp>
43 #include <com/sun/star/uno/Type.hxx>
44 #include <vector>
45 #include <algorithm>
46 
47 
48 typedef cppu::WeakImplHelper3<
49     com::sun::star::container::XIndexReplace,
50     com::sun::star::container::XSet,
51     com::sun::star::container::XContainer>
52 Collection_t;
53 
54 template<class ELEMENT_TYPE>
55 class Collection : public Collection_t
56 {
57 public:
58     typedef ELEMENT_TYPE T;
59     typedef com::sun::star::uno::Reference<com::sun::star::container::XContainerListener> XContainerListener_t;
60     typedef std::vector<XContainerListener_t> Listeners_t;
61 
62 protected:
63     std::vector<T> maItems;
64     Listeners_t maListeners;
65 
66 public:
67 
Collection()68     Collection() {}
~Collection()69     virtual ~Collection() {}
70 
getItem(sal_Int32 n) const71     const T& getItem( sal_Int32 n ) const
72     {
73         OSL_ENSURE( isValidIndex(n), "invalid index" );
74         OSL_ENSURE( isValid( maItems[n] ), "invalid item found" );
75         return maItems[n];
76     }
77 
setItem(sal_Int32 n,const T & t)78     void setItem( sal_Int32 n, const T& t)
79     {
80         OSL_ENSURE( isValidIndex(n), "invalid index" );
81         OSL_ENSURE( isValid ( t ), "invalid item" );
82 
83         T& aRef = maItems[ n ];
84         _elementReplaced( n, t );
85         _remove( aRef );
86         aRef = t;
87         _insert( t );
88     }
89 
hasItem(const T & t) const90     bool hasItem( const T& t ) const
91     {
92         return maItems.end() != std::find( maItems.begin(), maItems.end(), t );
93     }
94 
addItem(const T & t)95     sal_Int32 addItem( const T& t )
96     {
97         OSL_ENSURE( !hasItem( t ), "item to be added already present" );
98         OSL_ENSURE( isValid( t ), "invalid item" );
99 
100         maItems.push_back( t );
101         _insert( t );
102         _elementInserted( maItems.size() - 1 );
103         return ( maItems.size() - 1 );
104     }
105 
removeItem(const T & t)106     void removeItem( const T& t )
107     {
108         OSL_ENSURE( hasItem( t ), "item to be removed not present" );
109         OSL_ENSURE( isValid( t ), "an invalid item, funny that!" );
110 
111         _elementRemoved( t );
112         _remove( t );
113         maItems.erase( std::find( maItems.begin(), maItems.end(), t ) );
114     }
115 
hasItems() const116     bool hasItems() const
117     {
118         return maItems.size() != 0;
119     }
120 
countItems() const121     sal_Int32 countItems() const
122     {
123         return static_cast<sal_Int32>( maItems.size() );
124     }
125 
isValidIndex(sal_Int32 n) const126     bool isValidIndex( sal_Int32 n ) const
127     {
128         return n >= 0  &&  n < static_cast<sal_Int32>( maItems.size() );
129     }
130 
131 
132     // the following method may be overriden by sub-classes for
133     // customized behaviour
134 
135     /// called before insertion to determine whether item is valid
isValid(const T &) const136     virtual bool isValid( const T& ) const { return true; }
137 
138 
139 protected:
140 
141     // the following methods may be overriden by sub-classes for
142     // customized behaviour
143 
144     /// called after item has been inserted into the collection
_insert(const T &)145     virtual void _insert( const T& ) { }
146 
147     /// called before item is removed from the collection
_remove(const T &)148     virtual void _remove( const T& ) { }
149 
150 public:
151 
152     typedef com::sun::star::uno::Type Type_t;
153     typedef com::sun::star::uno::Any Any_t;
154     typedef com::sun::star::uno::RuntimeException RuntimeException_t;
155     typedef com::sun::star::lang::IllegalArgumentException IllegalArgumentException_t;
156     typedef com::sun::star::container::NoSuchElementException NoSuchElementException_t;
157     typedef com::sun::star::lang::IndexOutOfBoundsException IndexOutOfBoundsException_t;
158     typedef com::sun::star::uno::Reference<com::sun::star::container::XEnumeration> XEnumeration_t;
159     typedef com::sun::star::lang::WrappedTargetException WrappedTargetException_t;
160     typedef com::sun::star::container::ElementExistException ElementExistException_t;
161 
162 
163     // XElementAccess
getElementType()164     virtual Type_t SAL_CALL getElementType()
165         throw( RuntimeException_t )
166     {
167         return getCppuType( static_cast<T*>( NULL ) );
168     }
169 
hasElements()170     virtual sal_Bool SAL_CALL hasElements()
171         throw( RuntimeException_t )
172     {
173         return hasItems();
174     }
175 
176     // XIndexAccess : XElementAccess
getCount()177     virtual sal_Int32 SAL_CALL getCount()
178         throw( RuntimeException_t )
179     {
180         return countItems();
181     }
182 
getByIndex(sal_Int32 nIndex)183     virtual Any_t SAL_CALL getByIndex( sal_Int32 nIndex )
184         throw( IndexOutOfBoundsException_t,
185                WrappedTargetException_t,
186                RuntimeException_t)
187     {
188         if( isValidIndex( nIndex ) )
189             return com::sun::star::uno::makeAny( getItem( nIndex ) );
190         else
191             throw IndexOutOfBoundsException_t();
192     }
193 
194     // XIndexReplace : XIndexAccess
replaceByIndex(sal_Int32 nIndex,const Any_t & aElement)195     virtual void SAL_CALL replaceByIndex( sal_Int32 nIndex,
196                                           const Any_t& aElement )
197         throw( IllegalArgumentException_t,
198                IndexOutOfBoundsException_t,
199                WrappedTargetException_t,
200                RuntimeException_t)
201     {
202         T t;
203         if( isValidIndex( nIndex) )
204             if( ( aElement >>= t )  &&  isValid( t ) )
205                 setItem( nIndex, t );
206             else
207                 throw IllegalArgumentException_t();
208         else
209             throw IndexOutOfBoundsException_t();
210     }
211 
212     // XEnumerationAccess : XElementAccess
createEnumeration()213     virtual XEnumeration_t SAL_CALL createEnumeration()
214         throw( RuntimeException_t )
215     {
216         return new Enumeration( this );
217     }
218 
219 
220     // XSet : XEnumerationAccess
has(const Any_t & aElement)221     virtual sal_Bool SAL_CALL has( const Any_t& aElement )
222         throw( RuntimeException_t )
223     {
224         T t;
225         return ( aElement >>= t ) ? hasItem( t ) : sal_False;
226     }
227 
insert(const Any_t & aElement)228     virtual void SAL_CALL insert( const Any_t& aElement )
229         throw( IllegalArgumentException_t,
230                ElementExistException_t,
231                RuntimeException_t )
232     {
233         T t;
234         if( ( aElement >>= t )  &&  isValid( t ) )
235             if( ! hasItem( t ) )
236                 addItem( t );
237             else
238                 throw ElementExistException_t();
239         else
240             throw IllegalArgumentException_t();
241     }
242 
remove(const Any_t & aElement)243     virtual void SAL_CALL remove( const Any_t& aElement )
244         throw( IllegalArgumentException_t,
245                NoSuchElementException_t,
246                RuntimeException_t )
247     {
248         T t;
249         if( aElement >>= t )
250             if( hasItem( t ) )
251                 removeItem( t );
252             else
253                 throw NoSuchElementException_t();
254         else
255             throw IllegalArgumentException_t();
256     }
257 
258 
259     // XContainer
addContainerListener(const XContainerListener_t & xListener)260     virtual void SAL_CALL addContainerListener(
261         const XContainerListener_t& xListener )
262         throw( RuntimeException_t )
263     {
264         OSL_ENSURE( xListener.is(), "need listener!" );
265         if( std::find( maListeners.begin(), maListeners.end(), xListener)
266             == maListeners.end() )
267             maListeners.push_back( xListener );
268     }
269 
removeContainerListener(const XContainerListener_t & xListener)270     virtual void SAL_CALL removeContainerListener(
271         const XContainerListener_t& xListener )
272         throw( RuntimeException_t )
273     {
274         OSL_ENSURE( xListener.is(), "need listener!" );
275         Listeners_t::iterator aIter =
276             std::find( maListeners.begin(), maListeners.end(), xListener );
277         if( aIter != maListeners.end() )
278             maListeners.erase( aIter );
279     }
280 
281 protected:
282 
283     // call listeners:
_elementInserted(sal_Int32 nPos)284     void _elementInserted( sal_Int32 nPos )
285     {
286         OSL_ENSURE( isValidIndex(nPos), "invalid index" );
287         com::sun::star::container::ContainerEvent aEvent(
288             static_cast<com::sun::star::container::XIndexReplace*>( this ),
289             com::sun::star::uno::makeAny( nPos ),
290             com::sun::star::uno::makeAny( getItem( nPos ) ),
291             com::sun::star::uno::Any() );
292         for( Listeners_t::iterator aIter = maListeners.begin();
293              aIter != maListeners.end();
294              aIter++ )
295         {
296             (*aIter)->elementInserted( aEvent );
297         }
298     }
299 
_elementRemoved(const T & aOld)300     void _elementRemoved( const T& aOld )
301     {
302         com::sun::star::container::ContainerEvent aEvent(
303             static_cast<com::sun::star::container::XIndexReplace*>( this ),
304             com::sun::star::uno::Any(),
305             com::sun::star::uno::makeAny( aOld ),
306             com::sun::star::uno::Any() );
307         for( Listeners_t::iterator aIter = maListeners.begin();
308              aIter != maListeners.end();
309              aIter++ )
310         {
311             (*aIter)->elementRemoved( aEvent );
312         }
313     }
314 
_elementReplaced(const sal_Int32 nPos,const T & aNew)315     void _elementReplaced( const sal_Int32 nPos, const T& aNew )
316     {
317         OSL_ENSURE( isValidIndex(nPos), "invalid index" );
318         com::sun::star::container::ContainerEvent aEvent(
319             static_cast<com::sun::star::container::XIndexReplace*>( this ),
320             com::sun::star::uno::makeAny( nPos ),
321             com::sun::star::uno::makeAny( getItem( nPos ) ),
322             com::sun::star::uno::makeAny( aNew ) );
323         for( Listeners_t::iterator aIter = maListeners.begin();
324              aIter != maListeners.end();
325              aIter++ )
326         {
327             (*aIter)->elementReplaced( aEvent );
328         }
329     }
330 
331 };
332 
333 #endif
334