/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; const char cURLFormLetter[] = ".uno:DataSourceBrowser/FormLetter"; const char cURLInsertContent[] = ".uno:DataSourceBrowser/InsertContent";//data into fields const char cURLInsertColumns[] = ".uno:DataSourceBrowser/InsertColumns";//data into text const char cURLDocumentDataSource[] = ".uno:DataSourceBrowser/DocumentDataSource";//current data source of the document const char cInternalDBChangeNotification[] = ".uno::Writer/DataSourceChanged"; SwXDispatchProviderInterceptor::SwXDispatchProviderInterceptor(SwView& rVw) : m_pView(&rVw) { uno::Reference< frame::XFrame> xUnoFrame = m_pView->GetViewFrame().GetFrame().GetFrameInterface(); m_xIntercepted.set(xUnoFrame, uno::UNO_QUERY); if(m_xIntercepted.is()) { osl_atomic_increment(&m_refCount); m_xIntercepted->registerDispatchProviderInterceptor(static_cast(this)); // this should make us the top-level dispatch-provider for the component, via a call to our // setDispatchProvider we should have got a fallback for requests we (i.e. our master) cannot fulfill uno::Reference< lang::XComponent> xInterceptedComponent(m_xIntercepted, uno::UNO_QUERY); if (xInterceptedComponent.is()) xInterceptedComponent->addEventListener(static_cast(this)); osl_atomic_decrement(&m_refCount); } } SwXDispatchProviderInterceptor::~SwXDispatchProviderInterceptor() { } uno::Reference< frame::XDispatch > SwXDispatchProviderInterceptor::queryDispatch( const util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags ) { DispatchMutexLock_Impl aLock; uno::Reference< frame::XDispatch> xResult; // create some dispatch ... if(m_pView && aURL.Complete.startsWith(".uno:DataSourceBrowser/")) { if(aURL.Complete == cURLFormLetter || aURL.Complete == cURLInsertContent || aURL.Complete == cURLInsertColumns || aURL.Complete == cURLDocumentDataSource) { if(!m_xDispatch.is()) m_xDispatch = new SwXDispatch(*m_pView); xResult = m_xDispatch; } } // ask our slave provider if (!xResult.is() && m_xSlaveDispatcher.is()) xResult = m_xSlaveDispatcher->queryDispatch(aURL, aTargetFrameName, nSearchFlags); return xResult; } uno::Sequence SAL_CALL SwXDispatchProviderInterceptor::getInterceptedURLs() { uno::Sequence aRet = { u".uno:DataSourceBrowser/*"_ustr }; return aRet; } uno::Sequence< uno::Reference< frame::XDispatch > > SwXDispatchProviderInterceptor::queryDispatches( const uno::Sequence< frame::DispatchDescriptor >& aDescripts ) { DispatchMutexLock_Impl aLock; uno::Sequence< uno::Reference< frame::XDispatch> > aReturn(aDescripts.getLength()); std::transform(aDescripts.begin(), aDescripts.end(), aReturn.getArray(), [this](const frame::DispatchDescriptor& rDescr) -> uno::Reference { return queryDispatch(rDescr.FeatureURL, rDescr.FrameName, rDescr.SearchFlags); }); return aReturn; } uno::Reference< frame::XDispatchProvider > SwXDispatchProviderInterceptor::getSlaveDispatchProvider( ) { DispatchMutexLock_Impl aLock; return m_xSlaveDispatcher; } void SwXDispatchProviderInterceptor::setSlaveDispatchProvider( const uno::Reference< frame::XDispatchProvider >& xNewDispatchProvider ) { DispatchMutexLock_Impl aLock; m_xSlaveDispatcher = xNewDispatchProvider; } uno::Reference< frame::XDispatchProvider > SwXDispatchProviderInterceptor::getMasterDispatchProvider( ) { DispatchMutexLock_Impl aLock; return m_xMasterDispatcher; } void SwXDispatchProviderInterceptor::setMasterDispatchProvider( const uno::Reference< frame::XDispatchProvider >& xNewSupplier ) { DispatchMutexLock_Impl aLock; m_xMasterDispatcher = xNewSupplier; } void SwXDispatchProviderInterceptor::disposing( const lang::EventObject& ) { DispatchMutexLock_Impl aLock; if (m_xIntercepted.is()) { m_xIntercepted->releaseDispatchProviderInterceptor(static_cast(this)); uno::Reference< lang::XComponent> xInterceptedComponent(m_xIntercepted, uno::UNO_QUERY); if (xInterceptedComponent.is()) xInterceptedComponent->removeEventListener(static_cast(this)); m_xDispatch = nullptr; } m_xIntercepted = nullptr; } void SwXDispatchProviderInterceptor::Invalidate() { DispatchMutexLock_Impl aLock; if (m_xIntercepted.is()) { m_xIntercepted->releaseDispatchProviderInterceptor(static_cast(this)); uno::Reference< lang::XComponent> xInterceptedComponent(m_xIntercepted, uno::UNO_QUERY); if (xInterceptedComponent.is()) xInterceptedComponent->removeEventListener(static_cast(this)); m_xDispatch = nullptr; } m_xIntercepted = nullptr; m_pView = nullptr; } SwXDispatch::SwXDispatch(SwView& rVw) : m_pView(&rVw), m_bOldEnable(false), m_bListenerAdded(false) { } SwXDispatch::~SwXDispatch() { if(m_bListenerAdded && m_pView) { uno::Reference xSupplier = m_pView->GetUNOObject(); uno::Reference xThis = this; xSupplier->removeSelectionChangeListener(xThis); } } void SwXDispatch::dispatch(const util::URL& aURL, const uno::Sequence< beans::PropertyValue >& aArgs) { if(!m_pView) throw uno::RuntimeException(); #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS (void) aArgs; if (false) { } #else SwWrtShell& rSh = m_pView->GetWrtShell(); SwDBManager* pDBManager = rSh.GetDBManager(); if(aURL.Complete == cURLInsertContent) { svx::ODataAccessDescriptor aDescriptor(aArgs); SwMergeDescriptor aMergeDesc( DBMGR_MERGE, rSh, aDescriptor ); pDBManager->Merge(aMergeDesc); } else if(aURL.Complete == cURLInsertColumns) { SwDBManager::InsertText(rSh, aArgs); } else if(aURL.Complete == cURLFormLetter) { SfxUnoAnyItem aDBProperties(FN_PARAM_DATABASE_PROPERTIES, uno::Any(aArgs)); m_pView->GetViewFrame().GetDispatcher()->ExecuteList( FN_MAILMERGE_WIZARD, SfxCallMode::ASYNCHRON, { &aDBProperties }); } #endif else if(aURL.Complete == cURLDocumentDataSource) { OSL_FAIL("SwXDispatch::dispatch: this URL is not to be dispatched!"); } else if(aURL.Complete == cInternalDBChangeNotification) { frame::FeatureStateEvent aEvent; aEvent.Source = getXWeak(); const SwDBData& rData = m_pView->GetWrtShell().GetDBData(); svx::ODataAccessDescriptor aDescriptor; aDescriptor.setDataSource(rData.sDataSource); aDescriptor[svx::DataAccessDescriptorProperty::Command] <<= rData.sCommand; aDescriptor[svx::DataAccessDescriptorProperty::CommandType] <<= rData.nCommandType; aEvent.State <<= aDescriptor.createPropertyValueSequence(); aEvent.IsEnabled = !rData.sDataSource.isEmpty(); // calls to statusChanged may call addStatusListener or removeStatusListener // so copy m_aStatusListenerVector on stack auto copyStatusListenerVector = m_aStatusListenerVector; for (auto & status : copyStatusListenerVector) { if(status.aURL.Complete == cURLDocumentDataSource) { aEvent.FeatureURL = status.aURL; status.xListener->statusChanged( aEvent ); } } } else throw uno::RuntimeException(); } void SwXDispatch::addStatusListener( const uno::Reference< frame::XStatusListener >& xControl, const util::URL& aURL ) { if(!m_pView) throw uno::RuntimeException(); ShellMode eMode = m_pView->GetShellMode(); bool bEnable = ShellMode::Text == eMode || ShellMode::ListText == eMode || ShellMode::TableText == eMode || ShellMode::TableListText == eMode; m_bOldEnable = bEnable; frame::FeatureStateEvent aEvent; aEvent.IsEnabled = bEnable; aEvent.Source = getXWeak(); aEvent.FeatureURL = aURL; // one of the URLs requires a special state... if (aURL.Complete == cURLDocumentDataSource) { const SwDBData& rData = m_pView->GetWrtShell().GetDBData(); svx::ODataAccessDescriptor aDescriptor; aDescriptor.setDataSource(rData.sDataSource); aDescriptor[svx::DataAccessDescriptorProperty::Command] <<= rData.sCommand; aDescriptor[svx::DataAccessDescriptorProperty::CommandType] <<= rData.nCommandType; aEvent.State <<= aDescriptor.createPropertyValueSequence(); aEvent.IsEnabled = !rData.sDataSource.isEmpty(); } xControl->statusChanged( aEvent ); StatusStruct_Impl aStatus; aStatus.xListener = xControl; aStatus.aURL = aURL; m_aStatusListenerVector.emplace_back(aStatus); if(!m_bListenerAdded) { uno::Reference xSupplier = m_pView->GetUNOObject(); uno::Reference xThis = this; xSupplier->addSelectionChangeListener(xThis); m_bListenerAdded = true; } } void SwXDispatch::removeStatusListener( const uno::Reference< frame::XStatusListener >& xControl, const util::URL& ) { std::erase_if( m_aStatusListenerVector, [&](const StatusStruct_Impl& status) { return status.xListener.get() == xControl.get(); }); if(m_aStatusListenerVector.empty() && m_pView) { uno::Reference xSupplier = m_pView->GetUNOObject(); uno::Reference xThis = this; xSupplier->removeSelectionChangeListener(xThis); m_bListenerAdded = false; } } void SwXDispatch::selectionChanged( const lang::EventObject& ) { ShellMode eMode = m_pView->GetShellMode(); bool bEnable = ShellMode::Text == eMode || ShellMode::ListText == eMode || ShellMode::TableText == eMode || ShellMode::TableListText == eMode; if(bEnable == m_bOldEnable) return; m_bOldEnable = bEnable; frame::FeatureStateEvent aEvent; aEvent.IsEnabled = bEnable; aEvent.Source = getXWeak(); // calls to statusChanged may call addStatusListener or removeStatusListener // so copy m_aStatusListenerVector on stack auto copyStatusListenerVector = m_aStatusListenerVector; for (auto & status : copyStatusListenerVector) { aEvent.FeatureURL = status.aURL; if (status.aURL.Complete != cURLDocumentDataSource) // the document's data source does not depend on the selection, so it's state does not change here status.xListener->statusChanged( aEvent ); } } void SwXDispatch::disposing( const lang::EventObject& rSource ) { uno::Reference xSupplier(rSource.Source, uno::UNO_QUERY); uno::Reference xThis = this; xSupplier->removeSelectionChangeListener(xThis); m_bListenerAdded = false; lang::EventObject aObject; aObject.Source = getXWeak(); // calls to statusChanged may call addStatusListener or removeStatusListener // so copy m_aStatusListenerVector on stack auto copyStatusListenerVector = m_aStatusListenerVector; for (auto & status : copyStatusListenerVector) { status.xListener->disposing(aObject); } m_pView = nullptr; } const char* SwXDispatch::GetDBChangeURL() { return cInternalDBChangeNotification; } SwXDispatchProviderInterceptor::DispatchMutexLock_Impl::DispatchMutexLock_Impl() { } SwXDispatchProviderInterceptor::DispatchMutexLock_Impl::~DispatchMutexLock_Impl() { } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */