Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/control/shell.cxx
Line
Count
Source
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/embed/VerbDescriptor.hpp>
21
#include <com/sun/star/embed/VerbAttributes.hpp>
22
#include <com/sun/star/lang/XInitialization.hpp>
23
#include <officecfg/Office/Common.hxx>
24
#include <rtl/ustring.hxx>
25
#include <sal/log.hxx>
26
#include <osl/diagnose.h>
27
#include <svl/itempool.hxx>
28
#include <svl/setitem.hxx>
29
#include <svl/voiditem.hxx>
30
#include <svl/undo.hxx>
31
#include <svtools/asynclink.hxx>
32
#include <unotools/configmgr.hxx>
33
#include <comphelper/lok.hxx>
34
#include <comphelper/propertysequence.hxx>
35
#include <sfx2/shell.hxx>
36
#include <sfx2/bindings.hxx>
37
#include <sfx2/dispatch.hxx>
38
#include <sfx2/viewfrm.hxx>
39
#include <sfx2/objface.hxx>
40
#include <sfx2/objsh.hxx>
41
#include <sfx2/viewsh.hxx>
42
#include <sfx2/request.hxx>
43
#include <sfx2/sfxsids.hrc>
44
#include <statcach.hxx>
45
#include <sidebar/ContextChangeBroadcaster.hxx>
46
#include <com/sun/star/ui/dialogs/XSLTFilterDialog.hpp>
47
#include <toolkit/helper/vclunohelper.hxx>
48
#include <tools/debug.hxx>
49
50
#include <memory>
51
#include <vector>
52
#include <map>
53
54
#include <desktop/crashreport.hxx>
55
56
using namespace com::sun::star;
57
58
struct SfxShell_Impl: public SfxBroadcaster
59
{
60
    OUString                    aObjectName;   // Name of Sbx-Objects
61
    // Maps the Which() field to a pointer to a SfxPoolItem
62
    std::map<sal_uInt16, std::unique_ptr<SfxPoolItem>>
63
                                m_Items;       // Data exchange on Item level
64
    SfxViewShell*               pViewSh;       // SfxViewShell if Shell is
65
                                               // ViewFrame/ViewShell/SubShell list
66
    SfxViewFrame*               pFrame;        // Frame, if  <UI-active>
67
    SfxRepeatTarget*            pRepeatTarget; // SbxObjectRef xParent;
68
    bool                        bActive;
69
    SfxDisableFlags             nDisableFlags;
70
    std::unique_ptr<svtools::AsynchronLink> pExecuter;
71
    std::unique_ptr<svtools::AsynchronLink> pUpdater;
72
    std::vector<std::unique_ptr<SfxSlot> >  aSlotArr;
73
74
    css::uno::Sequence < css::embed::VerbDescriptor > aVerbList;
75
    ::sfx2::sidebar::ContextChangeBroadcaster maContextChangeBroadcaster;
76
77
    SfxShell_Impl()
78
228k
        : pViewSh(nullptr)
79
228k
        , pFrame(nullptr)
80
228k
        , pRepeatTarget(nullptr)
81
228k
        , bActive(false)
82
228k
        , nDisableFlags(SfxDisableFlags::NONE)
83
228k
    {
84
228k
    }
85
86
227k
    virtual ~SfxShell_Impl() override { pExecuter.reset(); pUpdater.reset();}
87
};
88
89
90
void SfxShell::EmptyExecStub(SfxShell *, SfxRequest &)
91
0
{
92
0
}
93
94
void SfxShell::EmptyStateStub(SfxShell *, SfxItemSet &)
95
0
{
96
0
}
97
98
SfxShell::SfxShell()
99
211k
:   pImpl(new SfxShell_Impl),
100
211k
    pPool(nullptr),
101
211k
    pUndoMgr(nullptr)
102
211k
{
103
211k
}
104
105
SfxShell::SfxShell( SfxViewShell *pViewSh )
106
16.3k
:   pImpl(new SfxShell_Impl),
107
16.3k
    pPool(nullptr),
108
16.3k
    pUndoMgr(nullptr)
109
16.3k
{
110
16.3k
    pImpl->pViewSh = pViewSh;
111
16.3k
}
112
113
SfxShell::~SfxShell()
114
227k
{
115
227k
}
116
117
void SfxShell::SetName( const OUString &rName )
118
55.3k
{
119
55.3k
    pImpl->aObjectName = rName;
120
55.3k
}
121
122
const OUString& SfxShell::GetName() const
123
177k
{
124
177k
    return pImpl->aObjectName;
125
177k
}
126
127
SfxDispatcher* SfxShell::GetDispatcher() const
128
306k
{
129
306k
    return pImpl->pFrame ? pImpl->pFrame->GetDispatcher() : nullptr;
130
306k
}
131
132
SfxViewShell* SfxShell::GetViewShell() const
133
447k
{
134
447k
    return pImpl->pViewSh;
135
447k
}
136
137
SfxViewFrame* SfxShell::GetFrame() const
138
132k
{
139
132k
    if ( pImpl->pFrame )
140
28.6k
        return pImpl->pFrame;
141
103k
    if ( pImpl->pViewSh )
142
24.5k
        return &pImpl->pViewSh->GetViewFrame();
143
79.4k
    return nullptr;
144
103k
}
145
146
const SfxPoolItem* SfxShell::GetItem
147
(
148
    sal_uInt16  nSlotId         // Slot-Id of the querying <SfxPoolItem>s
149
)   const
150
126k
{
151
126k
    auto const it = pImpl->m_Items.find( nSlotId );
152
126k
    if (it != pImpl->m_Items.end())
153
29.3k
        return it->second.get();
154
97.0k
    return nullptr;
155
126k
}
156
157
void SfxShell::PutItem
158
(
159
    const SfxPoolItem&  rItem  /* Instance, of which a copy is created,
160
                                  which is stored in the SfxShell in a list. */
161
)
162
1.12M
{
163
1.12M
    DBG_ASSERT( !rItem.isSetItem(), "SetItems aren't allowed here" );
164
1.12M
    DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
165
1.12M
                "items with Which-Ids aren't allowed here" );
166
167
    // MSC made a mess here of WNT/W95, beware of changes
168
1.12M
    SfxPoolItem *pItem = rItem.Clone();
169
1.12M
    SfxPoolItemHint aItemHint( pItem );
170
1.12M
    sal_uInt16 nWhich = rItem.Which();
171
172
1.12M
    auto const it = pImpl->m_Items.find(nWhich);
173
1.12M
    if (it != pImpl->m_Items.end())
174
94.6k
    {
175
        // Replace Item
176
94.6k
        it->second = std::unique_ptr<SfxPoolItem>(pItem);
177
178
        // if active, notify Bindings
179
94.6k
        SfxDispatcher *pDispat = GetDispatcher();
180
94.6k
        if ( pDispat )
181
116
        {
182
116
            SfxBindings* pBindings = pDispat->GetBindings();
183
116
            pBindings->Broadcast( aItemHint );
184
116
            sal_uInt16 nSlotId = nWhich; //pItem->GetSlotId();
185
116
            SfxStateCache* pCache = pBindings->GetStateCache( nSlotId );
186
116
            if ( pCache )
187
0
            {
188
0
                pCache->SetState( SfxItemState::DEFAULT, pItem, true );
189
0
                pCache->SetCachedState( true );
190
0
            }
191
116
        }
192
94.6k
        return;
193
94.6k
    }
194
1.03M
    else
195
1.03M
    {
196
1.03M
        Broadcast( aItemHint );
197
1.03M
        pImpl->m_Items.insert(std::make_pair(nWhich, std::unique_ptr<SfxPoolItem>(pItem)));
198
1.03M
    }
199
1.12M
}
200
201
SfxInterface* SfxShell::GetInterface() const
202
0
{
203
0
    return GetStaticInterface();
204
0
}
205
206
SfxUndoManager* SfxShell::GetUndoManager()
207
0
{
208
0
    return pUndoMgr;
209
0
}
210
211
void SfxShell::SetUndoManager( SfxUndoManager *pNewUndoMgr )
212
154k
{
213
154k
    OSL_ENSURE( ( pUndoMgr == nullptr ) || ( pNewUndoMgr == nullptr ) || ( pUndoMgr == pNewUndoMgr ),
214
154k
        "SfxShell::SetUndoManager: exchanging one non-NULL manager with another non-NULL manager? Suspicious!" );
215
    // there's at least one client of our UndoManager - the DocumentUndoManager at the SfxBaseModel - which
216
    // caches the UndoManager, and registers itself as listener. If exchanging non-NULL UndoManagers is really
217
    // a supported scenario (/me thinks it is not), then we would need to notify all such clients instances.
218
219
154k
    pUndoMgr = pNewUndoMgr;
220
154k
    if (pUndoMgr && !comphelper::IsFuzzing())
221
0
    {
222
0
        pUndoMgr->SetMaxUndoActionCount(
223
0
            officecfg::Office::Common::Undo::Steps::get());
224
0
    }
225
154k
}
226
227
SfxRepeatTarget* SfxShell::GetRepeatTarget() const
228
0
{
229
0
    return pImpl->pRepeatTarget;
230
0
}
231
232
void SfxShell::SetRepeatTarget( SfxRepeatTarget *pTarget )
233
0
{
234
0
    pImpl->pRepeatTarget = pTarget;
235
0
}
236
237
void SfxShell::Invalidate
238
(
239
    sal_uInt16          nId     /* Invalidated Slot-Id or Which-Id.
240
                               If these are 0 (default), then all
241
                               by this Shell currently handled Slot-Ids are
242
                               invalidated. */
243
)
244
668
{
245
668
    if ( !GetViewShell() )
246
0
    {
247
0
        OSL_FAIL( "wrong Invalidate method called!" );
248
0
        return;
249
0
    }
250
251
668
    Invalidate_Impl( GetViewShell()->GetViewFrame().GetBindings(), nId );
252
668
}
253
254
void SfxShell::Invalidate_Impl( SfxBindings& rBindings, sal_uInt16 nId )
255
668
{
256
668
    if ( nId == 0 )
257
0
    {
258
0
        rBindings.InvalidateShell( *this );
259
0
    }
260
668
    else
261
668
    {
262
668
        const SfxInterface *pIF = GetInterface();
263
668
        do
264
668
        {
265
668
            const SfxSlot *pSlot = pIF->GetSlot(nId);
266
668
            if ( pSlot )
267
668
            {
268
                // Invalidate the Slot itself
269
668
                rBindings.Invalidate( pSlot->GetSlotId() );
270
668
                return;
271
668
            }
272
273
0
            pIF = pIF->GetGenoType();
274
0
        }
275
276
668
        while ( pIF );
277
278
0
        SAL_INFO( "sfx.control", "W3: invalidating slot-id unknown in shell" );
279
0
    }
280
668
}
281
282
void SfxShell::HandleOpenXmlFilterSettings(SfxRequest & rReq)
283
0
{
284
0
    try
285
0
    {
286
0
        uno::Reference < ui::dialogs::XExecutableDialog > xDialog = ui::dialogs::XSLTFilterDialog::create( ::comphelper::getProcessComponentContext() );
287
288
        // set dialog parent
289
0
        css::uno::Reference<com::sun::star::lang::XInitialization> xInit(xDialog,
290
0
                                                                         css::uno::UNO_QUERY);
291
0
        if (xInit.is())
292
0
        {
293
0
            if (SfxViewShell* pViewShell = GetViewShell())
294
0
            {
295
0
                css::uno::Reference<css::awt::XWindow> xDialogParent
296
0
                    = VCLUnoHelper::GetInterface(pViewShell->GetWindow());
297
0
                css::uno::Sequence<css::uno::Any> aSeq(comphelper::InitAnyPropertySequence(
298
0
                    { { "ParentWindow", uno::Any(xDialogParent) } }));
299
0
                xInit->initialize(aSeq);
300
0
            }
301
0
        }
302
303
0
        (void)xDialog->execute();
304
0
    }
305
0
    catch (const uno::Exception&)
306
0
    {
307
0
    }
308
0
    rReq.Ignore ();
309
0
}
310
311
void SfxShell::DoActivate_Impl( SfxViewFrame *pFrame, bool bMDI )
312
32.6k
{
313
32.6k
    SfxObjectShell* pObjectShell = GetObjectShell();
314
32.6k
    if ( pObjectShell )
315
24.5k
    {
316
24.5k
        const OUString sActiveDocName = pObjectShell->GetTitle();
317
24.5k
        if( !pImpl->aObjectName.startsWith(sActiveDocName) )
318
16.3k
        {
319
16.3k
           CrashReporter::setActiveSfxObjectName(pImpl->aObjectName);
320
16.3k
        }
321
24.5k
    }
322
8.16k
    else
323
8.16k
    {
324
8.16k
        CrashReporter::setActiveSfxObjectName(pImpl->aObjectName);
325
8.16k
    }
326
327
#ifdef DBG_UTIL
328
    const SfxInterface *p_IF = GetInterface();
329
    if ( !p_IF )
330
        return;
331
#endif
332
32.6k
    SAL_INFO(
333
32.6k
        "sfx.control",
334
32.6k
        "SfxShell::DoActivate() " << this << "  " << GetInterface()->GetClassName()
335
32.6k
            << " bMDI " << (bMDI ? "MDI" : ""));
336
337
32.6k
    if ( bMDI )
338
32.6k
    {
339
        // Remember Frame, in which it was activated
340
32.6k
        pImpl->pFrame = pFrame;
341
32.6k
        pImpl->bActive = true;
342
32.6k
    }
343
344
    // Notify Subclass
345
32.6k
    Activate(bMDI);
346
32.6k
}
347
348
void SfxShell::DoDeactivate_Impl( SfxViewFrame const *pFrame, bool bMDI )
349
36.7k
{
350
#ifdef DBG_UTIL
351
    const SfxInterface *p_IF = GetInterface();
352
    if ( !p_IF )
353
        return;
354
#endif
355
36.7k
    SAL_INFO(
356
36.7k
        "sfx.control",
357
36.7k
        "SfxShell::DoDeactivate()" << this << "  " << GetInterface()->GetClassName()
358
36.7k
            << " bMDI " << (bMDI ? "MDI" : ""));
359
360
    // Only when it comes from a Frame
361
    // (not when for instance by popping BASIC-IDE from AppDisp)
362
36.7k
    if ( bMDI && pImpl->pFrame == pFrame )
363
32.6k
    {
364
        // deliver
365
32.6k
        pImpl->pFrame = nullptr;
366
32.6k
        pImpl->bActive = false;
367
32.6k
    }
368
369
    // Notify Subclass
370
36.7k
    Deactivate(bMDI);
371
36.7k
}
372
373
bool SfxShell::IsActive() const
374
8.16k
{
375
8.16k
    return pImpl->bActive;
376
8.16k
}
377
378
void SfxShell::Activate
379
(
380
    bool    /*bMDI*/        /*  TRUE
381
                            the <SfxDispatcher>, on which the SfxShell is
382
                            located, is activated or the SfxShell instance
383
                            was pushed on an active SfxDispatcher.
384
                            (compare with SystemWindow::IsMDIActivate())
385
386
                            FALSE
387
                            the <SfxViewFrame>, on which SfxDispatcher
388
                            the SfxShell instance is located, was
389
                            activated. (for example by a closing dialog) */
390
)
391
24.5k
{
392
24.5k
    BroadcastContextForActivation(true);
393
24.5k
}
394
395
void SfxShell::Deactivate
396
(
397
    bool    /*bMDI*/        /*  TRUE
398
                            the <SfxDispatcher>, on which the SfxShell is
399
                            located, is inactivated or the SfxShell instance
400
                            was popped on an active SfxDispatcher.
401
                            (compare with SystemWindow::IsMDIActivate())
402
403
                            FALSE
404
                            the <SfxViewFrame>, on which SfxDispatcher
405
                            the SfxShell instance is located, was
406
                            deactivated. (for example by a dialog) */
407
)
408
28.6k
{
409
28.6k
    BroadcastContextForActivation(false);
410
28.6k
}
411
412
bool SfxShell::CanExecuteSlot_Impl( const SfxSlot &rSlot )
413
0
{
414
    // Get Slot status
415
0
    SfxItemPool &rPool = GetPool();
416
0
    const sal_uInt16 nId = rSlot.GetWhich( rPool );
417
0
    SfxItemSet aSet(rPool, nId, nId);
418
0
    SfxStateFunc pFunc = rSlot.GetStateFnc();
419
0
    (*pFunc)( this, aSet );
420
0
    return aSet.GetItemState(nId) != SfxItemState::DISABLED;
421
0
}
422
423
bool SfxShell::IsConditionalFastCall( const SfxRequest &rReq )
424
0
{
425
0
    sal_uInt16 nId = rReq.GetSlot();
426
0
    bool bRet = false;
427
428
0
    if (nId == SID_UNDO || nId == SID_REDO)
429
0
    {
430
0
        const SfxItemSet* pArgs = rReq.GetArgs();
431
0
        if (pArgs && pArgs->HasItem(SID_REPAIRPACKAGE))
432
0
            bRet = true;
433
0
    }
434
0
    return bRet;
435
0
}
436
437
438
static void ShellCall_Impl( void* pObj, void* pArg )
439
0
{
440
0
    static_cast<SfxShell*>(pObj)->ExecuteSlot( *static_cast<SfxRequest*>(pArg) );
441
0
}
442
443
void SfxShell::ExecuteSlot( SfxRequest& rReq, bool bAsync )
444
0
{
445
0
    if( !bAsync )
446
0
        ExecuteSlot( rReq );
447
0
    else
448
0
    {
449
0
        if( !pImpl->pExecuter )
450
0
            pImpl->pExecuter.reset( new svtools::AsynchronLink(
451
0
                LINK_NONMEMBER( this, ShellCall_Impl ) ) );
452
0
        pImpl->pExecuter->Call( new SfxRequest( rReq ) );
453
0
    }
454
0
}
455
456
const SfxPoolItemHolder& SfxShell::ExecuteSlot
457
(
458
    SfxRequest          &rReq,  // the relayed <SfxRequest>
459
    const SfxInterface* pIF     // default = 0 means get virtually
460
)
461
0
{
462
0
    if ( !pIF )
463
0
        pIF = GetInterface();
464
465
0
    sal_uInt16 nSlot = rReq.GetSlot();
466
0
    const SfxSlot* pSlot = nullptr;
467
0
    if ( nSlot >= SID_VERB_START && nSlot <= SID_VERB_END )
468
0
        pSlot = GetVerbSlot_Impl(nSlot);
469
0
    if ( !pSlot )
470
0
        pSlot = pIF->GetSlot(nSlot);
471
0
    assert(pSlot && "slot not supported");
472
473
0
    SfxExecFunc pFunc = pSlot->GetExecFnc();
474
0
    if ( pFunc )
475
0
        (*pFunc)( this, rReq );
476
477
0
    return rReq.GetReturnValue();
478
0
}
479
480
SfxPoolItemHolder SfxShell::GetSlotState
481
(
482
    sal_uInt16              nSlotId,    // Slot-Id to the Slots in question
483
    const SfxInterface* pIF,        // default = 0 means get virtually
484
    SfxItemSet*         pStateSet   // SfxItemSet of the Slot-State method
485
)
486
4.08k
{
487
    // Get Slot on the given Interface
488
4.08k
    if ( !pIF )
489
4.08k
        pIF = GetInterface();
490
4.08k
    SfxItemState eState(SfxItemState::DEFAULT);
491
4.08k
    bool bItemStateSet(false);
492
4.08k
    SfxItemPool &rPool = GetPool();
493
494
4.08k
    const SfxSlot* pSlot = nullptr;
495
4.08k
    if ( nSlotId >= SID_VERB_START && nSlotId <= SID_VERB_END )
496
0
        pSlot = GetVerbSlot_Impl(nSlotId);
497
4.08k
    if ( !pSlot )
498
4.08k
        pSlot = pIF->GetSlot(nSlotId);
499
4.08k
    if ( pSlot )
500
        // Map on Which-Id if possible
501
4.08k
        nSlotId = pSlot->GetWhich( rPool );
502
503
    // Get Item and Item status
504
4.08k
    const SfxPoolItem *pItem = nullptr;
505
4.08k
    SfxItemSet aSet( rPool, nSlotId, nSlotId ); // else pItem dies too soon
506
4.08k
    if ( nullptr != pSlot )
507
4.08k
    {
508
        // Call Status method
509
4.08k
        SfxStateFunc pFunc = pSlot->GetStateFnc();
510
4.08k
        if ( pFunc )
511
4.08k
            (*pFunc)( this, aSet );
512
4.08k
        eState = aSet.GetItemState( nSlotId, true, &pItem );
513
4.08k
        bItemStateSet = true;
514
515
        // get default Item if possible
516
4.08k
        if ( eState == SfxItemState::DEFAULT )
517
0
        {
518
0
            if ( SfxItemPool::IsWhich(nSlotId) )
519
0
                pItem = &rPool.GetUserOrPoolDefaultItem(nSlotId);
520
0
            else
521
0
                eState = SfxItemState::INVALID;
522
0
        }
523
4.08k
    }
524
525
    // Evaluate Item and item status and possibly maintain them in pStateSet
526
4.08k
    if ( !bItemStateSet || eState <= SfxItemState::DISABLED )
527
0
    {
528
0
        if ( pStateSet )
529
0
            pStateSet->DisableItem(nSlotId);
530
0
        return SfxPoolItemHolder();
531
0
    }
532
533
4.08k
    if ( bItemStateSet && eState == SfxItemState::INVALID )
534
0
    {
535
0
        if ( pStateSet )
536
0
            pStateSet->ClearItem(nSlotId);
537
0
        return SfxPoolItemHolder(rPool, DISABLED_POOL_ITEM);
538
0
    }
539
540
    // bItemStateSet && eState >= SfxItemState::DEFAULT
541
4.08k
    if ( pStateSet && pStateSet->Put( *pItem ) )
542
0
    {
543
0
        return SfxPoolItemHolder(rPool, &pStateSet->Get(pItem->Which()));
544
0
    }
545
546
4.08k
    return SfxPoolItemHolder(rPool, pItem);
547
4.08k
}
548
549
static SFX_EXEC_STUB(SfxShell, VerbExec)
550
static void SfxStubSfxShellVerbState(SfxShell *, SfxItemSet& rSet)
551
0
{
552
0
    SfxShell::VerbState( rSet );
553
0
}
554
555
void SfxShell::SetVerbs(const css::uno::Sequence < css::embed::VerbDescriptor >& aVerbs)
556
0
{
557
0
    SfxViewShell *pViewSh = dynamic_cast<SfxViewShell*>( this );
558
559
0
    DBG_ASSERT(pViewSh, "Only call SetVerbs at the ViewShell!");
560
0
    if ( !pViewSh )
561
0
        return;
562
563
    // First make all Statecaches dirty, so that no-one no longer tries to use
564
    // the Slots
565
0
    {
566
0
        SfxBindings *pBindings =
567
0
            pViewSh->GetViewFrame().GetDispatcher()->GetBindings();
568
0
        sal_uInt16 nCount = pImpl->aSlotArr.size();
569
0
        for (sal_uInt16 n1=0; n1<nCount ; n1++)
570
0
        {
571
0
            sal_uInt16 nId = SID_VERB_START + n1;
572
0
            pBindings->Invalidate(nId, false, true);
573
0
        }
574
0
    }
575
576
0
    sal_uInt16 nr=0;
577
0
    for (sal_Int32 n=0; n<aVerbs.getLength(); n++)
578
0
    {
579
0
        sal_uInt16 nSlotId = SID_VERB_START + nr++;
580
0
        DBG_ASSERT(nSlotId <= SID_VERB_END, "Too many Verbs!");
581
0
        if (nSlotId > SID_VERB_END)
582
0
            break;
583
584
0
        SfxSlot* pNewSlot = new SfxSlot{
585
0
            nSlotId, SfxGroupId::NONE,
586
            // Verb slots must be executed asynchronously, so that they can be
587
            // destroyed while executing.
588
0
            SfxSlotMode::ASYNCHRON | SfxSlotMode::CONTAINER,
589
0
            0, 0,
590
0
            SFX_STUB_PTR(SfxShell, VerbExec), SFX_STUB_PTR(SfxShell, VerbState),
591
0
            nullptr, // HACK(SFX_TYPE(SfxVoidItem)) ???
592
0
            nullptr, nullptr, 0, SfxDisableFlags::NONE, u""_ustr};
593
594
0
        if (!pImpl->aSlotArr.empty())
595
0
        {
596
0
            SfxSlot& rSlot = *pImpl->aSlotArr[0];
597
0
            pNewSlot->pNextSlot = rSlot.pNextSlot;
598
0
            rSlot.pNextSlot = pNewSlot;
599
0
        }
600
0
        else
601
0
            pNewSlot->pNextSlot = pNewSlot;
602
603
0
        pImpl->aSlotArr.insert(pImpl->aSlotArr.begin() + static_cast<sal_uInt16>(n), std::unique_ptr<SfxSlot>(pNewSlot));
604
0
    }
605
606
0
    pImpl->aVerbList = aVerbs;
607
608
    // The status of SID_OBJECT is collected in the controller directly on
609
    // the Shell, it is thus enough to encourage a new status update
610
0
    SfxBindings* pBindings = pViewSh->GetViewFrame().GetDispatcher()->GetBindings();
611
0
    pBindings->Invalidate(SID_OBJECT, true, true);
612
0
}
613
614
const css::uno::Sequence < css::embed::VerbDescriptor >& SfxShell::GetVerbs() const
615
0
{
616
0
    return pImpl->aVerbList;
617
0
}
618
619
void SfxShell::VerbExec(SfxRequest& rReq)
620
0
{
621
0
    sal_uInt16 nId = rReq.GetSlot();
622
0
    SfxViewShell *pViewShell = GetViewShell();
623
0
    if ( !pViewShell )
624
0
        return;
625
626
0
    bool bReadOnly = pViewShell->GetObjectShell()->IsReadOnly();
627
0
    const css::uno::Sequence < css::embed::VerbDescriptor > aList = pViewShell->GetVerbs();
628
0
    sal_Int32 nVerb = 0;
629
0
    for (const auto& rVerb : aList)
630
0
    {
631
        // check for ReadOnly verbs
632
0
        if ( bReadOnly && !(rVerb.VerbAttributes & embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES) )
633
0
            continue;
634
635
        // check for verbs that shouldn't appear in the menu
636
0
        if ( !(rVerb.VerbAttributes & embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU) )
637
0
            continue;
638
639
0
        if (nId == SID_VERB_START + nVerb++)
640
0
        {
641
0
            pViewShell->DoVerb(rVerb.VerbID);
642
0
            rReq.Done();
643
0
            return;
644
0
        }
645
0
    }
646
0
}
647
648
void SfxShell::VerbState(SfxItemSet& )
649
0
{
650
0
}
651
652
const SfxSlot* SfxShell::GetVerbSlot_Impl(sal_uInt16 nId) const
653
0
{
654
0
    css::uno::Sequence < css::embed::VerbDescriptor > rList = pImpl->aVerbList;
655
656
0
    DBG_ASSERT(nId >= SID_VERB_START && nId <= SID_VERB_END,"Wrong VerbId!");
657
0
    sal_uInt16 nIndex = nId - SID_VERB_START;
658
0
    DBG_ASSERT(nIndex < rList.getLength(),"Wrong VerbId!");
659
660
0
    if (nIndex < rList.getLength())
661
0
        return pImpl->aSlotArr[nIndex].get();
662
0
    else
663
0
        return nullptr;
664
0
}
665
666
SfxObjectShell* SfxShell::GetObjectShell()
667
20.4k
{
668
20.4k
    if ( GetViewShell() )
669
12.2k
        return GetViewShell()->GetViewFrame().GetObjectShell();
670
8.16k
    else
671
8.16k
        return nullptr;
672
20.4k
}
673
674
bool SfxShell::HasUIFeature(SfxShellFeature) const
675
0
{
676
0
    return false;
677
0
}
678
679
static void DispatcherUpdate_Impl( void*, void* pArg )
680
0
{
681
0
    static_cast<SfxDispatcher*>(pArg)->Update_Impl( true );
682
0
    static_cast<SfxDispatcher*>(pArg)->GetBindings()->InvalidateAll(false);
683
0
}
684
685
void SfxShell::UIFeatureChanged()
686
4.08k
{
687
4.08k
    SfxViewFrame *pFrame = GetFrame();
688
4.08k
    if ( pFrame && pFrame->IsVisible() )
689
4.08k
    {
690
        // Also force an update, if dispatcher is already updated otherwise
691
        // something may get stuck in the bunkered tools. Asynchronous call to
692
        // prevent recursion.
693
4.08k
        if ( !pImpl->pUpdater )
694
4.08k
            pImpl->pUpdater.reset( new svtools::AsynchronLink( LINK_NONMEMBER( this, DispatcherUpdate_Impl ) ) );
695
696
        // Multiple views allowed
697
4.08k
        pImpl->pUpdater->Call( pFrame->GetDispatcher(), true );
698
4.08k
    }
699
4.08k
}
700
701
void SfxShell::SetDisableFlags( SfxDisableFlags nFlags )
702
81.7k
{
703
81.7k
    pImpl->nDisableFlags = nFlags;
704
81.7k
}
705
706
SfxDisableFlags SfxShell::GetDisableFlags() const
707
0
{
708
0
    return pImpl->nDisableFlags;
709
0
}
710
711
std::optional<SfxItemSet> SfxShell::CreateItemSet( sal_uInt16 )
712
0
{
713
0
    return {};
714
0
}
715
716
void SfxShell::ApplyItemSet( sal_uInt16, const SfxItemSet& )
717
0
{
718
0
}
719
720
void SfxShell::SetContextName (const OUString& rsContextName)
721
4.09k
{
722
4.09k
    pImpl->maContextChangeBroadcaster.Initialize(rsContextName);
723
4.09k
}
724
725
void SfxShell::SetViewShell_Impl( SfxViewShell* pView )
726
20.4k
{
727
20.4k
    pImpl->pViewSh = pView;
728
20.4k
}
729
730
void SfxShell::BroadcastContextForActivation (const bool bIsActivated)
731
53.1k
{
732
    // Avoids activation and de-activation (can be seen on switching view) from causing
733
    // the sidebar to re-build. Such switching can happen as we change view to render
734
    // using LOK for example, and is un-necessary for Online.
735
53.1k
    if (comphelper::LibreOfficeKit::isDialogPainting())
736
0
        return;
737
738
53.1k
    SfxViewFrame* pViewFrame = GetFrame();
739
53.1k
    if (pViewFrame != nullptr)
740
40.8k
    {
741
40.8k
        if (bIsActivated)
742
24.5k
            pImpl->maContextChangeBroadcaster.Activate(pViewFrame->GetFrame().GetFrameInterface());
743
16.3k
        else
744
16.3k
            pImpl->maContextChangeBroadcaster.Deactivate(pViewFrame->GetFrame().GetFrameInterface());
745
40.8k
    }
746
53.1k
}
747
748
bool SfxShell::SetContextBroadcasterEnabled (const bool bIsEnabled)
749
0
{
750
0
    return pImpl->maContextChangeBroadcaster.SetBroadcasterEnabled(bIsEnabled);
751
0
}
752
753
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */