tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / sfx2 / source / notify / globalevents.cxx
blobae05b7c9391189da2615fa6c27680003c87ef34d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/types.h>
22 #include <com/sun/star/task/theJobExecutor.hpp>
23 #include <com/sun/star/container/XNameReplace.hpp>
24 #include <com/sun/star/container/XSet.hpp>
25 #include <com/sun/star/document/XEventListener.hpp>
26 #include <com/sun/star/document/XEventBroadcaster.hpp>
27 #include <com/sun/star/document/XDocumentEventListener.hpp>
28 #include <com/sun/star/frame/XGlobalEventBroadcaster.hpp>
29 #include <com/sun/star/lang/DisposedException.hpp>
30 #include <com/sun/star/lang/NoSupportException.hpp>
31 #include <com/sun/star/lang/XServiceInfo.hpp>
32 #include <com/sun/star/uno/Type.hxx>
34 #include <cppuhelper/implbase.hxx>
35 #include <comphelper/interfacecontainer4.hxx>
36 #include <cppuhelper/supportsservice.hxx>
37 #include <comphelper/enumhelper.hxx>
38 #include <rtl/ref.hxx>
39 #include <sfx2/app.hxx>
40 #include <comphelper/diagnose_ex.hxx>
41 #include <unotools/eventcfg.hxx>
42 #include <eventsupplier.hxx>
44 #include <mutex>
45 #include <set>
46 #include <vector>
48 using namespace css;
50 namespace {
52 typedef ::std::vector< css::uno::Reference< css::frame::XModel > > TModelList;
55 //TODO: remove support of obsolete document::XEventBroadcaster/Listener
56 class SfxGlobalEvents_Impl : public ::cppu::WeakImplHelper< css::lang::XServiceInfo
57 , css::frame::XGlobalEventBroadcaster
58 , css::document::XEventBroadcaster
59 , css::document::XEventListener
60 , css::lang::XComponent
63 std::mutex m_aLock;
64 rtl::Reference< GlobalEventConfig > m_xEvents;
65 css::uno::Reference< css::document::XEventListener > m_xJobExecutorListener;
66 ::comphelper::OInterfaceContainerHelper4<document::XEventListener> m_aLegacyListeners;
67 ::comphelper::OInterfaceContainerHelper4<document::XDocumentEventListener> m_aDocumentListeners;
68 std::multiset<css::uno::Reference<css::lang::XEventListener>> m_disposeListeners;
69 TModelList m_lModels;
70 bool m_disposed;
72 public:
73 explicit SfxGlobalEvents_Impl(const css::uno::Reference < css::uno::XComponentContext >& rxContext);
75 virtual OUString SAL_CALL getImplementationName() override
77 return u"com.sun.star.comp.sfx2.GlobalEventBroadcaster"_ustr;
80 virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
82 return cppu::supportsService(this, ServiceName);
85 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
87 css::uno::Sequence< OUString > aSeq { u"com.sun.star.frame.GlobalEventBroadcaster"_ustr };
88 return aSeq;
91 // css.document.XEventBroadcaster
92 virtual css::uno::Reference< css::container::XNameReplace > SAL_CALL getEvents() override;
94 virtual void SAL_CALL addEventListener(const css::uno::Reference< css::document::XEventListener >& xListener) override;
96 virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::document::XEventListener >& xListener) override;
98 // css.document.XDocumentEventBroadcaster
99 virtual void SAL_CALL addDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& Listener ) override;
100 virtual void SAL_CALL removeDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& Listener ) override;
101 virtual void SAL_CALL notifyDocumentEvent( const OUString& EventName, const css::uno::Reference< css::frame::XController2 >& ViewController, const css::uno::Any& Supplement ) override;
103 // css.document.XEventListener
104 virtual void SAL_CALL notifyEvent(const css::document::EventObject& aEvent) override;
106 // css.document.XDocumentEventListener
107 virtual void SAL_CALL documentEventOccured( const css::document::DocumentEvent& Event ) override;
109 // css.container.XSet
110 virtual sal_Bool SAL_CALL has(const css::uno::Any& aElement) override;
112 virtual void SAL_CALL insert(const css::uno::Any& aElement) override;
114 virtual void SAL_CALL remove(const css::uno::Any& aElement) override;
116 // css.container.XEnumerationAccess
117 virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
119 // css.container.XElementAccess
120 virtual css::uno::Type SAL_CALL getElementType() override;
122 virtual sal_Bool SAL_CALL hasElements() override;
124 // css.lang.XEventListener
125 virtual void SAL_CALL disposing(const css::lang::EventObject& aEvent) override;
127 // css.lang.XComponent
128 void SAL_CALL dispose() override;
130 void SAL_CALL addEventListener(css::uno::Reference<css::lang::XEventListener> const & xListener)
131 override;
133 void SAL_CALL removeEventListener(
134 css::uno::Reference<css::lang::XEventListener> const & aListener) override;
136 private:
138 // threadsafe
139 void implts_notifyJobExecution(const css::document::EventObject& aEvent);
140 void implts_checkAndExecuteEventBindings(const css::document::DocumentEvent& aEvent);
141 void implts_notifyListener(const css::document::DocumentEvent& aEvent);
143 // not threadsafe
144 TModelList::iterator impl_searchDoc(const css::uno::Reference< css::frame::XModel >& xModel);
147 SfxGlobalEvents_Impl::SfxGlobalEvents_Impl( const uno::Reference < uno::XComponentContext >& rxContext)
148 : m_xJobExecutorListener( task::theJobExecutor::get( rxContext ), uno::UNO_QUERY_THROW )
149 , m_disposed(false)
151 osl_atomic_increment(&m_refCount);
152 SfxApplication::GetOrCreate();
153 m_xEvents = new GlobalEventConfig();
154 osl_atomic_decrement(&m_refCount);
157 uno::Reference< container::XNameReplace > SAL_CALL SfxGlobalEvents_Impl::getEvents()
159 // SAFE ->
160 std::scoped_lock aLock(m_aLock);
161 if (m_disposed) {
162 throw css::lang::DisposedException();
164 return m_xEvents;
165 // <- SAFE
169 void SAL_CALL SfxGlobalEvents_Impl::addEventListener(const uno::Reference< document::XEventListener >& xListener)
171 std::unique_lock g(m_aLock);
172 if (m_disposed)
173 throw css::lang::DisposedException();
174 m_aLegacyListeners.addInterface(g, xListener);
178 void SAL_CALL SfxGlobalEvents_Impl::removeEventListener(const uno::Reference< document::XEventListener >& xListener)
180 std::unique_lock g(m_aLock);
181 // The below removeInterface will silently do nothing when m_disposed
182 m_aLegacyListeners.removeInterface(g, xListener);
186 void SAL_CALL SfxGlobalEvents_Impl::addDocumentEventListener( const uno::Reference< document::XDocumentEventListener >& Listener )
188 std::unique_lock g(m_aLock);
189 if (m_disposed)
190 throw css::lang::DisposedException();
191 m_aDocumentListeners.addInterface( g, Listener );
195 void SAL_CALL SfxGlobalEvents_Impl::removeDocumentEventListener( const uno::Reference< document::XDocumentEventListener >& Listener )
197 std::unique_lock g(m_aLock);
198 // The below removeInterface will silently do nothing when m_disposed:
199 m_aDocumentListeners.removeInterface( g, Listener );
203 void SAL_CALL SfxGlobalEvents_Impl::notifyDocumentEvent( const OUString& /*_EventName*/,
204 const uno::Reference< frame::XController2 >& /*_ViewController*/, const uno::Any& /*_Supplement*/ )
206 // we're a multiplexer only, no chance to generate artificial events here
207 throw lang::NoSupportException(OUString(), *this);
211 void SAL_CALL SfxGlobalEvents_Impl::notifyEvent(const document::EventObject& aEvent)
213 // The below implts_* will silently do nothing when m_disposed:
214 document::DocumentEvent aDocEvent(aEvent.Source, aEvent.EventName, nullptr, uno::Any());
215 implts_notifyJobExecution(aEvent);
216 implts_checkAndExecuteEventBindings(aDocEvent);
217 implts_notifyListener(aDocEvent);
221 void SAL_CALL SfxGlobalEvents_Impl::documentEventOccured( const document::DocumentEvent& Event )
223 // The below implts_* will silently do nothing when m_disposed:
224 implts_notifyJobExecution(document::EventObject(Event.Source, Event.EventName));
225 implts_checkAndExecuteEventBindings(Event);
226 implts_notifyListener(Event);
230 void SAL_CALL SfxGlobalEvents_Impl::disposing(const lang::EventObject& aEvent)
232 uno::Reference< frame::XModel > xDoc(aEvent.Source, uno::UNO_QUERY);
234 // SAFE ->
235 std::scoped_lock g(m_aLock);
236 TModelList::iterator pIt = impl_searchDoc(xDoc);
237 if (pIt != m_lModels.end())
238 m_lModels.erase(pIt);
239 // <- SAFE
242 void SfxGlobalEvents_Impl::dispose() {
243 std::multiset<css::uno::Reference<css::lang::XEventListener>> listeners;
245 std::unique_lock g(m_aLock);
246 if (m_disposed)
247 return;
248 m_disposed = true;
249 auto tmpEvents = std::move(m_xEvents);
250 auto tmpModels = std::move(m_lModels);
251 m_xJobExecutorListener.clear();
252 m_disposeListeners.swap(listeners);
253 m_lModels.clear();
254 g.unlock();
255 // clear events&models outside lock because it will trigger a call back into us
256 tmpEvents.clear();
257 tmpModels.clear();
258 g.lock();
259 m_aLegacyListeners.disposeAndClear(g, {getXWeak()});
260 m_aDocumentListeners.disposeAndClear(g, {getXWeak()});
262 for (auto const & i: listeners) {
263 try {
264 i->disposing({getXWeak()});
265 } catch (css::lang::DisposedException &) {}
269 void SfxGlobalEvents_Impl::addEventListener(
270 css::uno::Reference<css::lang::XEventListener> const & xListener)
272 if (!xListener.is()) {
273 throw css::uno::RuntimeException(u"null listener"_ustr);
276 std::scoped_lock g(m_aLock);
277 if (!m_disposed) {
278 m_disposeListeners.insert(xListener);
279 return;
282 try {
283 xListener->disposing({getXWeak()});
284 } catch (css::lang::DisposedException &) {}
287 void SfxGlobalEvents_Impl::removeEventListener(
288 css::uno::Reference<css::lang::XEventListener> const & aListener)
290 std::scoped_lock g(m_aLock);
291 auto const i = m_disposeListeners.find(aListener);
292 if (i != m_disposeListeners.end()) {
293 m_disposeListeners.erase(i);
297 sal_Bool SAL_CALL SfxGlobalEvents_Impl::has(const uno::Any& aElement)
299 uno::Reference< frame::XModel > xDoc;
300 aElement >>= xDoc;
302 bool bHas = false;
304 // SAFE ->
305 std::scoped_lock g(m_aLock);
306 if (m_disposed) {
307 throw css::lang::DisposedException();
309 TModelList::iterator pIt = impl_searchDoc(xDoc);
310 if (pIt != m_lModels.end())
311 bHas = true;
312 // <- SAFE
314 return bHas;
318 void SAL_CALL SfxGlobalEvents_Impl::insert( const uno::Any& aElement )
320 uno::Reference< frame::XModel > xDoc;
321 aElement >>= xDoc;
322 if (!xDoc.is())
323 throw lang::IllegalArgumentException(
324 u"Can not locate at least the model parameter."_ustr,
325 static_cast< container::XSet* >(this),
328 // SAFE ->
330 std::scoped_lock g(m_aLock);
331 if (m_disposed) {
332 throw css::lang::DisposedException();
334 TModelList::iterator pIt = impl_searchDoc(xDoc);
335 if (pIt != m_lModels.end())
336 throw container::ElementExistException(
337 OUString(),
338 static_cast<container::XSet*>(this));
339 m_lModels.push_back(xDoc);
341 // <- SAFE
343 uno::Reference< document::XDocumentEventBroadcaster > xDocBroadcaster(xDoc, uno::UNO_QUERY );
344 if (xDocBroadcaster.is())
345 xDocBroadcaster->addDocumentEventListener(this);
346 else
348 // try the "legacy version" of XDocumentEventBroadcaster, which is XEventBroadcaster
349 uno::Reference< document::XEventBroadcaster > xBroadcaster(xDoc, uno::UNO_QUERY);
350 if (xBroadcaster.is())
351 xBroadcaster->addEventListener(static_cast< document::XEventListener* >(this));
356 void SAL_CALL SfxGlobalEvents_Impl::remove( const uno::Any& aElement )
358 uno::Reference< frame::XModel > xDoc;
359 aElement >>= xDoc;
360 if (!xDoc.is())
361 throw lang::IllegalArgumentException(
362 u"Can not locate at least the model parameter."_ustr,
363 static_cast< container::XSet* >(this),
366 // SAFE ->
368 std::scoped_lock g(m_aLock);
369 TModelList::iterator pIt = impl_searchDoc(xDoc);
370 if (pIt == m_lModels.end())
371 throw container::NoSuchElementException(
372 OUString(),
373 static_cast<container::XSet*>(this));
374 m_lModels.erase(pIt);
376 // <- SAFE
378 uno::Reference< document::XDocumentEventBroadcaster > xDocBroadcaster(xDoc, uno::UNO_QUERY );
379 if (xDocBroadcaster.is())
380 xDocBroadcaster->removeDocumentEventListener(this);
381 else
383 // try the "legacy version" of XDocumentEventBroadcaster, which is XEventBroadcaster
384 uno::Reference< document::XEventBroadcaster > xBroadcaster(xDoc, uno::UNO_QUERY);
385 if (xBroadcaster.is())
386 xBroadcaster->removeEventListener(static_cast< document::XEventListener* >(this));
391 uno::Reference< container::XEnumeration > SAL_CALL SfxGlobalEvents_Impl::createEnumeration()
393 // SAFE ->
394 std::scoped_lock g(m_aLock);
395 if (m_disposed) {
396 throw css::lang::DisposedException();
398 uno::Sequence<uno::Any> models(m_lModels.size());
399 auto modelsRange = asNonConstRange(models);
400 for (size_t i = 0; i < m_lModels.size(); ++i)
402 modelsRange[i] <<= m_lModels[i];
404 uno::Reference<container::XEnumeration> xEnum(new ::comphelper::OAnyEnumeration(models));
405 // <- SAFE
407 return xEnum;
411 uno::Type SAL_CALL SfxGlobalEvents_Impl::getElementType()
413 return cppu::UnoType<frame::XModel>::get();
417 sal_Bool SAL_CALL SfxGlobalEvents_Impl::hasElements()
419 // SAFE ->
420 std::scoped_lock g(m_aLock);
421 if (m_disposed) {
422 throw css::lang::DisposedException();
424 return (!m_lModels.empty());
425 // <- SAFE
429 void SfxGlobalEvents_Impl::implts_notifyJobExecution(const document::EventObject& aEvent)
431 css::uno::Reference<css::document::XEventListener> listener;
433 std::scoped_lock g(m_aLock);
434 listener = m_xJobExecutorListener;
436 if (!listener.is()) {
437 return;
441 listener->notifyEvent(aEvent);
443 catch(const uno::RuntimeException&)
444 { throw; }
445 catch(const uno::Exception&)
450 void SfxGlobalEvents_Impl::implts_checkAndExecuteEventBindings(const document::DocumentEvent& aEvent)
452 rtl::Reference<GlobalEventConfig> events;
454 std::scoped_lock g(m_aLock);
455 events = m_xEvents;
457 if (!events.is()) {
458 return;
462 if ( events->hasByName( aEvent.EventName ) )
464 uno::Sequence < beans::PropertyValue > aAny = events->getByName2(aEvent.EventName);
465 SfxEvents_Impl::Execute(aAny, aEvent, nullptr);
468 catch ( uno::RuntimeException const & )
470 throw;
472 catch ( uno::Exception const & )
474 DBG_UNHANDLED_EXCEPTION("sfx.notify");
479 void SfxGlobalEvents_Impl::implts_notifyListener(const document::DocumentEvent& aEvent)
481 std::unique_lock g(m_aLock);
483 document::EventObject aLegacyEvent(aEvent.Source, aEvent.EventName);
484 m_aLegacyListeners.notifyEach(g,
485 &document::XEventListener::notifyEvent, aLegacyEvent,
486 [] { TOOLS_WARN_EXCEPTION("sfx.notify", "ignoring"); });
487 m_aDocumentListeners.notifyEach(g,
488 &document::XDocumentEventListener::documentEventOccured, aEvent,
489 [] { TOOLS_WARN_EXCEPTION("sfx.notify", "ignoring"); });
493 // not threadsafe ... must be locked from outside!
494 TModelList::iterator SfxGlobalEvents_Impl::impl_searchDoc(const uno::Reference< frame::XModel >& xModel)
496 if (!xModel.is())
497 return m_lModels.end();
499 return std::find_if(m_lModels.begin(), m_lModels.end(),
500 [&xModel](const uno::Reference< frame::XModel >& rxModel) {
501 return rxModel == xModel;
505 } // namespace
507 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
508 com_sun_star_comp_sfx2_GlobalEventBroadcaster_get_implementation(
509 css::uno::XComponentContext *context,
510 css::uno::Sequence<css::uno::Any> const &)
512 return cppu::acquire(new SfxGlobalEvents_Impl(context));
515 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */