1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 #ifndef INCLUDED_COMPHELPER_INTERFACECONTAINER2_H
20 #define INCLUDED_COMPHELPER_INTERFACECONTAINER2_H
21 
22 #include <sal/config.h>
23 
24 #include <vector>
25 
26 #include <com/sun/star/lang/EventObject.hpp>
27 
28 #include <com/sun/star/lang/DisposedException.hpp>
29 #include <comphelper/comphelperdllapi.h>
30 
31 namespace com::sun::star::uno { class XInterface; }
32 namespace osl { class Mutex; }
33 
34 /** */ //for docpp
35 namespace comphelper
36 {
37 
38 namespace detail {
39 
40     /**
41       This is here to optimise space in the common case that there are zero or one
42       listeners.
43     */
44     union element_alias2
45     {
46         std::vector< css::uno::Reference< css::uno::XInterface > > *pAsVector;
47         css::uno::XInterface * pAsInterface;
element_alias2()48         element_alias2() : pAsInterface(nullptr) {}
49     };
50 
51 }
52 
53 
54 class OInterfaceContainerHelper2;
55 /**
56   This is the iterator of an InterfaceContainerHelper. Typically
57   one constructs an instance on the stack for one firing session.
58   It is not allowed to assign or copy an instance of this class.
59 
60   @see OInterfaceContainerHelper
61  */
62 class COMPHELPER_DLLPUBLIC OInterfaceIteratorHelper2
63 {
64 public:
65     /**
66        Create an iterator over the elements of the container. The iterator
67        copies the elements of the container. A change to the container
68        during the lifetime of an iterator is allowed and does not
69        affect the iterator-instance. The iterator and the container take cares
70        themself for concurrent access, no additional guarding is necessary.
71 
72        Remark: The copy is on demand. The iterator copy the elements only if the container
73        change the contents. It is not allowed to destroy the container as long
74        as an iterator exist.
75 
76        @param rCont the container of the elements.
77      */
78     OInterfaceIteratorHelper2( OInterfaceContainerHelper2 & rCont );
79 
80     /**
81       Releases the connection to the container.
82      */
83     ~OInterfaceIteratorHelper2();
84 
85     /** Return true, if there are more elements in the iterator. */
hasMoreElements() const86     bool hasMoreElements() const
87         { return nRemain != 0; }
88     /** Return the next element of the iterator. Calling this method if
89         hasMoreElements() has returned false, is an error. Cast the
90         returned pointer to the
91      */
92     css::uno::XInterface * next();
93 
94     /** Removes the current element (the last one returned by next())
95         from the underlying container. Calling this method before
96         next() has been called or calling it twice with no next()
97         inbetween is an error.
98     */
99     void remove();
100 
101 private:
102     OInterfaceContainerHelper2 & rCont;
103     detail::element_alias2       aData;
104     sal_Int32                    nRemain;
105     bool                         bIsList;
106 
107     OInterfaceIteratorHelper2( const OInterfaceIteratorHelper2 & ) = delete;
108     OInterfaceIteratorHelper2 &  operator = ( const OInterfaceIteratorHelper2 & ) = delete;
109 };
110 
111 
112 /**
113   A container of interfaces. To access the elements use an iterator.
114   This implementation is thread save.
115 
116   @see OInterfaceIteratorHelper
117  */
118 class COMPHELPER_DLLPUBLIC OInterfaceContainerHelper2
119 {
120 public:
121     /**
122        Create an interface container.
123 
124        @param rMutex    the mutex to protect multi thread access.
125        The lifetime must be longer than the lifetime
126        of this object.
127      */
128     OInterfaceContainerHelper2( ::osl::Mutex & rMutex );
129     /**
130       Release all interfaces. All iterators must be destroyed before
131       the container is destructed.
132      */
133     ~OInterfaceContainerHelper2();
134     /**
135       Return the number of Elements in the container. Only useful if you have acquired
136       the mutex.
137      */
138     sal_Int32 getLength() const;
139 
140     /**
141       Return all interfaces added to this container.
142      **/
143     std::vector< css::uno::Reference< css::uno::XInterface > > getElements() const;
144 
145     /** Inserts an element into the container.  The position is not specified, thus it is not
146         specified in which order events are fired.
147 
148         @attention
149         If you add the same interface more than once, then it will be added to the elements list
150         more than once and thus if you want to remove that interface from the list, you have to call
151         removeInterface() the same number of times.
152         In the latter case, you will also get events fired more than once (if the interface is a
153         listener interface).
154 
155         @param rxIFace
156                interface to be added; it is allowed to insert null or
157                the same interface more than once
158         @return
159                 the new count of elements in the container
160     */
161     sal_Int32 addInterface( const css::uno::Reference< css::uno::XInterface > & rxIFace );
162     /** Removes an element from the container.  It uses interface equality to remove the interface.
163 
164         @param rxIFace
165                interface to be removed
166         @return
167                 the new count of elements in the container
168     */
169     sal_Int32 removeInterface( const css::uno::Reference< css::uno::XInterface > & rxIFace );
170     /**
171       Call disposing on all object in the container that
172       support XEventListener. Then clear the container.
173      */
174     void disposeAndClear( const css::lang::EventObject & rEvt );
175     /**
176       Clears the container without calling disposing().
177      */
178     void clear();
179 
180     /** Executes a functor for each contained listener of specified type, e.g.
181         <code>forEach<awt::XPaintListener>(...</code>.
182 
183         If a css::lang::DisposedException occurs which relates to
184         the called listener, then that listener is removed from the container.
185 
186         @tparam ListenerT listener type
187         @tparam FuncT unary functor type, let your compiler deduce this for you
188         @param func unary functor object expecting an argument of type
189                     css::uno::Reference<ListenerT>
190     */
191     template <typename ListenerT, typename FuncT>
192     inline void forEach( FuncT const& func );
193 
194     /** Calls a UNO listener method for each contained listener.
195 
196         The listener method must take a single argument of type EventT,
197         and return <code>void</code>.
198 
199         If a css::lang::DisposedException occurs which relates to
200         the called listener, then that listener is removed from the container.
201 
202         @tparam ListenerT UNO event listener type, let your compiler deduce this for you
203         @tparam EventT event type, let your compiler deduce this for you
204         @param NotificationMethod
205             Pointer to a method of a ListenerT interface.
206         @param Event
207             Event to notify to all contained listeners
208 
209         Example:
210 @code
211     awt::PaintEvent aEvent( static_cast< cppu::OWeakObject* >( this ), ... );
212     listeners.notifyEach( &XPaintListener::windowPaint, aEvent );
213 @endcode
214     */
215     template< typename ListenerT, typename EventT >
216     inline void notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event );
217 
218 private:
219 friend class OInterfaceIteratorHelper2;
220     /**
221       bIsList == TRUE -> aData.pAsVector of type vector< XInterfaceSequence >,
222       otherwise aData.pAsInterface == of type (XEventListener *)
223      */
224     detail::element_alias2  aData;
225     ::osl::Mutex &          rMutex;
226     /** TRUE -> used by an iterator. */
227     bool                    bInUse;
228     /** TRUE -> aData.pAsVector is of type Sequence< XInterfaceSequence >. */
229     bool                    bIsList;
230 
231     OInterfaceContainerHelper2( const OInterfaceContainerHelper2 & ) = delete;
232     OInterfaceContainerHelper2 & operator = ( const OInterfaceContainerHelper2 & ) = delete;
233 
234     /*
235       Duplicate content of the container and release the old one without destroying.
236       The mutex must be locked and the memberbInUse must be true.
237      */
238     void copyAndResetInUse();
239 
240 private:
241     template< typename ListenerT, typename EventT >
242     class NotifySingleListener
243     {
244     private:
245         typedef void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& );
246         NotificationMethod const m_pMethod;
247         const EventT&            m_rEvent;
248     public:
NotifySingleListener(NotificationMethod method,const EventT & event)249         NotifySingleListener( NotificationMethod method, const EventT& event ) : m_pMethod( method ), m_rEvent( event ) { }
250 
operator ()(const css::uno::Reference<ListenerT> & listener) const251         void operator()( const css::uno::Reference<ListenerT>& listener ) const
252         {
253             (listener.get()->*m_pMethod)( m_rEvent );
254         }
255     };
256 };
257 
258 template <typename ListenerT, typename FuncT>
forEach(FuncT const & func)259 inline void OInterfaceContainerHelper2::forEach( FuncT const& func )
260 {
261     OInterfaceIteratorHelper2 iter( *this );
262     while (iter.hasMoreElements()) {
263         css::uno::Reference<ListenerT> const xListener( iter.next(), css::uno::UNO_QUERY );
264         if (xListener.is()) {
265             try {
266                 func( xListener );
267             }
268             catch (css::lang::DisposedException const& exc) {
269                 if (exc.Context == xListener)
270                     iter.remove();
271             }
272         }
273     }
274 }
275 
276 template< typename ListenerT, typename EventT >
notifyEach(void (SAL_CALL ListenerT::* NotificationMethod)(const EventT &),const EventT & Event)277 inline void OInterfaceContainerHelper2::notifyEach( void ( SAL_CALL ListenerT::*NotificationMethod )( const EventT& ), const EventT& Event )
278 {
279     forEach< ListenerT, NotifySingleListener< ListenerT, EventT > >( NotifySingleListener< ListenerT, EventT >( NotificationMethod, Event ) );
280 }
281 
282 }
283 #endif
284 
285 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
286