LibreOffice Module comphelper (master) 1
interfacecontainer3.hxx
Go to the documentation of this file.
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#pragma once
20
21#include <sal/config.h>
22
23#include <com/sun/star/lang/EventObject.hpp>
24#include <com/sun/star/lang/DisposedException.hpp>
25#include <o3tl/cow_wrapper.hxx>
26#include <vector>
27
28namespace com::sun::star::uno
29{
30class XInterface;
31}
32namespace osl
33{
34class Mutex;
35}
36
37namespace comphelper
38{
39template <class ListenerT> class OInterfaceContainerHelper3;
48template <class ListenerT> class OInterfaceIteratorHelper3
49{
50public:
64 : rCont(rCont_)
66 , nRemain(maData->size())
67 {
68 }
69
71 bool hasMoreElements() const { return nRemain != 0; }
75 css::uno::Reference<ListenerT> const& next();
76
82 void remove();
83
84private:
89 sal_Int32 nRemain;
90
93};
94
95template <class ListenerT>
96const css::uno::Reference<ListenerT>& OInterfaceIteratorHelper3<ListenerT>::next()
97{
98 nRemain--;
99 return (*maData)[nRemain];
100}
101
102template <class ListenerT> void OInterfaceIteratorHelper3<ListenerT>::remove()
103{
104 rCont.removeInterface((*maData)[nRemain]);
105}
106
119template <class ListenerT> class OInterfaceContainerHelper3
120{
121public:
129 inline OInterfaceContainerHelper3(::osl::Mutex& rMutex_);
130
135 sal_Int32 getLength() const;
136
140 std::vector<css::uno::Reference<ListenerT>> getElements() const;
141
158 sal_Int32 addInterface(const css::uno::Reference<ListenerT>& rxIFace);
166 sal_Int32 removeInterface(const css::uno::Reference<ListenerT>& rxIFace);
169 const css::uno::Reference<ListenerT>& getInterface(sal_Int32 nIndex) const;
174 void disposeAndClear(const css::lang::EventObject& rEvt);
178 void clear();
179
190 template <typename FuncT> inline void forEach(FuncT const& func);
191
212 template <typename EventT>
213 inline void notifyEach(void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&),
214 const EventT& Event);
215
216private:
217 friend class OInterfaceIteratorHelper3<ListenerT>;
220 maData;
221 ::osl::Mutex& mrMutex;
223 OInterfaceContainerHelper3& operator=(const OInterfaceContainerHelper3&) = delete;
224
227 DEFAULT()
228 {
231 SINGLETON;
232 return SINGLETON;
233 }
234
235private:
236 template <typename EventT> class NotifySingleListener
237 {
238 private:
239 typedef void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&);
240 NotificationMethod const m_pMethod;
241 const EventT& m_rEvent;
242
243 public:
244 NotifySingleListener(NotificationMethod method, const EventT& event)
245 : m_pMethod(method)
246 , m_rEvent(event)
247 {
248 }
249
250 void operator()(const css::uno::Reference<ListenerT>& listener) const
251 {
252 (listener.get()->*m_pMethod)(m_rEvent);
253 }
254 };
255};
256
257template <class T>
258inline OInterfaceContainerHelper3<T>::OInterfaceContainerHelper3(::osl::Mutex& rMutex_)
259 : maData(OInterfaceContainerHelper3<T>::DEFAULT())
260 , mrMutex(rMutex_)
261{
262}
263
264template <class T>
265template <typename FuncT>
266inline void OInterfaceContainerHelper3<T>::forEach(FuncT const& func)
267{
268 OInterfaceIteratorHelper3<T> iter(*this);
269 while (iter.hasMoreElements())
270 {
271 auto xListener = iter.next();
272 try
273 {
274 func(xListener);
275 }
276 catch (css::lang::DisposedException const& exc)
277 {
278 if (exc.Context == xListener)
279 iter.remove();
280 }
281 }
282}
283
284template <class ListenerT>
285template <typename EventT>
286inline void OInterfaceContainerHelper3<ListenerT>::notifyEach(
287 void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&), const EventT& Event)
288{
289 forEach<NotifySingleListener<EventT>>(NotifySingleListener<EventT>(NotificationMethod, Event));
290}
291
292template <class ListenerT> sal_Int32 OInterfaceContainerHelper3<ListenerT>::getLength() const
293{
294 osl::MutexGuard aGuard(mrMutex);
295 return maData->size();
296}
297
298template <class ListenerT>
299std::vector<css::uno::Reference<ListenerT>>
300OInterfaceContainerHelper3<ListenerT>::getElements() const
301{
302 std::vector<css::uno::Reference<ListenerT>> rVec;
303 osl::MutexGuard aGuard(mrMutex);
304 rVec = *maData;
305 return rVec;
306}
307
308template <class ListenerT>
309sal_Int32
310OInterfaceContainerHelper3<ListenerT>::addInterface(const css::uno::Reference<ListenerT>& rListener)
311{
312 assert(rListener.is());
313 osl::MutexGuard aGuard(mrMutex);
314
315 maData->push_back(rListener);
316 return maData->size();
317}
318
319template <class ListenerT>
320sal_Int32 OInterfaceContainerHelper3<ListenerT>::removeInterface(
321 const css::uno::Reference<ListenerT>& rListener)
322{
323 assert(rListener.is());
324 osl::MutexGuard aGuard(mrMutex);
325
326 // It is not valid to compare the pointer directly, but it's faster.
327 auto it = std::find_if(maData->begin(), maData->end(),
328 [&rListener](const css::uno::Reference<css::uno::XInterface>& rItem) {
329 return rItem.get() == rListener.get();
330 });
331
332 // interface not found, use the correct compare method
333 if (it == maData->end())
334 it = std::find(maData->begin(), maData->end(), rListener);
335
336 if (it != maData->end())
337 maData->erase(it);
338
339 return maData->size();
340}
341
342template <class ListenerT>
343const css::uno::Reference<ListenerT>&
344OInterfaceContainerHelper3<ListenerT>::getInterface(sal_Int32 nIndex) const
345{
346 osl::MutexGuard aGuard(mrMutex);
347
348 return (*maData)[nIndex];
349}
350
351template <class ListenerT>
352void OInterfaceContainerHelper3<ListenerT>::disposeAndClear(const css::lang::EventObject& rEvt)
353{
354 osl::ClearableMutexGuard aGuard(mrMutex);
355 OInterfaceIteratorHelper3<ListenerT> aIt(*this);
356 maData->clear();
357 aGuard.clear();
358 while (aIt.hasMoreElements())
359 {
360 try
361 {
362 aIt.next()->disposing(rEvt);
363 }
364 catch (css::uno::RuntimeException&)
365 {
366 // be robust, if e.g. a remote bridge has disposed already.
367 // there is no way to delegate the error to the caller :o(.
368 }
369 }
370}
371
372template <class ListenerT> void OInterfaceContainerHelper3<ListenerT>::clear()
373{
374 osl::MutexGuard aGuard(mrMutex);
375 maData->clear();
376}
377}
378
379/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
typedef void(SAL_CALL ListenerT::*NotificationMethod)(const EventT &)
NotifySingleListener(NotificationMethod method, const EventT &event)
void operator()(const css::uno::Reference< ListenerT > &listener) const
This is the iterator of an OInterfaceContainerHelper3.
OInterfaceIteratorHelper3 & operator=(const OInterfaceIteratorHelper3 &)=delete
bool hasMoreElements() const
Return true, if there are more elements in the iterator.
OInterfaceContainerHelper3< ListenerT > & rCont
void remove()
Removes the current element (the last one returned by next()) from the underlying container.
css::uno::Reference< ListenerT > const & next()
Return the next element of the iterator.
o3tl::cow_wrapper< std::vector< css::uno::Reference< ListenerT > >, o3tl::ThreadSafeRefCountingPolicy > maData
OInterfaceIteratorHelper3(OInterfaceContainerHelper3< ListenerT > &rCont_)
Create an iterator over the elements of the container.
OInterfaceIteratorHelper3(const OInterfaceIteratorHelper3 &)=delete
sal_Int32 nIndex
std::vector< sal_Int8, boost::noinit_adaptor< std::allocator< sal_Int8 > > > maData
size
static PropertyMapEntry const * find(const rtl::Reference< PropertySetInfo > &mxInfo, const OUString &aName) noexcept