/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include "precompiled_framework.hxx" #include "services/ContextChangeEventMultiplexer.hxx" #include "services.h" using ::rtl::OUString; #define A2S(s) ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) using namespace css; using namespace cssu; namespace framework { #define IMPLEMENTATION_NAME "org.apache.openoffice.comp.framework.ContextChangeEventMultiplexer" #define SERVICE_NAME "com.sun.star.ui.ContextChangeEventMultiplexer" #define SINGLETON_NAME "org.apache.openoffice.comp.framework.ContextChangeEventMultiplexerSigleton" ContextChangeEventMultiplexer::ContextChangeEventMultiplexer ( const cssu::Reference& rxContext) : ContextChangeEventMultiplexerInterfaceBase(m_aMutex), maListeners() { (void)rxContext; } ContextChangeEventMultiplexer::~ContextChangeEventMultiplexer (void) { } void SAL_CALL ContextChangeEventMultiplexer::disposing (void) { ListenerMap aListeners; aListeners.swap(maListeners); cssu::Reference xThis (static_cast(this)); css::lang::EventObject aEvent (xThis); for (ListenerMap::const_iterator iContainer(aListeners.begin()), iEnd(aListeners.end()); iContainer!=iEnd; ++iContainer) { // Unregister from the focus object. Reference xComponent (iContainer->first, UNO_QUERY); if (xComponent.is()) xComponent->removeEventListener(this); // Tell all listeners that we are being disposed. const FocusDescriptor& rFocusDescriptor (iContainer->second); for (ListenerContainer::const_iterator iListener(rFocusDescriptor.maListeners.begin()), iContainerEnd(rFocusDescriptor.maListeners.end()); iListener!=iContainerEnd; ++iListener) { (*iListener)->disposing(aEvent); } } } // XContextChangeEventMultiplexer void SAL_CALL ContextChangeEventMultiplexer::addContextChangeEventListener ( const cssu::Reference& rxListener, const cssu::Reference& rxEventFocus) throw(cssu::RuntimeException,cssl::IllegalArgumentException) { if ( ! rxListener.is()) throw css::lang::IllegalArgumentException( A2S("can not add an empty reference"), static_cast(this), 0); FocusDescriptor* pFocusDescriptor = GetFocusDescriptor(rxEventFocus, true); if (pFocusDescriptor != NULL) { ListenerContainer& rContainer (pFocusDescriptor->maListeners); if (::std::find(rContainer.begin(), rContainer.end(), rxListener) == rContainer.end()) rContainer.push_back(rxListener); else { // The listener was added for the same event focus // previously. That is an error. throw cssl::IllegalArgumentException(A2S("listener added twice"), static_cast(this), 0); } } // Send out an initial event that informs the new listener about // the current context. if (rxEventFocus.is() && pFocusDescriptor!=NULL) { css::ui::ContextChangeEventObject aEvent ( NULL, pFocusDescriptor->msCurrentApplicationName, pFocusDescriptor->msCurrentContextName); rxListener->notifyContextChangeEvent(aEvent); } } void SAL_CALL ContextChangeEventMultiplexer::removeContextChangeEventListener ( const cssu::Reference& rxListener, const cssu::Reference& rxEventFocus) throw(cssu::RuntimeException,cssl::IllegalArgumentException) { if ( ! rxListener.is()) throw cssl::IllegalArgumentException( A2S("can not remove an empty reference"), static_cast(this), 0); FocusDescriptor* pFocusDescriptor = GetFocusDescriptor(rxEventFocus, false); if (pFocusDescriptor != NULL) { ListenerContainer& rContainer (pFocusDescriptor->maListeners); const ListenerContainer::iterator iListener ( ::std::find(rContainer.begin(), rContainer.end(), rxListener)); if (iListener != rContainer.end()) { rContainer.erase(iListener); // We hold on to the focus descriptor even when the last listener has been removed. // This allows us to keep track of the current context and send it to new listeners. } } } void SAL_CALL ContextChangeEventMultiplexer::removeAllContextChangeEventListeners ( const cssu::Reference& rxListener) throw(cssu::RuntimeException,cssl::IllegalArgumentException) { if ( ! rxListener.is()) throw cssl::IllegalArgumentException( A2S("can not remove an empty reference"), static_cast(this), 0); for (ListenerMap::iterator iContainer(maListeners.begin()), iEnd(maListeners.end()); iContainer!=iEnd; ++iContainer) { const ListenerContainer::iterator iListener ( ::std::find(iContainer->second.maListeners.begin(), iContainer->second.maListeners.end(), rxListener)); if (iListener != iContainer->second.maListeners.end()) { iContainer->second.maListeners.erase(iListener); // We hold on to the focus descriptor even when the last listener has been removed. // This allows us to keep track of the current context and send it to new listeners. } } } void SAL_CALL ContextChangeEventMultiplexer::broadcastContextChangeEvent ( const css::ui::ContextChangeEventObject& rEventObject, const cssu::Reference& rxEventFocus) throw(cssu::RuntimeException) { // Remember the current context. if (rxEventFocus.is()) { FocusDescriptor* pFocusDescriptor = GetFocusDescriptor(rxEventFocus, true); if (pFocusDescriptor != NULL) { pFocusDescriptor->msCurrentApplicationName = rEventObject.ApplicationName; pFocusDescriptor->msCurrentContextName = rEventObject.ContextName; } } BroadcastEventToSingleContainer(rEventObject, rxEventFocus); if (rxEventFocus.is()) BroadcastEventToSingleContainer(rEventObject, NULL); } void ContextChangeEventMultiplexer::BroadcastEventToSingleContainer ( const css::ui::ContextChangeEventObject& rEventObject, const cssu::Reference& rxEventFocus) { FocusDescriptor* pFocusDescriptor = GetFocusDescriptor(rxEventFocus, false); if (pFocusDescriptor != NULL) { // Create a copy of the listener container to avoid problems // when one of the called listeners calls add... or remove... ListenerContainer aContainer (pFocusDescriptor->maListeners); for (ListenerContainer::const_iterator iListener(aContainer.begin()), iEnd(aContainer.end()); iListener!=iEnd; ++iListener) { (*iListener)->notifyContextChangeEvent(rEventObject); } } } ContextChangeEventMultiplexer::FocusDescriptor* ContextChangeEventMultiplexer::GetFocusDescriptor ( const cssu::Reference& rxEventFocus, const bool bCreateWhenMissing) { ListenerMap::iterator iDescriptor (maListeners.find(rxEventFocus)); if (iDescriptor == maListeners.end() && bCreateWhenMissing) { // Listen for the focus being disposed. Reference xComponent (rxEventFocus, UNO_QUERY); if (xComponent.is()) xComponent->addEventListener(this); // Create a new listener container for the event focus. iDescriptor = maListeners.insert( ListenerMap::value_type( rxEventFocus, FocusDescriptor())).first; } if (iDescriptor != maListeners.end()) return &iDescriptor->second; else return NULL; } // XSingleComponentFactory cssu::Reference SAL_CALL ContextChangeEventMultiplexer::createInstanceWithContext ( const cssu::Reference& rxContext) throw (cssu::Exception, cssu::RuntimeException) { (void)rxContext; return cssu::Reference(); } cssu::Reference SAL_CALL ContextChangeEventMultiplexer::createInstanceWithArgumentsAndContext ( const cssu::Sequence& rArguments, const cssu::Reference& rxContext) throw (cssu::Exception, cssu::RuntimeException) { (void)rArguments; (void)rxContext; return cssu::Reference(); } // XServiceInfo ::rtl::OUString SAL_CALL ContextChangeEventMultiplexer::getImplementationName (void) throw(cssu::RuntimeException) { return impl_getStaticImplementationName(); } sal_Bool SAL_CALL ContextChangeEventMultiplexer::supportsService ( const ::rtl::OUString& rsServiceName) throw (cssu::RuntimeException) { return ::comphelper::findValue(static_GetSupportedServiceNames(), rsServiceName, sal_True).getLength() != 0; } cssu::Sequence SAL_CALL ContextChangeEventMultiplexer::getSupportedServiceNames (void) throw (cssu::RuntimeException) { return static_GetSupportedServiceNames(); } void SAL_CALL ContextChangeEventMultiplexer::disposing ( const css::lang::EventObject& rEvent) throw (cssu::RuntimeException) { ListenerMap::iterator iDescriptor (maListeners.find(rEvent.Source)); if (iDescriptor == maListeners.end()) { OSL_ASSERT(iDescriptor != maListeners.end()); return; } // Should we notify the remaining listeners? maListeners.erase(iDescriptor); } // Local and static methods. OUString SAL_CALL ContextChangeEventMultiplexer::impl_getStaticImplementationName (void) { return A2S(IMPLEMENTATION_NAME); } cssu::Sequence SAL_CALL ContextChangeEventMultiplexer::static_GetSupportedServiceNames (void) { cssu::Sequence aServiceNames (2); aServiceNames[0] = A2S(SERVICE_NAME); aServiceNames[1] = A2S(SINGLETON_NAME); return aServiceNames; } cssu::Reference ContextChangeEventMultiplexer::impl_createFactory ( const cssu::Reference& rxServiceManager) { (void)rxServiceManager; return cppu::createSingleComponentFactory( ContextChangeEventMultiplexer::static_CreateInstance, ContextChangeEventMultiplexer::impl_getStaticImplementationName(), ContextChangeEventMultiplexer::static_GetSupportedServiceNames() ); } cssu::Reference SAL_CALL ContextChangeEventMultiplexer::static_CreateInstance ( const cssu::Reference& rxComponentContext) throw (cssu::Exception) { ContextChangeEventMultiplexer* pObject = new ContextChangeEventMultiplexer(rxComponentContext); cssu::Reference xService (static_cast(pObject), cssu::UNO_QUERY); return xService; } } // end of namespace framework