1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <config_features.h>
21 #include <config_fuzzers.h>
23 #include <com/sun/star/frame/XFrame.hpp>
24 #include <com/sun/star/view/XSelectionSupplier.hpp>
26 #include <sfx2/viewfrm.hxx>
27 #include <sfx2/dispatch.hxx>
28 #include <svx/dataaccessdescriptor.hxx>
29 #include <comphelper/servicehelper.hxx>
30 #include <osl/diagnose.h>
31 #include <unodispatch.hxx>
37 using namespace ::com::sun::star
;
39 const char cURLFormLetter
[] = ".uno:DataSourceBrowser/FormLetter";
40 const char cURLInsertContent
[] = ".uno:DataSourceBrowser/InsertContent";//data into fields
41 const char cURLInsertColumns
[] = ".uno:DataSourceBrowser/InsertColumns";//data into text
42 const char cURLDocumentDataSource
[] = ".uno:DataSourceBrowser/DocumentDataSource";//current data source of the document
43 const char cInternalDBChangeNotification
[] = ".uno::Writer/DataSourceChanged";
45 SwXDispatchProviderInterceptor::SwXDispatchProviderInterceptor(SwView
& rVw
) :
48 uno::Reference
< frame::XFrame
> xUnoFrame
= m_pView
->GetViewFrame().GetFrame().GetFrameInterface();
49 m_xIntercepted
.set(xUnoFrame
, uno::UNO_QUERY
);
50 if(m_xIntercepted
.is())
52 osl_atomic_increment(&m_refCount
);
53 m_xIntercepted
->registerDispatchProviderInterceptor(static_cast<frame::XDispatchProviderInterceptor
*>(this));
54 // this should make us the top-level dispatch-provider for the component, via a call to our
55 // setDispatchProvider we should have got a fallback for requests we (i.e. our master) cannot fulfill
56 uno::Reference
< lang::XComponent
> xInterceptedComponent(m_xIntercepted
, uno::UNO_QUERY
);
57 if (xInterceptedComponent
.is())
58 xInterceptedComponent
->addEventListener(static_cast<lang::XEventListener
*>(this));
59 osl_atomic_decrement(&m_refCount
);
63 SwXDispatchProviderInterceptor::~SwXDispatchProviderInterceptor()
67 uno::Reference
< frame::XDispatch
> SwXDispatchProviderInterceptor::queryDispatch(
68 const util::URL
& aURL
, const OUString
& aTargetFrameName
, sal_Int32 nSearchFlags
)
70 DispatchMutexLock_Impl aLock
;
71 uno::Reference
< frame::XDispatch
> xResult
;
72 // create some dispatch ...
73 if(m_pView
&& aURL
.Complete
.startsWith(".uno:DataSourceBrowser/"))
75 if(aURL
.Complete
== cURLFormLetter
||
76 aURL
.Complete
== cURLInsertContent
||
77 aURL
.Complete
== cURLInsertColumns
||
78 aURL
.Complete
== cURLDocumentDataSource
)
81 m_xDispatch
= new SwXDispatch(*m_pView
);
82 xResult
= m_xDispatch
;
86 // ask our slave provider
87 if (!xResult
.is() && m_xSlaveDispatcher
.is())
88 xResult
= m_xSlaveDispatcher
->queryDispatch(aURL
, aTargetFrameName
, nSearchFlags
);
93 uno::Sequence
<OUString
> SAL_CALL
SwXDispatchProviderInterceptor::getInterceptedURLs()
95 uno::Sequence
<OUString
> aRet
=
97 OUString(".uno:DataSourceBrowser/*")
103 uno::Sequence
< uno::Reference
< frame::XDispatch
> > SwXDispatchProviderInterceptor::queryDispatches(
104 const uno::Sequence
< frame::DispatchDescriptor
>& aDescripts
)
106 DispatchMutexLock_Impl aLock
;
107 uno::Sequence
< uno::Reference
< frame::XDispatch
> > aReturn(aDescripts
.getLength());
108 std::transform(aDescripts
.begin(), aDescripts
.end(), aReturn
.getArray(),
109 [this](const frame::DispatchDescriptor
& rDescr
) -> uno::Reference
<frame::XDispatch
> {
110 return queryDispatch(rDescr
.FeatureURL
, rDescr
.FrameName
, rDescr
.SearchFlags
); });
114 uno::Reference
< frame::XDispatchProvider
> SwXDispatchProviderInterceptor::getSlaveDispatchProvider( )
116 DispatchMutexLock_Impl aLock
;
117 return m_xSlaveDispatcher
;
120 void SwXDispatchProviderInterceptor::setSlaveDispatchProvider(
121 const uno::Reference
< frame::XDispatchProvider
>& xNewDispatchProvider
)
123 DispatchMutexLock_Impl aLock
;
124 m_xSlaveDispatcher
= xNewDispatchProvider
;
127 uno::Reference
< frame::XDispatchProvider
> SwXDispatchProviderInterceptor::getMasterDispatchProvider( )
129 DispatchMutexLock_Impl aLock
;
130 return m_xMasterDispatcher
;
133 void SwXDispatchProviderInterceptor::setMasterDispatchProvider(
134 const uno::Reference
< frame::XDispatchProvider
>& xNewSupplier
)
136 DispatchMutexLock_Impl aLock
;
137 m_xMasterDispatcher
= xNewSupplier
;
140 void SwXDispatchProviderInterceptor::disposing( const lang::EventObject
& )
142 DispatchMutexLock_Impl aLock
;
143 if (m_xIntercepted
.is())
145 m_xIntercepted
->releaseDispatchProviderInterceptor(static_cast<frame::XDispatchProviderInterceptor
*>(this));
146 uno::Reference
< lang::XComponent
> xInterceptedComponent(m_xIntercepted
, uno::UNO_QUERY
);
147 if (xInterceptedComponent
.is())
148 xInterceptedComponent
->removeEventListener(static_cast<lang::XEventListener
*>(this));
149 m_xDispatch
= nullptr;
151 m_xIntercepted
= nullptr;
154 void SwXDispatchProviderInterceptor::Invalidate()
156 DispatchMutexLock_Impl aLock
;
157 if (m_xIntercepted
.is())
159 m_xIntercepted
->releaseDispatchProviderInterceptor(static_cast<frame::XDispatchProviderInterceptor
*>(this));
160 uno::Reference
< lang::XComponent
> xInterceptedComponent(m_xIntercepted
, uno::UNO_QUERY
);
161 if (xInterceptedComponent
.is())
162 xInterceptedComponent
->removeEventListener(static_cast<lang::XEventListener
*>(this));
163 m_xDispatch
= nullptr;
165 m_xIntercepted
= nullptr;
169 SwXDispatch::SwXDispatch(SwView
& rVw
) :
172 m_bListenerAdded(false)
176 SwXDispatch::~SwXDispatch()
178 if(m_bListenerAdded
&& m_pView
)
180 uno::Reference
<view::XSelectionSupplier
> xSupplier
= m_pView
->GetUNOObject();
181 uno::Reference
<view::XSelectionChangeListener
> xThis
= this;
182 xSupplier
->removeSelectionChangeListener(xThis
);
186 void SwXDispatch::dispatch(const util::URL
& aURL
,
187 const uno::Sequence
< beans::PropertyValue
>& aArgs
)
190 throw uno::RuntimeException();
191 #if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
197 SwWrtShell
& rSh
= m_pView
->GetWrtShell();
198 SwDBManager
* pDBManager
= rSh
.GetDBManager();
199 if(aURL
.Complete
== cURLInsertContent
)
201 svx::ODataAccessDescriptor
aDescriptor(aArgs
);
202 SwMergeDescriptor
aMergeDesc( DBMGR_MERGE
, rSh
, aDescriptor
);
203 pDBManager
->Merge(aMergeDesc
);
205 else if(aURL
.Complete
== cURLInsertColumns
)
207 SwDBManager::InsertText(rSh
, aArgs
);
209 else if(aURL
.Complete
== cURLFormLetter
)
211 SfxUnoAnyItem
aDBProperties(FN_PARAM_DATABASE_PROPERTIES
, uno::Any(aArgs
));
212 m_pView
->GetViewFrame().GetDispatcher()->ExecuteList(
214 SfxCallMode::ASYNCHRON
,
218 else if(aURL
.Complete
== cURLDocumentDataSource
)
220 OSL_FAIL("SwXDispatch::dispatch: this URL is not to be dispatched!");
222 else if(aURL
.Complete
== cInternalDBChangeNotification
)
224 frame::FeatureStateEvent aEvent
;
225 aEvent
.Source
= *static_cast<cppu::OWeakObject
*>(this);
227 const SwDBData
& rData
= m_pView
->GetWrtShell().GetDBData();
228 svx::ODataAccessDescriptor aDescriptor
;
229 aDescriptor
.setDataSource(rData
.sDataSource
);
230 aDescriptor
[svx::DataAccessDescriptorProperty::Command
] <<= rData
.sCommand
;
231 aDescriptor
[svx::DataAccessDescriptorProperty::CommandType
] <<= rData
.nCommandType
;
233 aEvent
.State
<<= aDescriptor
.createPropertyValueSequence();
234 aEvent
.IsEnabled
= !rData
.sDataSource
.isEmpty();
236 // calls to statusChanged may call addStatusListener or removeStatusListener
237 // so copy m_aStatusListenerVector on stack
238 auto copyStatusListenerVector
= m_aStatusListenerVector
;
239 for (auto & status
: copyStatusListenerVector
)
241 if(status
.aURL
.Complete
== cURLDocumentDataSource
)
243 aEvent
.FeatureURL
= status
.aURL
;
244 status
.xListener
->statusChanged( aEvent
);
249 throw uno::RuntimeException();
253 void SwXDispatch::addStatusListener(
254 const uno::Reference
< frame::XStatusListener
>& xControl
, const util::URL
& aURL
)
257 throw uno::RuntimeException();
258 ShellMode eMode
= m_pView
->GetShellMode();
259 bool bEnable
= ShellMode::Text
== eMode
||
260 ShellMode::ListText
== eMode
||
261 ShellMode::TableText
== eMode
||
262 ShellMode::TableListText
== eMode
;
264 m_bOldEnable
= bEnable
;
265 frame::FeatureStateEvent aEvent
;
266 aEvent
.IsEnabled
= bEnable
;
267 aEvent
.Source
= *static_cast<cppu::OWeakObject
*>(this);
268 aEvent
.FeatureURL
= aURL
;
270 // one of the URLs requires a special state...
271 if (aURL
.Complete
== cURLDocumentDataSource
)
273 const SwDBData
& rData
= m_pView
->GetWrtShell().GetDBData();
275 svx::ODataAccessDescriptor aDescriptor
;
276 aDescriptor
.setDataSource(rData
.sDataSource
);
277 aDescriptor
[svx::DataAccessDescriptorProperty::Command
] <<= rData
.sCommand
;
278 aDescriptor
[svx::DataAccessDescriptorProperty::CommandType
] <<= rData
.nCommandType
;
280 aEvent
.State
<<= aDescriptor
.createPropertyValueSequence();
281 aEvent
.IsEnabled
= !rData
.sDataSource
.isEmpty();
284 xControl
->statusChanged( aEvent
);
286 StatusStruct_Impl aStatus
;
287 aStatus
.xListener
= xControl
;
289 m_aStatusListenerVector
.emplace_back(aStatus
);
291 if(!m_bListenerAdded
)
293 uno::Reference
<view::XSelectionSupplier
> xSupplier
= m_pView
->GetUNOObject();
294 uno::Reference
<view::XSelectionChangeListener
> xThis
= this;
295 xSupplier
->addSelectionChangeListener(xThis
);
296 m_bListenerAdded
= true;
300 void SwXDispatch::removeStatusListener(
301 const uno::Reference
< frame::XStatusListener
>& xControl
, const util::URL
& )
303 m_aStatusListenerVector
.erase(
304 std::remove_if(m_aStatusListenerVector
.begin(), m_aStatusListenerVector
.end(),
305 [&](const StatusStruct_Impl
& status
) { return status
.xListener
.get() == xControl
.get(); }),
306 m_aStatusListenerVector
.end());
307 if(m_aStatusListenerVector
.empty() && m_pView
)
309 uno::Reference
<view::XSelectionSupplier
> xSupplier
= m_pView
->GetUNOObject();
310 uno::Reference
<view::XSelectionChangeListener
> xThis
= this;
311 xSupplier
->removeSelectionChangeListener(xThis
);
312 m_bListenerAdded
= false;
316 void SwXDispatch::selectionChanged( const lang::EventObject
& )
318 ShellMode eMode
= m_pView
->GetShellMode();
319 bool bEnable
= ShellMode::Text
== eMode
||
320 ShellMode::ListText
== eMode
||
321 ShellMode::TableText
== eMode
||
322 ShellMode::TableListText
== eMode
;
323 if(bEnable
== m_bOldEnable
)
326 m_bOldEnable
= bEnable
;
327 frame::FeatureStateEvent aEvent
;
328 aEvent
.IsEnabled
= bEnable
;
329 aEvent
.Source
= *static_cast<cppu::OWeakObject
*>(this);
331 // calls to statusChanged may call addStatusListener or removeStatusListener
332 // so copy m_aStatusListenerVector on stack
333 auto copyStatusListenerVector
= m_aStatusListenerVector
;
334 for (auto & status
: copyStatusListenerVector
)
336 aEvent
.FeatureURL
= status
.aURL
;
337 if (status
.aURL
.Complete
!= cURLDocumentDataSource
)
338 // the document's data source does not depend on the selection, so it's state does not change here
339 status
.xListener
->statusChanged( aEvent
);
343 void SwXDispatch::disposing( const lang::EventObject
& rSource
)
345 uno::Reference
<view::XSelectionSupplier
> xSupplier(rSource
.Source
, uno::UNO_QUERY
);
346 uno::Reference
<view::XSelectionChangeListener
> xThis
= this;
347 xSupplier
->removeSelectionChangeListener(xThis
);
348 m_bListenerAdded
= false;
350 lang::EventObject aObject
;
351 aObject
.Source
= static_cast<cppu::OWeakObject
*>(this);
352 // calls to statusChanged may call addStatusListener or removeStatusListener
353 // so copy m_aStatusListenerVector on stack
354 auto copyStatusListenerVector
= m_aStatusListenerVector
;
355 for (auto & status
: copyStatusListenerVector
)
357 status
.xListener
->disposing(aObject
);
362 const char* SwXDispatch::GetDBChangeURL()
364 return cInternalDBChangeNotification
;
367 SwXDispatchProviderInterceptor::DispatchMutexLock_Impl::DispatchMutexLock_Impl()
371 SwXDispatchProviderInterceptor::DispatchMutexLock_Impl::~DispatchMutexLock_Impl()
375 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */