Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/sc/source/ui/unoobj/dispuno.cxx
Line
Count
Source (jump to first uncovered line)
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 <sfx2/viewfrm.hxx>
21
#include <svx/dataaccessdescriptor.hxx>
22
#include <svl/hint.hxx>
23
#include <vcl/svapp.hxx>
24
25
#include <com/sun/star/frame/XDispatchProviderInterception.hpp>
26
#include <com/sun/star/view/XSelectionSupplier.hpp>
27
#include <com/sun/star/sdb/CommandType.hpp>
28
29
#include <dispuno.hxx>
30
#include <tabvwsh.hxx>
31
#include <dbdocfun.hxx>
32
#include <dbdata.hxx>
33
34
using namespace com::sun::star;
35
36
const char cURLInsertColumns[] = ".uno:DataSourceBrowser/InsertColumns"; //data into text
37
constexpr OUString cURLDocDataSource = u".uno:DataSourceBrowser/DocumentDataSource"_ustr;
38
39
static uno::Reference<view::XSelectionSupplier> lcl_GetSelectionSupplier( const SfxViewShell* pViewShell )
40
0
{
41
0
    if ( pViewShell )
42
0
    {
43
0
        SfxViewFrame& rViewFrame = pViewShell->GetViewFrame();
44
0
        return uno::Reference<view::XSelectionSupplier>( rViewFrame.GetFrame().GetController(), uno::UNO_QUERY );
45
0
    }
46
0
    return uno::Reference<view::XSelectionSupplier>();
47
0
}
48
49
ScDispatchProviderInterceptor::ScDispatchProviderInterceptor(ScTabViewShell* pViewSh) :
50
0
    pViewShell( pViewSh )
51
0
{
52
0
    if ( !pViewShell )
53
0
        return;
54
55
0
    m_xIntercepted.set(uno::Reference<frame::XDispatchProviderInterception>(pViewShell->GetViewFrame().GetFrame().GetFrameInterface(), uno::UNO_QUERY));
56
0
    if (m_xIntercepted.is())
57
0
    {
58
0
        osl_atomic_increment( &m_refCount );
59
60
0
        m_xIntercepted->registerDispatchProviderInterceptor(
61
0
                    static_cast<frame::XDispatchProviderInterceptor*>(this));
62
        // this should make us the top-level dispatch-provider for the component, via a call to our
63
        // setDispatchProvider we should have got a fallback for requests we (i.e. our master) cannot fulfill
64
0
        uno::Reference<lang::XComponent> xInterceptedComponent(m_xIntercepted, uno::UNO_QUERY);
65
0
        if (xInterceptedComponent.is())
66
0
            xInterceptedComponent->addEventListener(static_cast<lang::XEventListener*>(this));
67
68
0
        osl_atomic_decrement( &m_refCount );
69
0
    }
70
71
0
    StartListening(*pViewShell);
72
0
}
73
74
ScDispatchProviderInterceptor::~ScDispatchProviderInterceptor()
75
0
{
76
0
    if (pViewShell)
77
0
        EndListening(*pViewShell);
78
0
}
79
80
void ScDispatchProviderInterceptor::Notify( SfxBroadcaster&, const SfxHint& rHint )
81
0
{
82
0
    if ( rHint.GetId() == SfxHintId::Dying )
83
0
        pViewShell = nullptr;
84
0
}
85
86
// XDispatchProvider
87
88
uno::Reference<frame::XDispatch> SAL_CALL ScDispatchProviderInterceptor::queryDispatch(
89
                        const util::URL& aURL, const OUString& aTargetFrameName,
90
                        sal_Int32 nSearchFlags )
91
0
{
92
0
    SolarMutexGuard aGuard;
93
94
0
    uno::Reference<frame::XDispatch> xResult;
95
    // create some dispatch ...
96
0
    if ( pViewShell && (
97
0
        aURL.Complete == cURLInsertColumns ||
98
0
        aURL.Complete == cURLDocDataSource ) )
99
0
    {
100
0
        if (!m_xMyDispatch.is())
101
0
            m_xMyDispatch = new ScDispatch( pViewShell );
102
0
        xResult = m_xMyDispatch;
103
0
    }
104
105
    // ask our slave provider
106
0
    if (!xResult.is() && m_xSlaveDispatcher.is())
107
0
        xResult = m_xSlaveDispatcher->queryDispatch(aURL, aTargetFrameName, nSearchFlags);
108
109
0
    return xResult;
110
0
}
111
112
uno::Sequence< uno::Reference<frame::XDispatch> > SAL_CALL
113
                        ScDispatchProviderInterceptor::queryDispatches(
114
                        const uno::Sequence<frame::DispatchDescriptor>& aDescripts )
115
0
{
116
0
    SolarMutexGuard aGuard;
117
118
0
    uno::Sequence< uno::Reference< frame::XDispatch> > aReturn(aDescripts.getLength());
119
0
    std::transform(aDescripts.begin(), aDescripts.end(), aReturn.getArray(),
120
0
        [this](const frame::DispatchDescriptor& rDescr) -> uno::Reference<frame::XDispatch> {
121
0
            return queryDispatch(rDescr.FeatureURL, rDescr.FrameName, rDescr.SearchFlags); });
122
0
    return aReturn;
123
0
}
124
125
// XDispatchProviderInterceptor
126
127
uno::Reference<frame::XDispatchProvider> SAL_CALL
128
                        ScDispatchProviderInterceptor::getSlaveDispatchProvider()
129
0
{
130
0
    SolarMutexGuard aGuard;
131
0
    return m_xSlaveDispatcher;
132
0
}
133
134
void SAL_CALL ScDispatchProviderInterceptor::setSlaveDispatchProvider(
135
                        const uno::Reference<frame::XDispatchProvider>& xNewDispatchProvider )
136
0
{
137
0
    SolarMutexGuard aGuard;
138
0
    m_xSlaveDispatcher.set(xNewDispatchProvider);
139
0
}
140
141
uno::Reference<frame::XDispatchProvider> SAL_CALL
142
                        ScDispatchProviderInterceptor::getMasterDispatchProvider()
143
0
{
144
0
    SolarMutexGuard aGuard;
145
0
    return m_xMasterDispatcher;
146
0
}
147
148
void SAL_CALL ScDispatchProviderInterceptor::setMasterDispatchProvider(
149
                        const uno::Reference<frame::XDispatchProvider>& xNewSupplier )
150
0
{
151
0
    SolarMutexGuard aGuard;
152
0
    m_xMasterDispatcher.set(xNewSupplier);
153
0
}
154
155
// XEventListener
156
157
void SAL_CALL ScDispatchProviderInterceptor::disposing( const lang::EventObject& /* Source */ )
158
0
{
159
0
    SolarMutexGuard aGuard;
160
161
0
    if (m_xIntercepted.is())
162
0
    {
163
0
        m_xIntercepted->releaseDispatchProviderInterceptor(
164
0
                static_cast<frame::XDispatchProviderInterceptor*>(this));
165
0
        uno::Reference<lang::XComponent> xInterceptedComponent(m_xIntercepted, uno::UNO_QUERY);
166
0
        if (xInterceptedComponent.is())
167
0
            xInterceptedComponent->removeEventListener(static_cast<lang::XEventListener*>(this));
168
169
0
        m_xMyDispatch = nullptr;
170
0
    }
171
0
    m_xIntercepted = nullptr;
172
0
}
173
174
ScDispatch::ScDispatch(ScTabViewShell* pViewSh) :
175
0
    pViewShell( pViewSh ),
176
0
    bListeningToView( false )
177
0
{
178
0
    if (pViewShell)
179
0
        StartListening(*pViewShell);
180
0
}
181
182
ScDispatch::~ScDispatch()
183
0
{
184
0
    if (pViewShell)
185
0
        EndListening(*pViewShell);
186
187
0
    if (bListeningToView && pViewShell)
188
0
    {
189
0
        uno::Reference<view::XSelectionSupplier> xSupplier(lcl_GetSelectionSupplier( pViewShell ));
190
0
        if ( xSupplier.is() )
191
0
            xSupplier->removeSelectionChangeListener(this);
192
0
    }
193
0
}
194
195
void ScDispatch::Notify( SfxBroadcaster&, const SfxHint& rHint )
196
0
{
197
0
    if ( rHint.GetId() == SfxHintId::Dying )
198
0
        pViewShell = nullptr;
199
0
}
200
201
// XDispatch
202
203
void SAL_CALL ScDispatch::dispatch( const util::URL& aURL,
204
                                const uno::Sequence<beans::PropertyValue>& aArgs )
205
0
{
206
0
    SolarMutexGuard aGuard;
207
208
0
    bool bDone = false;
209
0
    if ( pViewShell && aURL.Complete == cURLInsertColumns )
210
0
    {
211
0
        ScViewData& rViewData = pViewShell->GetViewData();
212
0
        ScAddress aPos( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() );
213
214
0
        ScDBDocFunc aFunc( rViewData.GetDocShell() );
215
0
        aFunc.DoImportUno( aPos, aArgs );
216
0
        bDone = true;
217
0
    }
218
    // cURLDocDataSource is never dispatched
219
220
0
    if (!bDone)
221
0
        throw uno::RuntimeException();
222
0
}
223
224
static void lcl_FillDataSource( frame::FeatureStateEvent& rEvent, const ScImportParam& rParam )
225
0
{
226
0
    rEvent.IsEnabled = rParam.bImport;
227
228
0
    svx::ODataAccessDescriptor aDescriptor;
229
0
    if ( rParam.bImport )
230
0
    {
231
0
        sal_Int32 nType = rParam.bSql ? sdb::CommandType::COMMAND :
232
0
                    ( (rParam.nType == ScDbQuery) ? sdb::CommandType::QUERY :
233
0
                                                    sdb::CommandType::TABLE );
234
235
0
        aDescriptor.setDataSource(rParam.aDBName);
236
0
        aDescriptor[svx::DataAccessDescriptorProperty::Command]     <<= rParam.aStatement;
237
0
        aDescriptor[svx::DataAccessDescriptorProperty::CommandType] <<= nType;
238
0
    }
239
0
    else
240
0
    {
241
        //  descriptor has to be complete anyway
242
243
0
        aDescriptor[svx::DataAccessDescriptorProperty::DataSource]  <<= OUString();
244
0
        aDescriptor[svx::DataAccessDescriptorProperty::Command]     <<= OUString();
245
0
        aDescriptor[svx::DataAccessDescriptorProperty::CommandType] <<= sal_Int32(sdb::CommandType::TABLE);
246
0
    }
247
0
    rEvent.State <<= aDescriptor.createPropertyValueSequence();
248
0
}
249
250
void SAL_CALL ScDispatch::addStatusListener(
251
    const uno::Reference<frame::XStatusListener>& xListener,
252
    const util::URL& aURL)
253
0
{
254
0
    SolarMutexGuard aGuard;
255
256
0
    if (!pViewShell)
257
0
        throw uno::RuntimeException();
258
259
    //  initial state
260
0
    frame::FeatureStateEvent aEvent;
261
0
    aEvent.IsEnabled = true;
262
0
    aEvent.Source = getXWeak();
263
0
    aEvent.FeatureURL = aURL;
264
265
0
    if ( aURL.Complete == cURLDocDataSource )
266
0
    {
267
0
        aDataSourceListeners.emplace_back( xListener );
268
269
0
        if (!bListeningToView)
270
0
        {
271
0
            uno::Reference<view::XSelectionSupplier> xSupplier(lcl_GetSelectionSupplier( pViewShell ));
272
0
            if ( xSupplier.is() )
273
0
                xSupplier->addSelectionChangeListener(this);
274
0
            bListeningToView = true;
275
0
        }
276
277
0
        ScDBData* pDBData = pViewShell->GetDBData(false,SC_DB_OLD);
278
0
        if ( pDBData )
279
0
            pDBData->GetImportParam( aLastImport );
280
0
        lcl_FillDataSource( aEvent, aLastImport );          // modifies State, IsEnabled
281
0
    }
282
    //! else add to listener for "enabled" changes?
283
284
0
    xListener->statusChanged( aEvent );
285
0
}
286
287
void SAL_CALL ScDispatch::removeStatusListener(
288
                                const uno::Reference<frame::XStatusListener>& xListener,
289
                                const util::URL& aURL )
290
0
{
291
0
    SolarMutexGuard aGuard;
292
293
0
    if ( aURL.Complete != cURLDocDataSource )
294
0
        return;
295
296
0
    sal_uInt16 nCount = aDataSourceListeners.size();
297
0
    for ( sal_uInt16 n=nCount; n--; )
298
0
    {
299
0
        uno::Reference<frame::XStatusListener>& rObj = aDataSourceListeners[n];
300
0
        if ( rObj == xListener )
301
0
        {
302
0
            aDataSourceListeners.erase( aDataSourceListeners.begin() + n );
303
0
            break;
304
0
        }
305
0
    }
306
307
0
    if ( aDataSourceListeners.empty() && pViewShell )
308
0
    {
309
0
        uno::Reference<view::XSelectionSupplier> xSupplier(lcl_GetSelectionSupplier( pViewShell ));
310
0
        if ( xSupplier.is() )
311
0
            xSupplier->removeSelectionChangeListener(this);
312
0
        bListeningToView = false;
313
0
    }
314
0
}
315
316
// XSelectionChangeListener
317
318
void SAL_CALL ScDispatch::selectionChanged( const css::lang::EventObject& /* aEvent */ )
319
0
{
320
    //  currently only called for URL cURLDocDataSource
321
322
0
    if ( !pViewShell )
323
0
        return;
324
325
0
    ScImportParam aNewImport;
326
0
    ScDBData* pDBData = pViewShell->GetDBData(false,SC_DB_OLD);
327
0
    if ( pDBData )
328
0
        pDBData->GetImportParam( aNewImport );
329
330
    //  notify listeners only if data source has changed
331
0
    if ( !(aNewImport.bImport    != aLastImport.bImport ||
332
0
         aNewImport.aDBName    != aLastImport.aDBName ||
333
0
         aNewImport.aStatement != aLastImport.aStatement ||
334
0
         aNewImport.bSql       != aLastImport.bSql ||
335
0
         aNewImport.nType      != aLastImport.nType) )
336
0
        return;
337
338
0
    frame::FeatureStateEvent aEvent;
339
0
    aEvent.Source = getXWeak();
340
0
    aEvent.FeatureURL.Complete = cURLDocDataSource;
341
342
0
    lcl_FillDataSource( aEvent, aNewImport );       // modifies State, IsEnabled
343
344
0
    for (uno::Reference<frame::XStatusListener> & xDataSourceListener : aDataSourceListeners)
345
0
        xDataSourceListener->statusChanged( aEvent );
346
347
0
    aLastImport = aNewImport;
348
0
}
349
350
// XEventListener
351
352
void SAL_CALL ScDispatch::disposing( const css::lang::EventObject& rSource )
353
0
{
354
0
    uno::Reference<view::XSelectionSupplier> xSupplier(rSource.Source, uno::UNO_QUERY);
355
0
    xSupplier->removeSelectionChangeListener(this);
356
0
    bListeningToView = false;
357
358
0
    lang::EventObject aEvent;
359
0
    aEvent.Source = getXWeak();
360
0
    for (uno::Reference<frame::XStatusListener> & xDataSourceListener : aDataSourceListeners)
361
0
        xDataSourceListener->disposing( aEvent );
362
363
0
    pViewShell = nullptr;
364
0
}
365
366
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */