LCOV - code coverage report
Current view: top level - framework/source/services - ContextChangeEventMultiplexer.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 83 102 81.4 %
Date: 2015-06-13 12:38:46 Functions: 16 20 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
      20             : #include <com/sun/star/lang/XComponent.hpp>
      21             : #include <com/sun/star/lang/XEventListener.hpp>
      22             : #include <com/sun/star/lang/XServiceInfo.hpp>
      23             : #include <com/sun/star/ui/XContextChangeEventMultiplexer.hpp>
      24             : #include <com/sun/star/uno/XComponentContext.hpp>
      25             : 
      26             : #include <cppuhelper/compbase3.hxx>
      27             : #include <cppuhelper/supportsservice.hxx>
      28             : #include <cppuhelper/basemutex.hxx>
      29             : 
      30             : #include <algorithm>
      31             : #include <map>
      32             : #include <vector>
      33             : #include <boost/noncopyable.hpp>
      34             : 
      35             : namespace cssl = css::lang;
      36             : namespace cssu = css::uno;
      37             : 
      38             : using namespace css;
      39             : using namespace css::uno;
      40             : 
      41             : namespace {
      42             : 
      43             : typedef ::cppu::WeakComponentImplHelper3 <
      44             :     css::ui::XContextChangeEventMultiplexer,
      45             :     css::lang::XServiceInfo,
      46             :     css::lang::XEventListener
      47             :     > ContextChangeEventMultiplexerInterfaceBase;
      48             : 
      49             : class ContextChangeEventMultiplexer
      50             :     : private ::boost::noncopyable,
      51             :       private ::cppu::BaseMutex,
      52             :       public ContextChangeEventMultiplexerInterfaceBase
      53             : {
      54             : public:
      55             :     ContextChangeEventMultiplexer();
      56             :     virtual ~ContextChangeEventMultiplexer();
      57             : 
      58             :     virtual void SAL_CALL disposing() SAL_OVERRIDE;
      59             : 
      60             :     // XContextChangeEventMultiplexer
      61             :     virtual void SAL_CALL addContextChangeEventListener (
      62             :         const cssu::Reference<css::ui::XContextChangeEventListener>& rxListener,
      63             :         const cssu::Reference<cssu::XInterface>& rxEventFocus)
      64             :         throw(cssu::RuntimeException, cssl::IllegalArgumentException, std::exception) SAL_OVERRIDE;
      65             :     virtual void SAL_CALL removeContextChangeEventListener (
      66             :         const cssu::Reference<css::ui::XContextChangeEventListener>& rxListener,
      67             :         const cssu::Reference<cssu::XInterface>& rxEventFocus)
      68             :         throw(cssu::RuntimeException, cssl::IllegalArgumentException, std::exception) SAL_OVERRIDE;
      69             :     virtual void SAL_CALL removeAllContextChangeEventListeners (
      70             :         const cssu::Reference<css::ui::XContextChangeEventListener>& rxListener)
      71             :         throw(cssu::RuntimeException, cssl::IllegalArgumentException, std::exception) SAL_OVERRIDE;
      72             :     virtual void SAL_CALL broadcastContextChangeEvent (
      73             :         const css::ui::ContextChangeEventObject& rContextChangeEventObject,
      74             :         const cssu::Reference<cssu::XInterface>& rxEventFocus)
      75             :         throw(cssu::RuntimeException, std::exception) SAL_OVERRIDE;
      76             : 
      77             :     // XServiceInfo
      78             :     virtual ::rtl::OUString SAL_CALL getImplementationName()
      79             :         throw (cssu::RuntimeException, std::exception) SAL_OVERRIDE;
      80             :     virtual sal_Bool SAL_CALL supportsService  (
      81             :         const ::rtl::OUString& rsServiceName)
      82             :         throw (cssu::RuntimeException, std::exception) SAL_OVERRIDE;
      83             :     virtual cssu::Sequence< ::rtl::OUString> SAL_CALL getSupportedServiceNames()
      84             :         throw (cssu::RuntimeException, std::exception) SAL_OVERRIDE;
      85             : 
      86             :     // XEventListener
      87             :     virtual void SAL_CALL disposing (
      88             :         const css::lang::EventObject& rEvent)
      89             :         throw (cssu::RuntimeException, std::exception) SAL_OVERRIDE;
      90             : 
      91             : private:
      92             :     typedef ::std::vector<cssu::Reference<css::ui::XContextChangeEventListener> > ListenerContainer;
      93       19002 :     class FocusDescriptor
      94             :     {
      95             :     public:
      96             :         ListenerContainer maListeners;
      97             :         ::rtl::OUString msCurrentApplicationName;
      98             :         ::rtl::OUString msCurrentContextName;
      99             :     };
     100             :     typedef ::std::map<cssu::Reference<cssu::XInterface>, FocusDescriptor> ListenerMap;
     101             :     ListenerMap maListeners;
     102             : 
     103             :     /** Notify all listeners in the container that is associated with
     104             :         the given event focus.
     105             : 
     106             :         Typically called twice from broadcastEvent(), once for the
     107             :         given event focus and onece for NULL.
     108             :     */
     109             :     void BroadcastEventToSingleContainer (
     110             :         const css::ui::ContextChangeEventObject& rEventObject,
     111             :         const cssu::Reference<cssu::XInterface>& rxEventFocus);
     112             :     FocusDescriptor* GetFocusDescriptor (
     113             :         const cssu::Reference<cssu::XInterface>& rxEventFocus,
     114             :         const bool bCreateWhenMissing);
     115             : };
     116             : 
     117          98 : ContextChangeEventMultiplexer::ContextChangeEventMultiplexer()
     118             :     : ContextChangeEventMultiplexerInterfaceBase(m_aMutex),
     119          98 :       maListeners()
     120             : {
     121          98 : }
     122             : 
     123         196 : ContextChangeEventMultiplexer::~ContextChangeEventMultiplexer()
     124             : {
     125         196 : }
     126             : 
     127          98 : void SAL_CALL ContextChangeEventMultiplexer::disposing()
     128             : {
     129          98 :     ListenerMap aListeners;
     130          98 :     aListeners.swap(maListeners);
     131             : 
     132         196 :     cssu::Reference<cssu::XInterface> xThis (static_cast<XWeak*>(this));
     133         196 :     css::lang::EventObject aEvent (xThis);
     134         103 :     for (ListenerMap::const_iterator iContainer(aListeners.begin()), iEnd(aListeners.end());
     135             :          iContainer!=iEnd;
     136             :          ++iContainer)
     137             :     {
     138             :         // Unregister from the focus object.
     139           5 :         Reference<lang::XComponent> xComponent (iContainer->first, UNO_QUERY);
     140           5 :         if (xComponent.is())
     141           5 :             xComponent->removeEventListener(this);
     142             : 
     143             :         // Tell all listeners that we are being disposed.
     144           5 :         const FocusDescriptor& rFocusDescriptor (iContainer->second);
     145          10 :         for (ListenerContainer::const_iterator
     146           5 :                  iListener(rFocusDescriptor.maListeners.begin()),
     147           5 :                  iContainerEnd(rFocusDescriptor.maListeners.end());
     148             :              iListener!=iContainerEnd;
     149             :              ++iListener)
     150             :         {
     151           5 :             (*iListener)->disposing(aEvent);
     152             :         }
     153         103 :     }
     154          98 : }
     155             : 
     156             : // XContextChangeEventMultiplexer
     157        7403 : void SAL_CALL ContextChangeEventMultiplexer::addContextChangeEventListener (
     158             :     const cssu::Reference<css::ui::XContextChangeEventListener>& rxListener,
     159             :     const cssu::Reference<cssu::XInterface>& rxEventFocus)
     160             :     throw(cssu::RuntimeException,cssl::IllegalArgumentException, std::exception)
     161             : {
     162        7403 :     if ( ! rxListener.is())
     163             :         throw css::lang::IllegalArgumentException(
     164             :             "can not add an empty reference",
     165             :             static_cast<XWeak*>(this),
     166           0 :             0);
     167             : 
     168        7403 :     FocusDescriptor* pFocusDescriptor = GetFocusDescriptor(rxEventFocus, true);
     169        7403 :     if (pFocusDescriptor != NULL)
     170             :     {
     171        7403 :         ListenerContainer& rContainer (pFocusDescriptor->maListeners);
     172        7403 :         if (::std::find(rContainer.begin(), rContainer.end(), rxListener) == rContainer.end())
     173        7403 :             rContainer.push_back(rxListener);
     174             :         else
     175             :         {
     176             :             // The listener was added for the same event focus
     177             :             // previously.  That is an error.
     178           0 :             throw cssl::IllegalArgumentException("listener added twice", static_cast<XWeak*>(this), 0);
     179             :         }
     180             :     }
     181             : 
     182             :     // Send out an initial event that informs the new listener about
     183             :     // the current context.
     184        7403 :     if (rxEventFocus.is() && pFocusDescriptor!=NULL)
     185             :     {
     186             :         css::ui::ContextChangeEventObject aEvent (
     187             :             NULL,
     188             :             pFocusDescriptor->msCurrentApplicationName,
     189        7403 :             pFocusDescriptor->msCurrentContextName);
     190        7403 :         rxListener->notifyContextChangeEvent(aEvent);
     191             :     }
     192        7403 : }
     193             : 
     194           0 : void SAL_CALL ContextChangeEventMultiplexer::removeContextChangeEventListener (
     195             :     const cssu::Reference<css::ui::XContextChangeEventListener>& rxListener,
     196             :     const cssu::Reference<cssu::XInterface>& rxEventFocus)
     197             :     throw(cssu::RuntimeException,cssl::IllegalArgumentException, std::exception)
     198             : {
     199           0 :     if ( ! rxListener.is())
     200             :         throw cssl::IllegalArgumentException(
     201             :             "can not remove an empty reference",
     202           0 :             static_cast<XWeak*>(this), 0);
     203             : 
     204           0 :     FocusDescriptor* pFocusDescriptor = GetFocusDescriptor(rxEventFocus, false);
     205           0 :     if (pFocusDescriptor != NULL)
     206             :     {
     207           0 :         ListenerContainer& rContainer (pFocusDescriptor->maListeners);
     208             :         const ListenerContainer::iterator iListener (
     209           0 :             ::std::find(rContainer.begin(), rContainer.end(), rxListener));
     210           0 :         if (iListener != rContainer.end())
     211             :         {
     212           0 :             rContainer.erase(iListener);
     213             : 
     214             :             // We hold on to the focus descriptor even when the last listener has been removed.
     215             :             // This allows us to keep track of the current context and send it to new listeners.
     216             :         }
     217             :     }
     218             : 
     219           0 : }
     220             : 
     221        7403 : void SAL_CALL ContextChangeEventMultiplexer::removeAllContextChangeEventListeners (
     222             :     const cssu::Reference<css::ui::XContextChangeEventListener>& rxListener)
     223             :     throw(cssu::RuntimeException,cssl::IllegalArgumentException, std::exception)
     224             : {
     225        7403 :     if ( ! rxListener.is())
     226             :         throw cssl::IllegalArgumentException(
     227             :             "can not remove an empty reference",
     228           0 :             static_cast<XWeak*>(this), 0);
     229             : 
     230        8364 :     for (ListenerMap::iterator
     231        7403 :              iContainer(maListeners.begin()),
     232        7403 :              iEnd(maListeners.end());
     233             :          iContainer!=iEnd;
     234             :          ++iContainer)
     235             :     {
     236             :         const ListenerContainer::iterator iListener (
     237         961 :             ::std::find(iContainer->second.maListeners.begin(), iContainer->second.maListeners.end(), rxListener));
     238         961 :         if (iListener != iContainer->second.maListeners.end())
     239             :         {
     240         525 :             iContainer->second.maListeners.erase(iListener);
     241             : 
     242             :             // We hold on to the focus descriptor even when the last listener has been removed.
     243             :             // This allows us to keep track of the current context and send it to new listeners.
     244             :         }
     245             :     }
     246        7403 : }
     247             : 
     248        4197 : void SAL_CALL ContextChangeEventMultiplexer::broadcastContextChangeEvent (
     249             :     const css::ui::ContextChangeEventObject& rEventObject,
     250             :     const cssu::Reference<cssu::XInterface>& rxEventFocus)
     251             :     throw(cssu::RuntimeException, std::exception)
     252             : {
     253             :     // Remember the current context.
     254        4197 :     if (rxEventFocus.is())
     255             :     {
     256        4197 :         FocusDescriptor* pFocusDescriptor = GetFocusDescriptor(rxEventFocus, true);
     257        4197 :         if (pFocusDescriptor != NULL)
     258             :         {
     259        4197 :             pFocusDescriptor->msCurrentApplicationName = rEventObject.ApplicationName;
     260        4197 :             pFocusDescriptor->msCurrentContextName = rEventObject.ContextName;
     261             :         }
     262             :     }
     263             : 
     264        4197 :     BroadcastEventToSingleContainer(rEventObject, rxEventFocus);
     265        4197 :     if (rxEventFocus.is())
     266        4197 :         BroadcastEventToSingleContainer(rEventObject, NULL);
     267        4197 : }
     268             : 
     269        8394 : void ContextChangeEventMultiplexer::BroadcastEventToSingleContainer (
     270             :     const css::ui::ContextChangeEventObject& rEventObject,
     271             :     const cssu::Reference<cssu::XInterface>& rxEventFocus)
     272             : {
     273        8394 :     FocusDescriptor* pFocusDescriptor = GetFocusDescriptor(rxEventFocus, false);
     274        8394 :     if (pFocusDescriptor != NULL)
     275             :     {
     276             :         // Create a copy of the listener container to avoid problems
     277             :         // when one of the called listeners calls add... or remove...
     278        4197 :         ListenerContainer aContainer (pFocusDescriptor->maListeners);
     279       11844 :         for (ListenerContainer::const_iterator
     280        4197 :                  iListener(aContainer.begin()),
     281        4197 :                  iEnd(aContainer.end());
     282             :              iListener!=iEnd;
     283             :              ++iListener)
     284             :         {
     285        7647 :             (*iListener)->notifyContextChangeEvent(rEventObject);
     286        4197 :         }
     287             :     }
     288        8394 : }
     289             : 
     290       19994 : ContextChangeEventMultiplexer::FocusDescriptor* ContextChangeEventMultiplexer::GetFocusDescriptor (
     291             :     const cssu::Reference<cssu::XInterface>& rxEventFocus,
     292             :     const bool bCreateWhenMissing)
     293             : {
     294       19994 :     ListenerMap::iterator iDescriptor (maListeners.find(rxEventFocus));
     295       19994 :     if (iDescriptor == maListeners.end() && bCreateWhenMissing)
     296             :     {
     297             :         // Listen for the focus being disposed.
     298        3167 :         Reference<lang::XComponent> xComponent (rxEventFocus, UNO_QUERY);
     299        3167 :         if (xComponent.is())
     300        3167 :             xComponent->addEventListener(this);
     301             : 
     302             :         // Create a new listener container for the event focus.
     303             :         iDescriptor = maListeners.insert(
     304             :             ListenerMap::value_type(
     305             :                 rxEventFocus,
     306        3167 :                 FocusDescriptor())).first;
     307             :     }
     308       19994 :     if (iDescriptor != maListeners.end())
     309       15797 :         return &iDescriptor->second;
     310             :     else
     311        4197 :         return NULL;
     312             : }
     313             : 
     314           0 : OUString SAL_CALL ContextChangeEventMultiplexer::getImplementationName()
     315             :     throw(cssu::RuntimeException, std::exception)
     316             : {
     317           0 :     return OUString("org.apache.openoffice.comp.framework.ContextChangeEventMultiplexer");
     318             : }
     319             : 
     320           0 : sal_Bool SAL_CALL ContextChangeEventMultiplexer::supportsService ( const ::rtl::OUString& rsServiceName)
     321             :     throw (cssu::RuntimeException, std::exception)
     322             : {
     323           0 :     return cppu::supportsService(this, rsServiceName);
     324             : }
     325             : 
     326           0 : css::uno::Sequence<OUString> SAL_CALL ContextChangeEventMultiplexer::getSupportedServiceNames()
     327             :     throw (cssu::RuntimeException, std::exception)
     328             : {
     329             :     // it's a singleton, not a service
     330           0 :     return css::uno::Sequence<OUString>();
     331             : }
     332             : 
     333        3162 : void SAL_CALL ContextChangeEventMultiplexer::disposing ( const css::lang::EventObject& rEvent)
     334             :     throw (cssu::RuntimeException, std::exception)
     335             : {
     336        3162 :     ListenerMap::iterator iDescriptor (maListeners.find(rEvent.Source));
     337             : 
     338        3162 :     if (iDescriptor == maListeners.end())
     339             :     {
     340             :         OSL_ASSERT(iDescriptor != maListeners.end());
     341        3162 :         return;
     342             :     }
     343             : 
     344             :     // Should we notify the remaining listeners?
     345             : 
     346        3162 :     maListeners.erase(iDescriptor);
     347             : }
     348             : 
     349          98 : struct Instance {
     350          98 :     explicit Instance():
     351             :         instance(static_cast<cppu::OWeakObject *>(
     352          98 :                     new ContextChangeEventMultiplexer()))
     353             :     {
     354          98 :     }
     355             : 
     356             :     css::uno::Reference<css::uno::XInterface> instance;
     357             : };
     358             : 
     359             : struct Singleton:
     360             :     public rtl::Static<Instance, Singleton>
     361             : {};
     362             : 
     363             : }
     364             : 
     365             : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
     366          98 : org_apache_openoffice_comp_framework_ContextChangeEventMultiplexer_get_implementation(
     367             :     css::uno::XComponentContext *,
     368             :     css::uno::Sequence<css::uno::Any> const &)
     369             : {
     370             :     return cppu::acquire(static_cast<cppu::OWeakObject *>(
     371          98 :                 Singleton::get().instance.get()));
     372             : }
     373             : 
     374             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11