/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- *//* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */#include <sal/types.h>#include <com/sun/star/task/theJobExecutor.hpp>#include <com/sun/star/container/XNameReplace.hpp>#include <com/sun/star/container/XSet.hpp>#include <com/sun/star/document/XEventListener.hpp>#include <com/sun/star/document/XEventBroadcaster.hpp>#include <com/sun/star/document/XDocumentEventListener.hpp>#include <com/sun/star/frame/XGlobalEventBroadcaster.hpp>#include <com/sun/star/lang/NoSupportException.hpp>#include <com/sun/star/lang/XServiceInfo.hpp>#include <com/sun/star/uno/Type.hxx>#include <cppuhelper/implbase.hxx>#include <comphelper/interfacecontainer2.hxx>#include <cppuhelper/supportsservice.hxx>#include <rtl/ref.hxx>#include <comphelper/enumhelper.hxx>#include <sfx2/app.hxx>#include <sfx2/objsh.hxx>#include <sfx2/sfxbasemodel.hxx>#include <sfx2/evntconf.hxx>#include <tools/diagnose_ex.h>#include <unotools/eventcfg.hxx>#include <eventsupplier.hxx>#include <vector>usingnamespacecss;namespace{structModelCollectionMutexBase{public:osl::Mutexm_aLock;};typedef::std::vector<css::uno::Reference<css::frame::XModel>>TModelList;//TODO: remove support of obsolete document::XEventBroadcaster/ListenerclassSfxGlobalEvents_Impl:publicModelCollectionMutexBase,public::cppu::WeakImplHelper<css::lang::XServiceInfo,css::frame::XGlobalEventBroadcaster,css::document::XEventListener>{css::uno::Reference<css::container::XNameReplace>m_xEvents;css::uno::Reference<css::document::XEventListener>m_xJobExecutorListener;::comphelper::OInterfaceContainerHelper2m_aLegacyListeners;::comphelper::OInterfaceContainerHelper2m_aDocumentListeners;TModelListm_lModels;public:explicitSfxGlobalEvents_Impl(constcss::uno::Reference<css::uno::XComponentContext>&rxContext);virtualOUStringSAL_CALLgetImplementationName()override{returnOUString("com.sun.star.comp.sfx2.GlobalEventBroadcaster");}virtualsal_BoolSAL_CALLsupportsService(OUStringconst&ServiceName)override{returncppu::supportsService(this,ServiceName);}virtualcss::uno::Sequence<OUString>SAL_CALLgetSupportedServiceNames()override{css::uno::Sequence<OUString>aSeq{"com.sun.star.frame.GlobalEventBroadcaster"};returnaSeq;}// css.document.XEventBroadcastervirtualcss::uno::Reference<css::container::XNameReplace>SAL_CALLgetEvents()override;virtualvoidSAL_CALLaddEventListener(constcss::uno::Reference<css::document::XEventListener>&xListener)override;virtualvoidSAL_CALLremoveEventListener(constcss::uno::Reference<css::document::XEventListener>&xListener)override;// css.document.XDocumentEventBroadcastervirtualvoidSAL_CALLaddDocumentEventListener(constcss::uno::Reference<css::document::XDocumentEventListener>&Listener)override;virtualvoidSAL_CALLremoveDocumentEventListener(constcss::uno::Reference<css::document::XDocumentEventListener>&Listener)override;virtualvoidSAL_CALLnotifyDocumentEvent(constOUString&EventName,constcss::uno::Reference<css::frame::XController2>&ViewController,constcss::uno::Any&Supplement)override;// css.document.XEventListenervirtualvoidSAL_CALLnotifyEvent(constcss::document::EventObject&aEvent)override;// css.document.XDocumentEventListenervirtualvoidSAL_CALLdocumentEventOccured(constcss::document::DocumentEvent&Event)override;// css.container.XSetvirtualsal_BoolSAL_CALLhas(constcss::uno::Any&aElement)override;virtualvoidSAL_CALLinsert(constcss::uno::Any&aElement)override;virtualvoidSAL_CALLremove(constcss::uno::Any&aElement)override;// css.container.XEnumerationAccessvirtualcss::uno::Reference<css::container::XEnumeration>SAL_CALLcreateEnumeration()override;// css.container.XElementAccessvirtualcss::uno::TypeSAL_CALLgetElementType()override;virtualsal_BoolSAL_CALLhasElements()override;// css.lang.XEventListenervirtualvoidSAL_CALLdisposing(constcss::lang::EventObject&aEvent)override;private:// threadsafevoidimplts_notifyJobExecution(constcss::document::EventObject&aEvent);voidimplts_checkAndExecuteEventBindings(constcss::document::DocumentEvent&aEvent);voidimplts_notifyListener(constcss::document::DocumentEvent&aEvent);// not threadsafeTModelList::iteratorimpl_searchDoc(constcss::uno::Reference<css::frame::XModel>&xModel);};SfxGlobalEvents_Impl::SfxGlobalEvents_Impl(constuno::Reference<uno::XComponentContext>&rxContext):ModelCollectionMutexBase(),m_xJobExecutorListener(task::theJobExecutor::get(rxContext),uno::UNO_QUERY_THROW),m_aLegacyListeners(m_aLock),m_aDocumentListeners(m_aLock){m_refCount++;SfxApplication::GetOrCreate();m_xEvents=newGlobalEventConfig();m_refCount--;}uno::Reference<container::XNameReplace>SAL_CALLSfxGlobalEvents_Impl::getEvents(){// SAFE ->::osl::ResettableMutexGuardaLock(m_aLock);returnm_xEvents;// <- SAFE}voidSAL_CALLSfxGlobalEvents_Impl::addEventListener(constuno::Reference<document::XEventListener>&xListener){// container is threadsafem_aLegacyListeners.addInterface(xListener);}voidSAL_CALLSfxGlobalEvents_Impl::removeEventListener(constuno::Reference<document::XEventListener>&xListener){// container is threadsafem_aLegacyListeners.removeInterface(xListener);}voidSAL_CALLSfxGlobalEvents_Impl::addDocumentEventListener(constuno::Reference<document::XDocumentEventListener>&Listener){m_aDocumentListeners.addInterface(Listener);}voidSAL_CALLSfxGlobalEvents_Impl::removeDocumentEventListener(constuno::Reference<document::XDocumentEventListener>&Listener){m_aDocumentListeners.removeInterface(Listener);}voidSAL_CALLSfxGlobalEvents_Impl::notifyDocumentEvent(constOUString&/*_EventName*/,constuno::Reference<frame::XController2>&/*_ViewController*/,constuno::Any&/*_Supplement*/){// we're a multiplexer only, no chance to generate artificial events herethrowlang::NoSupportException(OUString(),*this);}voidSAL_CALLSfxGlobalEvents_Impl::notifyEvent(constdocument::EventObject&aEvent){document::DocumentEventaDocEvent(aEvent.Source,aEvent.EventName,nullptr,uno::Any());implts_notifyJobExecution(aEvent);implts_checkAndExecuteEventBindings(aDocEvent);implts_notifyListener(aDocEvent);}voidSAL_CALLSfxGlobalEvents_Impl::documentEventOccured(constdocument::DocumentEvent&Event){implts_notifyJobExecution(document::EventObject(Event.Source,Event.EventName));implts_checkAndExecuteEventBindings(Event);implts_notifyListener(Event);}voidSAL_CALLSfxGlobalEvents_Impl::disposing(constlang::EventObject&aEvent){uno::Reference<frame::XModel>xDoc(aEvent.Source,uno::UNO_QUERY);// SAFE ->::osl::ResettableMutexGuardaLock(m_aLock);TModelList::iteratorpIt=impl_searchDoc(xDoc);if(pIt!=m_lModels.end())m_lModels.erase(pIt);aLock.clear();// <- SAFE}sal_BoolSAL_CALLSfxGlobalEvents_Impl::has(constuno::Any&aElement){uno::Reference<frame::XModel>xDoc;aElement>>=xDoc;boolbHas=false;// SAFE ->::osl::ResettableMutexGuardaLock(m_aLock);TModelList::iteratorpIt=impl_searchDoc(xDoc);if(pIt!=m_lModels.end())bHas=true;aLock.clear();// <- SAFEreturnbHas;}voidSAL_CALLSfxGlobalEvents_Impl::insert(constuno::Any&aElement){uno::Reference<frame::XModel>xDoc;aElement>>=xDoc;if(!xDoc.is())throwlang::IllegalArgumentException("Can not locate at least the model parameter.",static_cast<container::XSet*>(this),0);// SAFE ->::osl::ResettableMutexGuardaLock(m_aLock);TModelList::iteratorpIt=impl_searchDoc(xDoc);if(pIt!=m_lModels.end())throwcontainer::ElementExistException(OUString(),static_cast<container::XSet*>(this));m_lModels.push_back(xDoc);aLock.clear();// <- SAFEuno::Reference<document::XDocumentEventBroadcaster>xDocBroadcaster(xDoc,uno::UNO_QUERY);if(xDocBroadcaster.is())xDocBroadcaster->addDocumentEventListener(this);else{// try the "legacy version" of XDocumentEventBroadcaster, which is XEventBroadcasteruno::Reference<document::XEventBroadcaster>xBroadcaster(xDoc,uno::UNO_QUERY);if(xBroadcaster.is())xBroadcaster->addEventListener(static_cast<document::XEventListener*>(this));}}voidSAL_CALLSfxGlobalEvents_Impl::remove(constuno::Any&aElement){uno::Reference<frame::XModel>xDoc;aElement>>=xDoc;if(!xDoc.is())throwlang::IllegalArgumentException("Can not locate at least the model parameter.",static_cast<container::XSet*>(this),0);// SAFE ->::osl::ResettableMutexGuardaLock(m_aLock);TModelList::iteratorpIt=impl_searchDoc(xDoc);if(pIt==m_lModels.end())throwcontainer::NoSuchElementException(OUString(),static_cast<container::XSet*>(this));m_lModels.erase(pIt);aLock.clear();// <- SAFEuno::Reference<document::XDocumentEventBroadcaster>xDocBroadcaster(xDoc,uno::UNO_QUERY);if(xDocBroadcaster.is())xDocBroadcaster->removeDocumentEventListener(this);else{// try the "legacy version" of XDocumentEventBroadcaster, which is XEventBroadcasteruno::Reference<document::XEventBroadcaster>xBroadcaster(xDoc,uno::UNO_QUERY);if(xBroadcaster.is())xBroadcaster->removeEventListener(static_cast<document::XEventListener*>(this));}}uno::Reference<container::XEnumeration>SAL_CALLSfxGlobalEvents_Impl::createEnumeration(){// SAFE ->::osl::ResettableMutexGuardaLock(m_aLock);uno::Sequence<uno::Any>models(m_lModels.size());for(size_ti=0;i<m_lModels.size();++i){models[i]<<=m_lModels[i];}uno::Reference<container::XEnumeration>xEnum(static_cast<container::XEnumeration*>(new::comphelper::OAnyEnumeration(models)));aLock.clear();// <- SAFEreturnxEnum;}uno::TypeSAL_CALLSfxGlobalEvents_Impl::getElementType(){returncppu::UnoType<frame::XModel>::get();}sal_BoolSAL_CALLSfxGlobalEvents_Impl::hasElements(){// SAFE ->::osl::ResettableMutexGuardaLock(m_aLock);return(!m_lModels.empty());// <- SAFE}voidSfxGlobalEvents_Impl::implts_notifyJobExecution(constdocument::EventObject&aEvent){try{m_xJobExecutorListener->notifyEvent(aEvent);}catch(constuno::RuntimeException&){throw;}catch(constuno::Exception&){}}voidSfxGlobalEvents_Impl::implts_checkAndExecuteEventBindings(constdocument::DocumentEvent&aEvent){try{// SAFE ->::osl::ResettableMutexGuardaLock(m_aLock);uno::Reference<container::XNameReplace>xEvents=m_xEvents;aLock.clear();// <- SAFEuno::AnyaAny;if(xEvents.is()&&xEvents->hasByName(aEvent.EventName))aAny=xEvents->getByName(aEvent.EventName);SfxEvents_Impl::Execute(aAny,aEvent,nullptr);}catch(uno::RuntimeExceptionconst&){throw;}catch(uno::Exceptionconst&){DBG_UNHANDLED_EXCEPTION("sfx.notify");}}voidSfxGlobalEvents_Impl::implts_notifyListener(constdocument::DocumentEvent&aEvent){// containers are threadsafedocument::EventObjectaLegacyEvent(aEvent.Source,aEvent.EventName);m_aLegacyListeners.notifyEach(&document::XEventListener::notifyEvent,aLegacyEvent);m_aDocumentListeners.notifyEach(&document::XDocumentEventListener::documentEventOccured,aEvent);}// not threadsafe ... must be locked from outside!TModelList::iteratorSfxGlobalEvents_Impl::impl_searchDoc(constuno::Reference<frame::XModel>&xModel){if(!xModel.is())returnm_lModels.end();TModelList::iteratorpIt;for(pIt=m_lModels.begin();pIt!=m_lModels.end();++pIt){uno::Reference<frame::XModel>xContainerDoc(*pIt,uno::UNO_QUERY);if(xContainerDoc==xModel)break;}returnpIt;}structInstance{explicitInstance(css::uno::Reference<css::uno::XComponentContext>const&context):instance(static_cast<cppu::OWeakObject*>(newSfxGlobalEvents_Impl(context))){}rtl::Reference<css::uno::XInterface>instance;};structSingleton:publicrtl::StaticWithArg<Instance,css::uno::Reference<css::uno::XComponentContext>,Singleton>{};}extern"C"SAL_DLLPUBLIC_EXPORTcss::uno::XInterface*com_sun_star_comp_sfx2_GlobalEventBroadcaster_get_implementation(<--- The function 'com_sun_star_comp_sfx2_GlobalEventBroadcaster_get_implementation' is never used.css::uno::XComponentContext*context,css::uno::Sequence<css::uno::Any>const&){returncppu::acquire(static_cast<cppu::OWeakObject*>(Singleton::get(context).instance.get()));}/* vim:set shiftwidth=4 softtabstop=4 expandtab: */