Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/control/dispatch.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 <config_feature_desktop.h>
21
22
#include <algorithm>
23
#include <cstddef>
24
#include <deque>
25
#include <vector>
26
27
#include <stdlib.h>
28
29
#include <boost/property_tree/json_parser.hpp>
30
31
#include <com/sun/star/awt/PopupMenuDirection.hpp>
32
#include <com/sun/star/beans/XPropertySet.hpp>
33
#include <com/sun/star/frame/XDispatchRecorderSupplier.hpp>
34
#include <com/sun/star/frame/XLayoutManager.hpp>
35
#include <com/sun/star/frame/XPopupMenuController.hpp>
36
#include <com/sun/star/uno/XComponentContext.hpp>
37
#include <com/sun/star/ui/ContextMenuExecuteEvent.hpp>
38
39
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
40
#include <comphelper/lok.hxx>
41
#include <comphelper/processfactory.hxx>
42
#include <comphelper/propertyvalue.hxx>
43
#include <config_vclplug.h>
44
#include <officecfg/Office/Common.hxx>
45
#include <rtl/strbuf.hxx>
46
#include <sal/log.hxx>
47
#include <sfx2/app.hxx>
48
#include <sfx2/bindings.hxx>
49
#include <sfx2/chalign.hxx>
50
#include <sfx2/childwin.hxx>
51
#include <sfx2/dispatch.hxx>
52
#include <sfx2/docfile.hxx>
53
#include <hintpost.hxx>
54
#include <sfx2/ipclient.hxx>
55
#include <sfx2/module.hxx>
56
#include <sfx2/msg.hxx>
57
#include <sfx2/msgpool.hxx>
58
#include <sfx2/objface.hxx>
59
#include <sfx2/request.hxx>
60
#include <sfx2/sfxsids.hrc>
61
#include <sfx2/viewfrm.hxx>
62
#include <sfx2/viewsh.hxx>
63
#include <svl/eitem.hxx>
64
#include <svl/itemiter.hxx>
65
#include <svl/itempool.hxx>
66
#include <toolkit/awt/vclxmenu.hxx>
67
#include <toolkit/helper/vclunohelper.hxx>
68
#include <tools/debug.hxx>
69
#include <tools/mapunit.hxx>
70
#include <vcl/idle.hxx>
71
#include <vcl/menu.hxx>
72
73
#include <sfxtypes.hxx>
74
#include <slotserv.hxx>
75
#include <workwin.hxx>
76
77
typedef std::vector<SfxShell*> SfxShellStack_Impl;
78
79
namespace {
80
81
struct SfxToDo_Impl
82
{
83
    SfxShell*  pCluster;
84
    bool       bPush;
85
    bool       bDelete;
86
    bool       bDeleted;
87
    bool       bUntil;
88
89
    SfxToDo_Impl( bool bOpPush, bool bOpDelete, bool bOpUntil, SfxShell& rCluster )
90
148k
        : pCluster(&rCluster)
91
148k
        , bPush(bOpPush)
92
148k
        , bDelete(bOpDelete)
93
148k
        , bDeleted(false)
94
148k
        , bUntil(bOpUntil)
95
148k
                {}
96
};
97
98
struct SfxObjectBars_Impl
99
{
100
    ToolbarId          eId;      // ConfigId of the Toolbox
101
    sal_uInt16         nPos;
102
    SfxVisibilityFlags nFlags;   // special visibility flags
103
104
224k
    SfxObjectBars_Impl() : eId(ToolbarId::None), nPos(0), nFlags(SfxVisibilityFlags::Invisible) {}
105
};
106
107
}
108
109
struct SfxDispatcher_Impl
110
{
111
    //When the dispatched is locked, SfxRequests accumulate in aReqArr for
112
    //later dispatch when unlocked via Post
113
114
    //The pointers are typically deleted in Post, only if we never get around
115
    //to posting them do we delete the unposted requests.
116
    std::vector<std::unique_ptr<SfxRequest>>
117
                         aReqArr;
118
    SfxShellStack_Impl   aStack;        // active functionality
119
    Idle                 aIdle { "sfx::SfxDispatcher_Impl aIdle" }; // for Flush
120
    std::deque<SfxToDo_Impl> aToDoStack;    // not processed Push/Pop
121
    SfxViewFrame*        pFrame;        // NULL or associated Frame
122
    tools::SvRef<SfxHintPoster>
123
                         xPoster;       // Execute asynchronous
124
    bool                 bFlushing;     // sal_True during Flush //?
125
    bool                 bUpdated;      // Update_Impl has run
126
    bool                 bLocked;       // No Execute
127
    bool                 bInvalidateOnUnlock;   // because someone asked
128
    bool                 bActive;       // not to be confused with set!
129
    bool*                pInCallAliveFlag;   // view the Destructor Stack
130
    SfxObjectBars_Impl   aObjBars[SFX_OBJECTBAR_MAX];
131
    SfxObjectBars_Impl   aFixedObjBars[SFX_OBJECTBAR_MAX];
132
    std::vector<sal_uInt32> aChildWins;
133
    bool                 bNoUI;         // UI only from Parent Dispatcher
134
    bool                 bReadOnly;     // Document is ReadOnly
135
    bool                 bQuiet;        // Only use parent dispatcher
136
137
    SfxSlotFilterState   nFilterEnabling; // 1==filter enabled slots,
138
                                          // 2==ReadOnlyDoc overturned
139
    std::span<sal_uInt16 const>
140
                         pFilterSIDs;   // sorted Array of SIDs
141
    SfxDisableFlags      nDisableFlags;
142
    bool                 bFlushed;
143
    std::deque< std::deque<SfxToDo_Impl> > aToDoCopyStack;
144
};
145
146
/** This method checks if the stack of the SfxDispatchers is flushed, or if
147
    push- or pop- commands are pending.
148
*/
149
bool SfxDispatcher::IsFlushed() const
150
0
{
151
0
     return xImp->bFlushed;
152
0
}
153
154
/** This method performs outstanding push- and pop- commands. For <SfxShell>s,
155
    which are new on the stack, the <SfxShell::Activate(bool)> is invoked
156
    with bMDI == sal_True, for SfxShells that are removed from the stack, the
157
    <SfxShell::Deactivate(bool)> is invoked with bMDI == sal_True
158
*/
159
void SfxDispatcher::Flush()
160
130k
{
161
130k
    if (!xImp->bFlushed) FlushImpl();
162
130k
}
163
164
/** With this method, a <SfxShell> pushed on to the SfxDispatcher.
165
    The SfxShell is first marked for push and a timer is set up.
166
    First when the timer has counted down to zero the push
167
    ( <SfxDispatcher::Flush()> ) is actually performed and the
168
    <SfxBindings> is invalidated. While the timer is counting down
169
    the opposing push and pop commands on the same SfxShell are
170
    leveled out.
171
*/
172
void SfxDispatcher::Push(SfxShell& rShell)
173
174
69.7k
{
175
69.7k
    Pop( rShell, SfxDispatcherPopFlags::PUSH );
176
69.7k
}
177
178
/** This method checks whether a particular <SfxShell> instance is
179
    on the SfxDispatcher.
180
181
    @returns true   The SfxShell instance is on the SfxDispatcher.
182
             false  The SfxShell instance is not on the SfxDispatcher.
183
*/
184
bool SfxDispatcher::IsActive(const SfxShell& rShell)
185
186
0
{
187
0
    return CheckVirtualStack(rShell);
188
0
}
189
190
/** With this method it can be determined whether the SfxDispatcher is
191
    locked or unlocked. A locked SfxDispatcher does not perform <SfxRequest>s
192
    and no longer provides any status information. It behaves as if all the
193
    slots are disabled.
194
195
    The dispatcher is also marked as blocked, if all Dispatcher are locked
196
    (<SfxApplication::LockDispatcher()>) or the associated top frame is in the
197
    modal-mode and if the specified slot are handled as frame-specific
198
    (ie, not served by the application).
199
*/
200
bool SfxDispatcher::IsLocked() const
201
59.7k
{
202
59.7k
    return xImp->bLocked;
203
59.7k
}
204
205
/** With this method it can be determined if the SfxDispacher is the
206
    applications dispatcher.
207
208
    @return bool it is the application dispatcher.
209
*/
210
bool SfxDispatcher::IsAppDispatcher() const
211
69.0k
{
212
69.0k
    return !xImp->pFrame;
213
69.0k
}
214
215
/** Helper function to check whether a slot can be executed and
216
    check the execution itself
217
*/
218
void SfxDispatcher::Call_Impl(SfxShell& rShell, const SfxSlot &rSlot, SfxRequest &rReq, bool bRecord)
219
0
{
220
0
    SFX_STACK(SfxDispatcher::Call_Impl);
221
222
    // The slot may be called (meaning enabled)
223
0
    if ( !rSlot.IsMode(SfxSlotMode::FASTCALL) && !rShell.CanExecuteSlot_Impl(rSlot) && !rShell.IsConditionalFastCall(rReq) )
224
0
        return;
225
226
0
    if ( GetFrame() )
227
0
    {
228
        // Recording may start
229
0
        css::uno::Reference< css::beans::XPropertySet > xSet(
230
0
                GetFrame()->GetFrame().GetFrameInterface(),
231
0
                css::uno::UNO_QUERY);
232
233
0
        if ( xSet.is() )
234
0
        {
235
0
            css::uno::Any aProp = xSet->getPropertyValue(u"DispatchRecorderSupplier"_ustr);
236
0
            css::uno::Reference< css::frame::XDispatchRecorderSupplier > xSupplier;
237
0
            css::uno::Reference< css::frame::XDispatchRecorder > xRecorder;
238
0
            aProp >>= xSupplier;
239
0
            if(xSupplier.is())
240
0
                xRecorder = xSupplier->getDispatchRecorder();
241
242
0
            if ( bRecord && xRecorder.is() && !rSlot.IsMode(SfxSlotMode::NORECORD) )
243
0
                rReq.Record_Impl( rShell, rSlot, xRecorder, GetFrame() );
244
0
        }
245
0
    }
246
    // Get all that is needed, because the slot may not have survived the
247
    // Execute if it is a 'pseudo slot' for macros or verbs.
248
0
    bool bAutoUpdate = rSlot.IsMode(SfxSlotMode::AUTOUPDATE);
249
250
    // API-call parentheses and document-lock during the calls
251
0
    {
252
        // 'this' must respond in the Destructor
253
0
        bool bThisDispatcherAlive = true;
254
0
        bool *pOldInCallAliveFlag = xImp->pInCallAliveFlag;
255
0
        xImp->pInCallAliveFlag = &bThisDispatcherAlive;
256
257
0
        SfxExecFunc pFunc = rSlot.GetExecFnc();
258
0
        (*pFunc)(&rShell, rReq);
259
260
        // If 'this' is still alive
261
0
        if ( bThisDispatcherAlive )
262
0
            xImp->pInCallAliveFlag = pOldInCallAliveFlag;
263
0
        else
264
0
        {
265
0
            if ( pOldInCallAliveFlag )
266
0
            {
267
                // also protect nested stack frames
268
0
                *pOldInCallAliveFlag = false;
269
0
            }
270
271
            // do nothing after this object is dead
272
0
            return;
273
0
        }
274
0
    }
275
276
0
    if ( rReq.IsDone() )
277
0
    {
278
0
        SfxBindings *pBindings = GetBindings();
279
280
        // When AutoUpdate update immediately
281
0
        if ( bAutoUpdate && pBindings )
282
0
        {
283
0
            pBindings->Invalidate(rSlot.GetSlotId());
284
0
            pBindings->Update(rSlot.GetSlotId());
285
0
        }
286
0
    }
287
0
}
288
289
void SfxDispatcher::Construct_Impl()
290
8.63k
{
291
8.63k
    xImp.reset(new SfxDispatcher_Impl);
292
8.63k
    xImp->bFlushed = true;
293
294
8.63k
    xImp->bFlushing = false;
295
8.63k
    xImp->bUpdated = false;
296
8.63k
    xImp->bLocked = false;
297
8.63k
    xImp->bActive = false;
298
8.63k
    xImp->bNoUI = false;
299
8.63k
    xImp->bReadOnly = false;
300
8.63k
    xImp->bQuiet = false;
301
8.63k
    xImp->pInCallAliveFlag = nullptr;
302
8.63k
    xImp->nFilterEnabling = SfxSlotFilterState::DISABLED;
303
8.63k
    xImp->nDisableFlags = SfxDisableFlags::NONE;
304
305
8.63k
    xImp->bInvalidateOnUnlock = false;
306
307
8.63k
    for (SfxObjectBars_Impl & rObjBar : xImp->aObjBars)
308
112k
        rObjBar.eId = ToolbarId::None;
309
310
8.63k
    xImp->xPoster = new SfxHintPoster(this);
311
312
8.63k
    xImp->aIdle.SetPriority(TaskPriority::HIGH_IDLE );
313
8.63k
    xImp->aIdle.SetInvokeHandler( LINK(this, SfxDispatcher, EventHdl_Impl ) );
314
8.63k
}
315
316
SfxDispatcher::SfxDispatcher()
317
21
{
318
21
    Construct_Impl();
319
21
    xImp->pFrame = nullptr;
320
21
}
321
322
/** The constructor of the SfxDispatcher class places a stack of empty
323
    <SfxShell> pointers. It is not initially locked and is considered flushed.
324
*/
325
SfxDispatcher::SfxDispatcher(SfxViewFrame *pViewFrame)
326
8.61k
{
327
8.61k
    Construct_Impl();
328
8.61k
    xImp->pFrame = pViewFrame;
329
8.61k
}
330
331
/** The destructor of the SfxDispatcher class should not be called when the
332
    SfxDispatcher instance is active. It may, however, still be a <SfxShell>
333
    pointer on the stack.
334
*/
335
SfxDispatcher::~SfxDispatcher()
336
8.61k
{
337
8.61k
    SAL_INFO("sfx.control", "Delete Dispatcher " << reinterpret_cast<sal_Int64>(this));
338
8.61k
    DBG_ASSERT( !xImp->bActive, "deleting active Dispatcher" );
339
340
    // So that no timer by Reschedule in PlugComm strikes the LeaveRegistrations
341
8.61k
    xImp->aIdle.Stop();
342
8.61k
    xImp->xPoster->ClearLink();
343
344
    // Notify the stack variables in Call_Impl
345
8.61k
    if ( xImp->pInCallAliveFlag )
346
0
        *xImp->pInCallAliveFlag = false;
347
348
    // Get bindings and application
349
8.61k
    SfxApplication *pSfxApp = SfxGetpApp();
350
8.61k
    SfxBindings* pBindings = GetBindings();
351
352
    // When not flushed, revive the bindings
353
8.61k
    if (pBindings && !pSfxApp->IsDowning() && !xImp->bFlushed)
354
8.61k
        pBindings->DLEAVEREGISTRATIONS();
355
356
    // may unregister the bindings
357
17.2k
    while ( pBindings )
358
8.61k
    {
359
8.61k
        if ( pBindings->GetDispatcher_Impl() == this)
360
8.61k
            pBindings->SetDispatcher(nullptr);
361
8.61k
        pBindings = pBindings->GetSubBindings_Impl();
362
8.61k
    }
363
8.61k
}
364
365
/** With this method, one or more <SfxShell> are popped from the SfxDispatcher.
366
    The SfxShell is marked for popping and a timer is set up. Only when the
367
    timer has reached the end, the pop is actually performed
368
    ( <SfxDispatcher::Flush()> ) and the <SfxBindings> is invalidated.
369
    While the timer is running the opposing push and pop commands on one
370
    SfxShell cancel each other out.
371
372
    @param rShell the stack to take the SfxShell instance.
373
    @param nMode SfxDispatcherPopFlags::POP_UNTIL
374
                            Also all 'rShell' of SfxShells are taken from the
375
                            stack.
376
377
                 SfxDispatcherPopFlags::POP_DELETE
378
                            All SfxShells actually taken from the stack
379
                            will be deleted.
380
381
                 SfxDispatcherPopFlags::PUSH (InPlace use only)
382
                            The Shell is pushed.
383
*/
384
void SfxDispatcher::Pop(SfxShell& rShell, SfxDispatcherPopFlags nMode)
385
104k
{
386
104k
    DBG_ASSERT( rShell.GetInterface(),
387
104k
                "pushing SfxShell without previous RegisterInterface()" );
388
389
104k
    bool bDelete = bool(nMode & SfxDispatcherPopFlags::POP_DELETE);
390
104k
    bool bUntil = bool(nMode & SfxDispatcherPopFlags::POP_UNTIL);
391
104k
    bool bPush = bool(nMode & SfxDispatcherPopFlags::PUSH);
392
393
104k
    SfxApplication *pSfxApp = SfxGetpApp();
394
395
104k
    SAL_INFO(
396
104k
        "sfx.control",
397
104k
        "-SfxDispatcher(" << this << (bPush ? ")::Push(" : ")::Pop(")
398
104k
            << (rShell.GetInterface()
399
104k
                ? rShell.GetInterface()->GetClassName() : SAL_STREAM(&rShell))
400
104k
            << (bDelete ? ") with delete" : ")")
401
104k
            << (bUntil ? " (up to)" : ""));
402
403
    // same shell as on top of the to-do stack?
404
104k
    if(!xImp->aToDoStack.empty() && xImp->aToDoStack.front().pCluster == &rShell)
405
110
    {
406
        // cancel inverse actions
407
110
        if ( xImp->aToDoStack.front().bPush != bPush )
408
110
            xImp->aToDoStack.pop_front();
409
0
        else
410
0
        {
411
0
            DBG_ASSERT( bPush, "SfxInterface pushed more than once" );
412
0
            DBG_ASSERT( !bPush, "SfxInterface popped more than once" );
413
0
        }
414
110
    }
415
104k
    else
416
104k
    {
417
        // Remember Action
418
104k
        xImp->aToDoStack.push_front( SfxToDo_Impl(bPush, bDelete, bUntil, rShell) );
419
104k
        if (xImp->bFlushed)
420
51.8k
        {
421
51.8k
            SAL_INFO("sfx.control", "Unflushed dispatcher!");
422
51.8k
            xImp->bFlushed = false;
423
51.8k
            xImp->bUpdated = false;
424
425
            // Put bindings to sleep
426
51.8k
            SfxBindings* pBindings = GetBindings();
427
51.8k
            if ( pBindings )
428
51.8k
                pBindings->DENTERREGISTRATIONS();
429
51.8k
        }
430
104k
    }
431
432
104k
    if(!pSfxApp->IsDowning() && !xImp->aToDoStack.empty())
433
104k
    {
434
        // No immediate update is requested
435
104k
        xImp->aIdle.Start();
436
104k
    }
437
0
    else
438
0
    {
439
        // but to do nothing
440
0
        xImp->aIdle.Stop();
441
442
        // Bindings may wake up again
443
0
        if(xImp->aToDoStack.empty())
444
0
        {
445
0
            SfxBindings* pBindings = GetBindings();
446
0
            if ( pBindings )
447
0
                pBindings->DLEAVEREGISTRATIONS();
448
0
        }
449
0
    }
450
104k
}
451
452
453
/** This handler is called after <SfxDispatcher::Invalidate()> or after
454
    changes on the stack (<SfxDispatcher::Push()> and <SfxDispatcher::Pop())
455
456
    It flushes the Stack, if it is dirty, thus it actually executes the
457
    pending Push and Pop commands.
458
*/
459
IMPL_LINK_NOARG( SfxDispatcher, EventHdl_Impl, Timer *, void )
460
0
{
461
0
    Flush();
462
0
    Update_Impl();
463
0
    SfxBindings* pBindings = GetBindings();
464
0
    if ( pBindings )
465
0
        pBindings->StartUpdate_Impl();
466
0
}
467
468
/** With this method it can be tested whether the <SfxShell> rShell is on the
469
    stack, when it was flushed. This way the SfxDispatcher is not actually
470
    flushed.
471
472
    This method is intended among other things to make assertions possible
473
    without the side effect of having to flush the SfxDispatcher.
474
*/
475
bool SfxDispatcher::CheckVirtualStack(const SfxShell& rShell)
476
0
{
477
0
    SFX_STACK(SfxDispatcher::CheckVirtualStack);
478
479
0
    SfxShellStack_Impl aStack( xImp->aStack );
480
0
    for(std::deque<SfxToDo_Impl>::reverse_iterator i = xImp->aToDoStack.rbegin(); i != xImp->aToDoStack.rend(); ++i)
481
0
    {
482
0
        if(i->bPush)
483
0
            aStack.push_back(i->pCluster);
484
0
        else
485
0
        {
486
0
            SfxShell* pPopped(nullptr);
487
0
            do
488
0
            {
489
0
                DBG_ASSERT( !aStack.empty(), "popping from empty stack" );
490
0
                pPopped = aStack.back();
491
0
                aStack.pop_back();
492
0
            }
493
0
            while(i->bUntil && pPopped != i->pCluster);
494
0
            DBG_ASSERT(pPopped == i->pCluster, "popping unpushed SfxInterface");
495
0
        }
496
0
    }
497
498
0
    bool bReturn = std::find(aStack.begin(), aStack.end(), &rShell) != aStack.end();
499
0
    return bReturn;
500
0
}
501
502
/** Determines the position of a given SfxShell in the stack of the dispatcher.
503
    If possible this is flushed before.
504
505
    [Return value]
506
507
    sal_uInt16                  == USRT_MAX
508
                                The SfxShell is not on this SfxDispatcher.
509
510
                                < USHRT_MAX
511
                                Position of the SfxShell on the Dispatcher
512
                                from the top count stating with 0.
513
*/
514
sal_uInt16 SfxDispatcher::GetShellLevel(const SfxShell& rShell)
515
8.61k
{
516
8.61k
    SFX_STACK(SfxDispatcher::GetShellLevel);
517
8.61k
    Flush();
518
519
34.8k
    for ( size_t n = 0; n < xImp->aStack.size(); ++n )
520
34.8k
        if ( *( xImp->aStack.rbegin() + n ) == &rShell )
521
8.61k
            return n;
522
523
0
    return USHRT_MAX;
524
8.61k
}
525
526
/** Returns a pointer to the <SfxShell> which is at the position nIdx
527
    (from the top, last pushed is 0) on the stack.
528
529
    Thus the SfxDispatcher is not flushed.
530
531
    Is the stack not deep enough a NULL-Pointer is returned.
532
*/
533
SfxShell *SfxDispatcher::GetShell(sal_uInt16 nIdx) const
534
176k
{
535
176k
    sal_uInt16 nShellCount = xImp->aStack.size();
536
176k
    if ( nIdx < nShellCount )
537
176k
        return *(xImp->aStack.rbegin() + nIdx);
538
0
    return nullptr;
539
176k
}
540
541
/** This method returns a pointer to the <SfxBinding> Instance on which the
542
    SfxDispatcher is currently bound. A SfxDispatcher is only bound to
543
    the SfxBindings when it is <UI-aktiv>. If it is not UI-active,
544
    a NULL-pointer is returned.
545
546
    The returned pointer is only valid in the immediate context of the method
547
    call.
548
*/
549
SfxBindings* SfxDispatcher::GetBindings() const
550
328k
{
551
328k
    if ( xImp->pFrame )
552
328k
        return &xImp->pFrame->GetBindings();
553
63
    else
554
63
        return nullptr;
555
328k
}
556
557
/** Returns a pointer to the <SfxViewFrame> instance, which belongs to
558
    this SfxDispatcher. If it is about the application dispatcher,
559
    a NULL-pointer is returned.
560
*/
561
SfxViewFrame* SfxDispatcher::GetFrame() const
562
416k
{
563
416k
    return xImp->pFrame;
564
416k
}
565
566
/** This method controls the activation of a dispatcher.
567
568
    Since the application dispatcher is always active, either as a sub
569
    dispatcher of the <SfxViewFrame> dispatcher or as itself, it is never
570
    activated as a whole, instead only its individual <SfxShell>s at
571
    <SfxDispatcher::Push(SfxShell&)>.
572
573
    When activating a SfxDispatcher all of the SfxShells located on its stack
574
    are called with the handler <SfxShell::Activate(bool)>, starting with
575
    the lowest.
576
*/
577
void SfxDispatcher::DoActivate_Impl(bool bMDI)
578
8.63k
{
579
8.63k
    SFX_STACK(SfxDispatcher::DoActivate);
580
8.63k
    if ( bMDI )
581
8.63k
    {
582
8.63k
        SAL_INFO("sfx.control", "Activate Dispatcher " << reinterpret_cast<sal_Int64>(this));
583
8.63k
        DBG_ASSERT( !xImp->bActive, "Activation error" );
584
585
8.63k
        xImp->bActive = true;
586
8.63k
        xImp->bUpdated = false;
587
8.63k
        SfxBindings* pBindings = GetBindings();
588
8.63k
        if ( pBindings )
589
8.61k
        {
590
8.61k
            pBindings->SetDispatcher(this);
591
8.61k
            pBindings->SetActiveFrame( xImp->pFrame->GetFrame().GetFrameInterface() );
592
8.61k
        }
593
8.63k
    }
594
0
    else
595
0
    {
596
0
        SAL_INFO("sfx.control", "Non-MDI-Activate Dispatcher " << reinterpret_cast<sal_Int64>(this));
597
0
    }
598
599
8.63k
    if ( IsAppDispatcher() )
600
21
        return;
601
602
51.7k
    for ( int i = int(xImp->aStack.size()) - 1; i >= 0; --i )
603
43.0k
        (*(xImp->aStack.rbegin() + i ))->DoActivate_Impl(xImp->pFrame, bMDI);
604
605
8.61k
    if ( bMDI && xImp->pFrame )
606
8.61k
    {
607
8.61k
        xImp->pFrame->GetFrame().GetWorkWindow_Impl()->HidePopups_Impl( false, 1 );
608
8.61k
    }
609
610
8.61k
    if(!xImp->aToDoStack.empty())
611
0
    {
612
        // No immediate update is requested
613
0
        xImp->aIdle.Start();
614
0
    }
615
8.61k
}
616
617
/** This method controls the deactivation of a dispatcher.
618
619
    Since the application dispatcher is always active, either as a sub
620
    dispatcher of the <SfxViewFrame> dispatcher or as itself, it is never
621
    deactivated as a whole, instead only its individual <SfxShell>s at
622
    <SfxDispatcher::Pop(SfxShell&)>.
623
624
    When deactivating a SfxDispatcher all of the SfxShells located on its stack
625
    are called with the handler <SfxShell::Deactivate(bool)>, starting with
626
    the lowest.
627
*/
628
void SfxDispatcher::DoDeactivate_Impl(bool bMDI, SfxViewFrame const * pNew)
629
8.61k
{
630
8.61k
    SFX_STACK(SfxDispatcher::DoDeactivate);
631
632
8.61k
    SfxApplication *pSfxApp = SfxGetpApp();
633
634
8.61k
    if ( bMDI )
635
8.61k
    {
636
8.61k
        SAL_INFO("sfx.control", "Deactivate Dispatcher " << this);
637
8.61k
        DBG_ASSERT( xImp->bActive, "Deactivate error" );
638
8.61k
        xImp->bActive = false;
639
640
8.61k
        if ( xImp->pFrame && !(xImp->pFrame->GetObjectShell()->IsInPlaceActive() ) )
641
8.61k
        {
642
8.61k
            SfxWorkWindow *pWorkWin = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
643
8.61k
            if ( pWorkWin )
644
8.61k
            {
645
319k
                for (size_t n=0; n<xImp->aChildWins.size();)
646
311k
                {
647
311k
                    SfxChildWindow *pWin = pWorkWin->GetChildWindow_Impl( static_cast<sal_uInt16>( xImp->aChildWins[n] & 0xFFFF ) );
648
311k
                    if (!pWin || pWin->GetAlignment() == SfxChildAlignment::NOALIGNMENT)
649
311k
                        xImp->aChildWins.erase(xImp->aChildWins.begin()+n);
650
0
                    else
651
0
                        n++;
652
311k
                }
653
8.61k
            }
654
8.61k
        }
655
8.61k
    }
656
0
    else {
657
0
        SAL_INFO("sfx.control", "Non-MDI-DeActivate Dispatcher " << this);
658
0
    }
659
660
8.61k
    if ( IsAppDispatcher() && !pSfxApp->IsDowning() )
661
0
        return;
662
663
77.9k
    for ( size_t i = 0; i < xImp->aStack.size(); ++i )
664
69.3k
        (*(xImp->aStack.rbegin() + i))->DoDeactivate_Impl(xImp->pFrame, bMDI);
665
666
8.61k
    bool bHidePopups = bMDI && xImp->pFrame;
667
8.61k
    if ( pNew && xImp->pFrame )
668
0
    {
669
0
        css::uno::Reference< css::frame::XFrame > xOldFrame =
670
0
            pNew->GetFrame().GetFrameInterface()->getCreator();
671
672
0
        css::uno::Reference< css::frame::XFrame > xMyFrame =
673
0
            GetFrame()->GetFrame().GetFrameInterface();
674
675
0
        if ( xOldFrame == xMyFrame )
676
0
            bHidePopups = false;
677
0
    }
678
679
8.61k
    if ( bHidePopups )
680
8.61k
    {
681
8.61k
        xImp->pFrame->GetFrame().GetWorkWindow_Impl()->HidePopups_Impl( true, 1 );
682
8.61k
    }
683
684
8.61k
    Flush();
685
8.61k
}
686
687
/** This method searches in SfxDispatcher after <SfxShell> , from the Slot Id
688
    nSlot currently being handled. For this, the dispatcher is first flushed.
689
690
    @param nSlot the searchable Slot-Id
691
    @param ppShell the SfxShell, which are currently handled the nSlot
692
    @param ppSlot the SfxSlot, which are currently handled the nSlot
693
694
    @return int      sal_True
695
                     The SfxShell was found, ppShell and ppSlot are valid.
696
697
                     sal_False
698
                     The SfxShell was not found, ppShell and ppSlot are invalid.
699
*/
700
bool SfxDispatcher::GetShellAndSlot_Impl(sal_uInt16 nSlot, SfxShell** ppShell,
701
        const SfxSlot** ppSlot, bool bOwnShellsOnly, bool bRealSlot)
702
8.61k
{
703
8.61k
    SFX_STACK(SfxDispatcher::GetShellAndSlot_Impl);
704
705
8.61k
    Flush();
706
8.61k
    SfxSlotServer aSvr;
707
8.61k
    if ( FindServer_(nSlot, aSvr) )
708
8.61k
    {
709
8.61k
        if ( bOwnShellsOnly && aSvr.GetShellLevel() >= xImp->aStack.size() )
710
0
            return false;
711
712
8.61k
        *ppShell = GetShell(aSvr.GetShellLevel());
713
8.61k
        *ppSlot = aSvr.GetSlot();
714
8.61k
        if ( nullptr == (*ppSlot)->GetExecFnc() && bRealSlot && *ppShell )
715
0
            *ppSlot = (*ppShell)->GetInterface()->GetRealSlot(*ppSlot);
716
        // Check only real slots as enum slots don't have an execute function!
717
8.61k
        return !bRealSlot || ((nullptr != *ppSlot) && (nullptr != (*ppSlot)->GetExecFnc()) );
718
8.61k
    }
719
720
0
    return false;
721
8.61k
}
722
723
/** This method performs a request for a cached <Slot-Server>.
724
725
    @param rShell to the calling <SfxShell>
726
    @param rSlot to the calling <SfxSlot>
727
    @param rReq function to be performed (Id and optional parameters)
728
    @param eCallMode Synchronously, asynchronously or as shown in the slot
729
*/
730
void SfxDispatcher::Execute_(SfxShell& rShell, const SfxSlot& rSlot,
731
        SfxRequest& rReq, SfxCallMode eCallMode)
732
0
{
733
0
    SFX_STACK(SfxDispatcher::Execute_);
734
0
    DBG_ASSERT( !xImp->bFlushing, "recursive call to dispatcher" );
735
0
    DBG_ASSERT( xImp->aToDoStack.empty(), "unprepared InPlace _Execute" );
736
737
0
    if ( IsLocked() )
738
0
        return;
739
740
0
    if ( bool(eCallMode & SfxCallMode::ASYNCHRON) ||
741
0
         ( (eCallMode & SfxCallMode::SYNCHRON) == SfxCallMode::SLOT &&
742
0
           rSlot.IsMode(SfxSlotMode::ASYNCHRON) ) )
743
0
    {
744
0
        sal_uInt16 nShellCount = xImp->aStack.size();
745
0
        for ( sal_uInt16 n=0; n<nShellCount; n++ )
746
0
        {
747
0
            if ( &rShell == *(xImp->aStack.rbegin() + n) )
748
0
            {
749
0
                if ( bool(eCallMode & SfxCallMode::RECORD) )
750
0
                    rReq.AllowRecording( true );
751
0
                xImp->xPoster->Post(std::make_unique<SfxRequest>(rReq));
752
0
                return;
753
0
            }
754
0
        }
755
0
    }
756
0
    else
757
0
        Call_Impl( rShell, rSlot, rReq, SfxCallMode::RECORD==(eCallMode&SfxCallMode::RECORD) );
758
0
}
759
760
/** Helper function to put from rItem below the Which-ID in the pool of the
761
    Item Sets rSet.
762
*/
763
static void MappedPut_Impl(SfxAllItemSet &rSet, const SfxPoolItem &rItem)
764
0
{
765
    // Put with mapped Which-Id if needed
766
0
    if (SfxItemPool::IsSlot(rItem.Which()))
767
0
        rSet.PutAsTargetWhich(rItem, rSet.GetPool()->GetWhichIDFromSlotID(rItem.Which()));
768
0
    else
769
0
        rSet.Put(rItem);
770
0
}
771
772
const SfxSlot* SfxDispatcher::GetSlot( const OUString& rCommand )
773
0
{
774
    // Count the number of Shells on the linked Dispatcher
775
0
    Flush();
776
0
    sal_uInt16 nTotCount = xImp->aStack.size();
777
778
0
    for ( sal_uInt16 i = 0; i < nTotCount; ++i )
779
0
    {
780
0
        if (SfxShell *pObjShell = GetShell(i))
781
0
        {
782
0
            SfxInterface *pIFace = pObjShell->GetInterface();
783
0
            const SfxSlot *pSlot = pIFace->GetSlot( rCommand );
784
0
            if ( pSlot )
785
0
                return pSlot;
786
0
        }
787
0
    }
788
789
0
    return nullptr;
790
0
}
791
792
SfxPoolItemHolder SfxDispatcher::Execute(sal_uInt16 nSlot, SfxCallMode nCall,
793
        SfxItemSet const * pArgs, SfxItemSet const * pInternalArgs, sal_uInt16 nModi)
794
0
{
795
0
    if ( IsLocked() )
796
0
        return SfxPoolItemHolder();
797
798
0
    SfxShell *pShell = nullptr;
799
0
    const SfxSlot *pSlot = nullptr;
800
0
    if ( GetShellAndSlot_Impl( nSlot,  &pShell, &pSlot, false, true ) )
801
0
    {
802
0
        SfxAllItemSet aSet( pShell->GetPool() );
803
0
        if ( pArgs )
804
0
        {
805
0
            for (SfxItemIter aIter( *pArgs ); !aIter.IsAtEnd(); aIter.Next())
806
0
                MappedPut_Impl( aSet, *aIter.GetCurItem() );
807
0
        }
808
0
        SfxRequest aReq(nSlot, nCall, aSet);
809
0
        if (pInternalArgs)
810
0
            aReq.SetInternalArgs_Impl( *pInternalArgs );
811
0
        aReq.SetModifier( nModi );
812
813
0
        Execute_( *pShell, *pSlot, aReq, nCall );
814
0
        return aReq.GetReturnValue();
815
0
    }
816
817
0
    return SfxPoolItemHolder();
818
0
}
819
820
/** Method to execute a <SfxSlot>s over the Slot-Id.
821
822
    @param nSlot the Id of the executing function
823
    @param eCall SfxCallMode::SYNCRHON, ..._ASYNCHRON or ..._SLOT
824
    @param pArgs Zero terminated C-Array of Parameters
825
    @param pInternalArgs Zero terminated C-Array of Parameters
826
827
    @return const SfxPoolItem* Pointer to the SfxPoolItem valid to the next run
828
                            though the Message-Loop, which contains the return
829
                            value.
830
831
                            Or a NULL-Pointer, when the function was not
832
                            executed (for example canceled by the user).
833
*/
834
SfxPoolItemHolder SfxDispatcher::Execute(sal_uInt16 nSlot, SfxCallMode eCall,
835
        const SfxPoolItem **pArgs, sal_uInt16 nModi, const SfxPoolItem **pInternalArgs)
836
0
{
837
0
    if ( IsLocked() )
838
0
        return SfxPoolItemHolder();
839
840
0
    SfxShell *pShell = nullptr;
841
0
    const SfxSlot *pSlot = nullptr;
842
0
    if ( GetShellAndSlot_Impl( nSlot,  &pShell, &pSlot, false, true ) )
843
0
    {
844
0
        std::unique_ptr<SfxRequest> pReq;
845
0
        if ( pArgs && *pArgs )
846
0
        {
847
0
            SfxAllItemSet aSet( pShell->GetPool() );
848
0
            for ( const SfxPoolItem **pArg = pArgs; *pArg; ++pArg )
849
0
                MappedPut_Impl( aSet, **pArg );
850
0
            pReq.reset(new SfxRequest( nSlot, eCall, aSet ));
851
0
        }
852
0
        else
853
0
            pReq.reset(new SfxRequest( nSlot, eCall, pShell->GetPool() ));
854
0
        pReq->SetModifier( nModi );
855
0
        if( pInternalArgs && *pInternalArgs)
856
0
        {
857
0
            SfxAllItemSet aSet( SfxGetpApp()->GetPool() );
858
0
            for ( const SfxPoolItem **pArg = pInternalArgs; *pArg; ++pArg )
859
0
                aSet.Put( **pArg );
860
0
            pReq->SetInternalArgs_Impl( aSet );
861
0
        }
862
0
        Execute_( *pShell, *pSlot, *pReq, eCall );
863
0
        return pReq->GetReturnValue();
864
0
    }
865
866
0
    return SfxPoolItemHolder();
867
0
}
868
869
/** Method to execute a <SfxSlot>s over the Slot-Id.
870
871
    @param nSlot the Id of the executing function
872
    @param eCall SfxCallMode::SYNCRHON, ..._ASYNCHRON or ..._SLOT
873
    @param rArgs <SfxItemSet> with the parameters
874
875
    @return const SfxPoolItem* Pointer to the SfxPoolItem valid to the next run
876
                            though the Message-Loop, which contains the return
877
                            value.
878
879
                            Or a NULL-Pointer, when the function was not
880
                            executed (for example canceled by the user).
881
*/
882
SfxPoolItemHolder SfxDispatcher::Execute(sal_uInt16 nSlot, SfxCallMode eCall,
883
        const SfxItemSet &rArgs)
884
0
{
885
0
    if ( IsLocked() )
886
0
        return SfxPoolItemHolder();
887
888
0
    SfxShell *pShell = nullptr;
889
0
    const SfxSlot *pSlot = nullptr;
890
0
    if ( GetShellAndSlot_Impl( nSlot,  &pShell, &pSlot, false, true ) )
891
0
    {
892
0
        SfxAllItemSet aSet( pShell->GetPool() );
893
0
        for (SfxItemIter aIter( rArgs ); !aIter.IsAtEnd(); aIter.Next())
894
0
            MappedPut_Impl( aSet, *aIter.GetCurItem() );
895
0
        SfxRequest aReq( nSlot, eCall, aSet );
896
0
        aReq.SetModifier( 0 );
897
0
        Execute_( *pShell, *pSlot, aReq, eCall );
898
0
        return aReq.GetReturnValue();
899
0
    }
900
901
0
    return SfxPoolItemHolder();
902
0
}
903
904
/** Method to execute a <SfxSlot>s over the Slot-Id.
905
906
    [Note]
907
908
    The parameters are copied, can therefore be passed on as the address
909
    of stack objects.
910
911
    @param nSlot the Id of the executing function
912
    @param eCall SfxCallMode::SYNCRHON, ..._ASYNCHRON or ..._SLOT
913
    @param args  list of SfxPoolItem arguments
914
915
    @return                 Pointer to the SfxPoolItem valid to the next run
916
                            though the Message-Loop, which contains the return
917
                            value.
918
919
                            Or a NULL-Pointer, when the function was not
920
                            executed (for example canceled by the user).
921
922
    [Example]
923
924
    pDispatcher->Execute( SID_OPENDOCUMENT, SfxCallMode::SYNCHRON,
925
        {   &SfxStringItem( SID_FILE_NAME, "\\tmp\\temp.sdd" ),
926
            &SfxStringItem( SID_FILTER_NAME, "StarDraw Presentation" ),
927
            &SfxBoolItem( SID_DOC_READONLY, sal_False ),
928
        });
929
*/
930
SfxPoolItemHolder SfxDispatcher::ExecuteList(sal_uInt16 nSlot, SfxCallMode eCall,
931
        std::initializer_list<SfxPoolItem const*> args,
932
        std::initializer_list<SfxPoolItem const*> internalargs)
933
0
{
934
0
    if ( IsLocked() )
935
0
        return SfxPoolItemHolder();
936
937
0
    SfxShell *pShell = nullptr;
938
0
    const SfxSlot *pSlot = nullptr;
939
0
    if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false, true ) )
940
0
    {
941
0
       SfxAllItemSet aSet( pShell->GetPool() );
942
943
0
       for (const SfxPoolItem *pArg : args)
944
0
       {
945
0
           assert(pArg);
946
0
           MappedPut_Impl( aSet, *pArg );
947
0
       }
948
949
0
       SfxRequest aReq(nSlot, eCall, aSet);
950
951
0
       if (internalargs.begin() != internalargs.end())
952
0
       {
953
0
           SfxAllItemSet aInternalSet(SfxGetpApp()->GetPool());
954
0
           for (const SfxPoolItem *pArg : internalargs)
955
0
           {
956
0
               assert(pArg);
957
0
               aInternalSet.Put(*pArg);
958
0
           }
959
0
           aReq.SetInternalArgs_Impl(aInternalSet);
960
0
       }
961
962
0
       Execute_( *pShell, *pSlot, aReq, eCall );
963
0
       return aReq.GetReturnValue();
964
0
    }
965
966
0
    return SfxPoolItemHolder();
967
0
}
968
969
/** Helper method to receive the asynchronously executed <SfxRequest>s.
970
*/
971
void SfxDispatcher::PostMsgHandler(std::unique_ptr<SfxRequest> pReq)
972
0
{
973
0
    DBG_ASSERT( !xImp->bFlushing, "recursive call to dispatcher" );
974
0
    SFX_STACK(SfxDispatcher::PostMsgHandler);
975
976
    // Has also the Pool not yet died?
977
0
    if ( pReq->IsCancelled() )
978
0
        return;
979
980
0
    if ( !IsLocked() )
981
0
    {
982
0
        Flush();
983
0
        SfxSlotServer aSvr;
984
0
        if ( FindServer_(pReq->GetSlot(), aSvr ) ) // HACK(x), whatever that was supposed to mean
985
0
        {
986
0
            if (SfxShell *pSh = GetShell(aSvr.GetShellLevel()))
987
0
            {
988
0
                const SfxSlot *pSlot = aSvr.GetSlot();
989
990
                // When the pSlot is a "Pseudoslot" for macros or Verbs, it can
991
                // be destroyed in the Call_Impl, thus do not use it anymore!
992
0
                pReq->SetSynchronCall( false );
993
0
                Call_Impl( *pSh, *pSlot, *pReq, pReq->AllowsRecording() ); //! why bRecord?
994
0
            }
995
0
        }
996
0
    }
997
0
    else
998
0
    {
999
0
        if ( xImp->bLocked )
1000
0
            xImp->aReqArr.emplace_back(std::move(pReq));
1001
0
        else
1002
0
            xImp->xPoster->Post(std::move(pReq));
1003
0
    }
1004
0
}
1005
1006
void SfxDispatcher::SetMenu_Impl()
1007
17.2k
{
1008
#if HAVE_FEATURE_DESKTOP
1009
    if ( !xImp->pFrame )
1010
        return;
1011
1012
    if (comphelper::LibreOfficeKit::isActive())
1013
        return;
1014
1015
    SfxViewFrame* pTop = xImp->pFrame->GetTopViewFrame();
1016
    if ( !pTop || pTop->GetBindings().GetDispatcher() != this )
1017
        return;
1018
1019
    SfxFrame& rFrame = pTop->GetFrame();
1020
    if ( !rFrame.IsMenuBarOn_Impl() )
1021
        return;
1022
1023
    css::uno::Reference < css::beans::XPropertySet > xPropSet( rFrame.GetFrameInterface(), css::uno::UNO_QUERY );
1024
    if ( xPropSet.is() )
1025
    {
1026
        css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
1027
        css::uno::Any aValue = xPropSet->getPropertyValue(u"LayoutManager"_ustr);
1028
        aValue >>= xLayoutManager;
1029
        if ( xLayoutManager.is() )
1030
        {
1031
            OUString aMenuBarURL( u"private:resource/menubar/menubar"_ustr );
1032
            if ( !xLayoutManager->isElementVisible( aMenuBarURL ) )
1033
                xLayoutManager->createElement( aMenuBarURL );
1034
        }
1035
    }
1036
#endif
1037
17.2k
}
1038
1039
void SfxDispatcher::Update_Impl( bool bForce )
1040
17.2k
{
1041
17.2k
    SFX_STACK(SfxDispatcher::Update_Impl);
1042
1043
17.2k
    Flush();
1044
1045
17.2k
    if ( !xImp->pFrame )
1046
0
        return;
1047
1048
17.2k
    bool bUpdate = bForce;
1049
17.2k
    if ( xImp->pFrame )
1050
17.2k
    {
1051
17.2k
        SfxWorkWindow *pWork = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1052
17.2k
        SfxDispatcher *pAct = pWork->GetBindings().GetDispatcher_Impl();
1053
17.2k
        if (pAct == this)
1054
17.2k
        {
1055
17.2k
            if ( !bUpdate )
1056
8.61k
                bUpdate = !xImp->bUpdated;
1057
17.2k
            xImp->bUpdated = true;
1058
17.2k
        }
1059
17.2k
    }
1060
1061
17.2k
    if ( !bUpdate || xImp->pFrame->GetFrame().IsClosing_Impl() )
1062
0
        return;
1063
1064
17.2k
    SfxViewFrame* pTop = xImp->pFrame ? xImp->pFrame->GetTopViewFrame() : nullptr;
1065
17.2k
    bool bUIActive = pTop && pTop->GetBindings().GetDispatcher() == this;
1066
1067
17.2k
    if ( !bUIActive && pTop && GetBindings() == &pTop->GetBindings() )
1068
        // keep own tools internally for collecting
1069
0
        GetBindings()->GetDispatcher()->xImp->bUpdated = false;
1070
1071
17.2k
    css::uno::Reference< css::frame::XFrame > xFrame;
1072
17.2k
    SfxBindings* pBindings = GetBindings();
1073
17.2k
    if (pBindings)
1074
17.2k
    {
1075
17.2k
        pBindings->DENTERREGISTRATIONS();
1076
17.2k
        xFrame = pBindings->GetActiveFrame();
1077
17.2k
    }
1078
17.2k
    css::uno::Reference< css::beans::XPropertySet > xPropSet( xFrame, css::uno::UNO_QUERY );
1079
17.2k
    css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
1080
17.2k
    if ( xPropSet.is() )
1081
17.2k
    {
1082
17.2k
        try
1083
17.2k
        {
1084
17.2k
            css::uno::Any aValue = xPropSet->getPropertyValue(u"LayoutManager"_ustr);
1085
17.2k
            aValue >>= xLayoutManager;
1086
17.2k
        }
1087
17.2k
        catch (const css::uno::Exception&)
1088
17.2k
        {
1089
0
        }
1090
17.2k
    }
1091
1092
17.2k
    if ( xLayoutManager.is() )
1093
17.2k
        xLayoutManager->lock();
1094
1095
17.2k
    bool bIsIPActive = xImp->pFrame && xImp->pFrame->GetObjectShell()->IsInPlaceActive();
1096
17.2k
    SfxInPlaceClient *pClient = xImp->pFrame ? xImp->pFrame->GetViewShell()->GetUIActiveClient() : nullptr;
1097
17.2k
    if ( bUIActive && /* !bIsIPActive && */ ( !pClient || !pClient->IsObjectUIActive() ) )
1098
17.2k
        SetMenu_Impl();
1099
1100
17.2k
    SfxWorkWindow *pWorkWin = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1101
17.2k
    pWorkWin->ResetStatusBarId();
1102
1103
17.2k
    {
1104
17.2k
        SfxWorkWindow *pWork = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1105
17.2k
        SfxDispatcher *pAct = pWork->GetBindings().GetDispatcher_Impl();
1106
17.2k
        if (pAct == this)
1107
17.2k
        {
1108
17.2k
            pWork->ResetObjectBars_Impl();
1109
17.2k
            pWork->ResetChildWindows_Impl();
1110
17.2k
        }
1111
17.2k
    }
1112
1113
17.2k
    bool bIsActive = false;
1114
17.2k
    SfxDispatcher *pActDispat = pWorkWin->GetBindings().GetDispatcher_Impl();
1115
17.2k
    if ( this == pActDispat )
1116
17.2k
        bIsActive = true;
1117
1118
17.2k
    Update_Impl_( bUIActive, !bIsIPActive, bIsIPActive, pWorkWin );
1119
17.2k
    if (bUIActive || bIsActive)
1120
17.2k
        pWorkWin->UpdateObjectBars_Impl();
1121
1122
17.2k
    if ( pBindings )
1123
17.2k
        pBindings->DLEAVEREGISTRATIONS();
1124
1125
17.2k
    if ( xLayoutManager.is() )
1126
17.2k
        xLayoutManager->unlock();
1127
1128
17.2k
    const SfxViewShell* pViewShell = SfxViewShell::Current();
1129
17.2k
    if (pViewShell && pViewShell->GetDispatcher())
1130
8.61k
    {
1131
8.61k
        SfxPoolItemHolder aItem;
1132
8.61k
        pViewShell->GetDispatcher()->QueryState(SID_NOTEBOOKBAR, aItem);
1133
8.61k
    }
1134
17.2k
}
1135
1136
void SfxDispatcher::Update_Impl_( bool bUIActive, bool bIsMDIApp, bool bIsIPOwner, SfxWorkWindow *pTaskWin )
1137
17.2k
{
1138
17.2k
    SfxWorkWindow *pWorkWin = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1139
17.2k
    bool bIsActive = false;
1140
17.2k
    SfxDispatcher *pActDispat = pWorkWin->GetBindings().GetDispatcher_Impl();
1141
17.2k
    if ( pActDispat )
1142
17.2k
    {
1143
17.2k
        if ( this == pActDispat )
1144
17.2k
            bIsActive = true;
1145
17.2k
    }
1146
1147
17.2k
    for (SfxObjectBars_Impl & rObjBar : xImp->aObjBars)
1148
224k
        rObjBar.eId = ToolbarId::None;
1149
17.2k
    xImp->aChildWins.clear();
1150
1151
    // bQuiet: own shells aren't considered for UI and SlotServer
1152
    // bNoUI: own Shells aren't considered forms UI
1153
17.2k
    if ( xImp->bQuiet || xImp->bNoUI || (xImp->pFrame && xImp->pFrame->GetObjectShell()->IsPreview()) )
1154
0
        return;
1155
1156
17.2k
    StatusBarId eStatBarId = StatusBarId::None;
1157
17.2k
    const bool isViewerAppMode = officecfg::Office::Common::Misc::ViewerAppMode::get();
1158
1159
17.2k
    SfxSlotPool* pSlotPool = &SfxSlotPool::GetSlotPool( GetFrame() );
1160
17.2k
    sal_uInt16 nTotCount = xImp->aStack.size();
1161
129k
    for ( sal_uInt16 nShell = nTotCount; nShell > 0; --nShell )
1162
112k
    {
1163
112k
        SfxShell *pShell = GetShell( nShell-1 );
1164
112k
        if (!pShell)
1165
0
            continue;
1166
1167
112k
        SfxInterface *pIFace = pShell->GetInterface();
1168
1169
        // don't consider shells if "Hidden" or "Quiet"
1170
112k
        bool bReadOnlyShell = IsReadOnlyShell_Impl( nShell-1 );
1171
112k
        sal_uInt16 nNo;
1172
198k
        for ( nNo = 0; pIFace && nNo<pIFace->GetObjectBarCount(); ++nNo )
1173
86.5k
        {
1174
86.5k
            sal_uInt16 nPos = pIFace->GetObjectBarPos(nNo);
1175
86.5k
            SfxVisibilityFlags nFlags = pIFace->GetObjectBarFlags(nNo);
1176
86.5k
            if ( bReadOnlyShell && !( nFlags & SfxVisibilityFlags::ReadonlyDoc ) )
1177
0
                continue;
1178
1179
            // check whether toolbar needs activation of a special feature
1180
86.5k
            SfxShellFeature nFeature = pIFace->GetObjectBarFeature(nNo);
1181
86.5k
            if ((nFeature != SfxShellFeature::NONE) && !pShell->HasUIFeature(nFeature))
1182
25.8k
                continue;
1183
1184
            // check for toolboxes that are exclusively for a viewer
1185
60.7k
            if ( xImp->pFrame)
1186
60.7k
            {
1187
60.7k
                bool bViewerTbx( nFlags & SfxVisibilityFlags::Viewer );
1188
60.7k
                SfxObjectShell* pSh = xImp->pFrame->GetObjectShell();
1189
60.7k
                const SfxMedium* pMedium = pSh->GetMedium();
1190
60.7k
                const SfxBoolItem* pItem = pMedium ? pMedium->GetItemSet().GetItem(SID_VIEWONLY, false) : nullptr;
1191
60.7k
                bool bIsViewer = pItem && pItem->GetValue();
1192
60.7k
                if ( bIsViewer != bViewerTbx )
1193
17.2k
                    continue;
1194
60.7k
            }
1195
1196
            // always register toolbars, allows to switch them on
1197
43.4k
            bool bVisible = pIFace->IsObjectBarVisible(nNo);
1198
43.4k
            if ( !bVisible )
1199
0
                nFlags = SfxVisibilityFlags::Invisible;
1200
1201
43.4k
            SfxObjectBars_Impl& rBar = xImp->aObjBars[nPos];
1202
43.4k
            rBar.nPos = nPos;
1203
43.4k
            rBar.nFlags = nFlags;
1204
43.4k
            rBar.eId = pIFace->GetObjectBarId(nNo);
1205
1206
43.4k
            if ( bUIActive || bIsActive )
1207
43.4k
            {
1208
43.4k
                pWorkWin->SetObjectBar_Impl(nPos, nFlags, rBar.eId);
1209
43.4k
            }
1210
1211
43.4k
            if ( !bVisible )
1212
0
                rBar.eId = ToolbarId::None;
1213
43.4k
        }
1214
1215
673k
        for ( nNo=0; pIFace && nNo<pIFace->GetChildWindowCount(); nNo++ )
1216
561k
        {
1217
561k
            sal_uInt32 nId = pIFace->GetChildWindowId(nNo);
1218
561k
            const SfxSlot *pSlot = pSlotPool->GetSlot( static_cast<sal_uInt16>(nId) );
1219
561k
            SAL_INFO_IF( !pSlot, "sfx.control", "Childwindow slot missing: " << nId );
1220
1221
561k
            if (isViewerAppMode)
1222
0
            {
1223
                // Skip if the slot is not allowed in viewer app mode
1224
0
                if (pSlot && !pSlot->IsMode(SfxSlotMode::VIEWERAPP))
1225
0
                    continue;
1226
0
            }
1227
1228
561k
            if ( bReadOnlyShell )
1229
0
            {
1230
                // only show ChildWindows if their slot is allowed for readonly documents
1231
0
                if ( pSlot && !pSlot->IsMode( SfxSlotMode::READONLYDOC ) )
1232
0
                    continue;
1233
0
            }
1234
1235
561k
            SfxShellFeature nFeature = pIFace->GetChildWindowFeature(nNo);
1236
561k
            if ((nFeature != SfxShellFeature::NONE) && !pShell->HasUIFeature(nFeature))
1237
51.7k
                continue;
1238
1239
            // slot decides whether a ChildWindow is shown when document is OLE server or OLE client
1240
509k
            SfxVisibilityFlags nMode = SfxVisibilityFlags::Standard;
1241
509k
            if( pSlot )
1242
509k
            {
1243
509k
                if ( pSlot->IsMode(SfxSlotMode::CONTAINER) )
1244
51.6k
                {
1245
51.6k
                    if ( pWorkWin->IsVisible_Impl( SfxVisibilityFlags::Client ) )
1246
51.6k
                        nMode |= SfxVisibilityFlags::Client;
1247
51.6k
                }
1248
457k
                else
1249
457k
                {
1250
457k
                    if ( pWorkWin->IsVisible_Impl( SfxVisibilityFlags::Server ) )
1251
457k
                        nMode |= SfxVisibilityFlags::Server;
1252
457k
                }
1253
509k
            }
1254
1255
509k
            if ( bUIActive || bIsActive )
1256
509k
                pWorkWin->SetChildWindowVisible_Impl( nId, true, nMode );
1257
509k
            if ( bUIActive || bIsActive || !pWorkWin->IsFloating( static_cast<sal_uInt16>( nId & 0xFFFF ) ) )
1258
509k
                xImp->aChildWins.push_back( nId );
1259
509k
        }
1260
1261
112k
        if ( bIsMDIApp || bIsIPOwner )
1262
112k
        {
1263
112k
            StatusBarId eId = pIFace ? pIFace->GetStatusBarId() : StatusBarId::None;
1264
112k
            if (eId != StatusBarId::None)
1265
34.4k
                eStatBarId = eId;
1266
112k
        }
1267
112k
    }
1268
1269
241k
    for ( sal_uInt16 nPos=0; nPos<SFX_OBJECTBAR_MAX; nPos++ )
1270
224k
    {
1271
224k
        SfxObjectBars_Impl& rFixed = xImp->aFixedObjBars[nPos];
1272
224k
        if (rFixed.eId != ToolbarId::None)
1273
0
        {
1274
0
            SfxObjectBars_Impl& rBar = xImp->aObjBars[nPos];
1275
0
            rBar = rFixed;
1276
0
            pWorkWin->SetObjectBar_Impl(rFixed.nPos, rFixed.nFlags,
1277
0
                rFixed.eId);
1278
0
        }
1279
224k
    }
1280
1281
17.2k
    if ( !pTaskWin || ( !bIsMDIApp && !bIsIPOwner ) )
1282
0
        return;
1283
1284
17.2k
    bool bIsTaskActive = false;
1285
1286
17.2k
    SfxDispatcher *pActDispatcher = pTaskWin->GetBindings().GetDispatcher_Impl();
1287
17.2k
    if ( pActDispatcher )
1288
17.2k
    {
1289
17.2k
        if ( this == pActDispatcher )
1290
17.2k
            bIsTaskActive = true;
1291
17.2k
    }
1292
1293
17.2k
    if (bIsTaskActive && eStatBarId != StatusBarId::None && xImp->pFrame)
1294
17.2k
    {
1295
        // internal frames also may control statusbar
1296
17.2k
        xImp->pFrame->GetFrame().GetWorkWindow_Impl()->SetStatusBarId(eStatBarId);
1297
17.2k
    }
1298
17.2k
}
1299
1300
/** Helper method to execute the outstanding push and pop commands.
1301
*/
1302
void SfxDispatcher::FlushImpl()
1303
43.2k
{
1304
43.2k
    SFX_STACK(SfxDispatcher::FlushImpl);
1305
1306
43.2k
    SAL_INFO("sfx.control", "Flushing dispatcher!");
1307
1308
43.2k
    xImp->aIdle.Stop();
1309
1310
43.2k
    xImp->bFlushing = !xImp->bFlushing;
1311
43.2k
    if ( !xImp->bFlushing )
1312
0
    {
1313
0
        xImp->bFlushing = true;
1314
0
        return;
1315
0
    }
1316
1317
43.2k
    SfxApplication *pSfxApp = SfxGetpApp();
1318
1319
    // Re-build the true stack in the first round
1320
43.2k
    std::deque<SfxToDo_Impl> aToDoCopy;
1321
43.2k
    bool bModify = false;
1322
138k
    for(std::deque<SfxToDo_Impl>::reverse_iterator i = xImp->aToDoStack.rbegin(); i != xImp->aToDoStack.rend(); ++i)
1323
95.7k
    {
1324
95.7k
        bModify = true;
1325
1326
95.7k
        if(i->bPush)
1327
69.6k
        {
1328
            // Actually push
1329
69.6k
            DBG_ASSERT( std::find(xImp->aStack.begin(), xImp->aStack.end(), i->pCluster) == xImp->aStack.end(),
1330
69.6k
                       "pushed SfxShell already on stack" );
1331
69.6k
            xImp->aStack.push_back(i->pCluster);
1332
69.6k
            i->pCluster->SetDisableFlags(xImp->nDisableFlags);
1333
1334
            // Mark the moved shell
1335
69.6k
            aToDoCopy.push_front(*i);
1336
69.6k
        }
1337
26.1k
        else
1338
26.1k
        {
1339
            // Actually pop
1340
26.1k
            bool bFound = false;
1341
26.1k
            if (!i->bUntil)
1342
17.5k
            {
1343
                // pop exactly the requested shell
1344
17.5k
                if (auto it = std::find(xImp->aStack.begin(), xImp->aStack.end(), i->pCluster);
1345
17.5k
                    it != xImp->aStack.end())
1346
17.5k
                {
1347
17.5k
                    xImp->aStack.erase(it);
1348
17.5k
                    i->pCluster->SetDisableFlags(SfxDisableFlags::NONE);
1349
17.5k
                    bFound = true;
1350
1351
                    // Mark the moved Shell
1352
17.5k
                    aToDoCopy.push_front(SfxToDo_Impl(false, i->bDelete, false, *i->pCluster));
1353
17.5k
                }
1354
17.5k
            }
1355
52.3k
            while (!bFound)
1356
26.2k
            {
1357
26.2k
                DBG_ASSERT( !xImp->aStack.empty(), "popping from empty stack" );
1358
26.2k
                SfxShell* pPopped = xImp->aStack.back();
1359
26.2k
                xImp->aStack.pop_back();
1360
26.2k
                pPopped->SetDisableFlags( SfxDisableFlags::NONE );
1361
26.2k
                bFound = (pPopped == i->pCluster);
1362
1363
                // Mark the moved Shell
1364
26.2k
                aToDoCopy.push_front(SfxToDo_Impl(false, i->bDelete, false, *pPopped));
1365
26.2k
                if (!i->bUntil)
1366
0
                {
1367
                    // We get here only when the requested shell was not on the stack.
1368
                    // I don't know how correct to pop a single random other shell and exit
1369
                    // in this case, but I just make sure that the previous logic is kept.
1370
0
                    break;
1371
0
                }
1372
26.2k
            }
1373
26.1k
            DBG_ASSERT( bFound, "wrong SfxShell popped" );
1374
26.1k
        }
1375
95.7k
    }
1376
43.2k
    xImp->aToDoStack.clear();
1377
1378
    // Invalidate bindings, if possible
1379
43.2k
    if ( !pSfxApp->IsDowning() )
1380
43.2k
    {
1381
43.2k
        InvalidateBindings_Impl( bModify );
1382
43.2k
    }
1383
1384
43.2k
    xImp->bFlushing = false;
1385
43.2k
    xImp->bUpdated = false; // not only when bModify, if Doc/Template-Config
1386
43.2k
    xImp->bFlushed = true;
1387
43.2k
    SAL_INFO("sfx.control", "Successfully flushed dispatcher!");
1388
1389
    //fdo#70703 FlushImpl may call back into itself so use aToDoCopyStack to talk
1390
    //to outer levels of ourself. If DoActivate_Impl/DoDeactivate_Impl deletes
1391
    //an entry, then they will walk back up aToDoCopyStack and set outer
1392
    //levels's entries to bDeleted
1393
43.2k
    xImp->aToDoCopyStack.push_back(aToDoCopy);
1394
43.2k
    std::deque<SfxToDo_Impl>& rToDoCopy = xImp->aToDoCopyStack.back();
1395
    // Activate the Shells and possible delete them in the 2nd round
1396
156k
    for(std::deque<SfxToDo_Impl>::reverse_iterator i = rToDoCopy.rbegin(); i != rToDoCopy.rend(); ++i)
1397
113k
    {
1398
113k
        if (i->bDeleted)
1399
0
            continue;
1400
113k
        if (!xImp->bActive)
1401
86.5k
            continue;
1402
26.7k
        if (i->bPush)
1403
26.5k
            i->pCluster->DoActivate_Impl(xImp->pFrame, true);
1404
271
        else
1405
271
            i->pCluster->DoDeactivate_Impl(xImp->pFrame, true);
1406
26.7k
    }
1407
1408
43.2k
    aToDoCopy = xImp->aToDoCopyStack.back();
1409
43.2k
    xImp->aToDoCopyStack.pop_back();
1410
1411
156k
    for(std::deque<SfxToDo_Impl>::reverse_iterator i = aToDoCopy.rbegin(); i != aToDoCopy.rend(); ++i)
1412
113k
    {
1413
113k
        if (i->bDelete && !i->bDeleted)
1414
26.5k
        {
1415
26.5k
            if (!xImp->aToDoCopyStack.empty())
1416
0
            {
1417
                //fdo#70703 if there is an outer FlushImpl then inform it that
1418
                //we have deleted this cluster
1419
0
                for (auto & elem : xImp->aToDoCopyStack)
1420
0
                {
1421
0
                    for (auto & subelem : elem)
1422
0
                    {
1423
0
                        if (subelem.pCluster == i->pCluster)
1424
0
                            subelem.bDeleted = true;
1425
0
                    }
1426
0
                }
1427
0
            }
1428
26.5k
            delete i->pCluster;
1429
26.5k
        }
1430
113k
    }
1431
43.2k
    bool bAwakeBindings = !aToDoCopy.empty();
1432
43.2k
    if( bAwakeBindings )
1433
43.2k
        aToDoCopy.clear();
1434
1435
    // If more changes have occurred on the stack when
1436
    // Activate/Deactivate/Delete:
1437
43.2k
    if (!xImp->bFlushed)
1438
        // If Push/Pop has been called by someone, then also EnterReg was called!
1439
0
        FlushImpl();
1440
1441
43.2k
    if( bAwakeBindings && GetBindings() )
1442
43.1k
        GetBindings()->DLEAVEREGISTRATIONS();
1443
1444
43.2k
    for (SfxObjectBars_Impl & rFixedObjBar : xImp->aFixedObjBars)
1445
561k
        rFixedObjBar.eId = ToolbarId::None;
1446
1447
43.2k
    SAL_INFO("sfx.control", "SfxDispatcher(" << this << ")::Flush() done");
1448
43.2k
}
1449
1450
/** With this method a filter set, the target slots can be enabled or disabled.
1451
    The passed array must be retained until the destructor or the next
1452
    <SetSlotFilter()>, it is not deleted from the dispatcher, so it can thus be
1453
    static.
1454
1455
    In read-only documents the quasi ReadOnlyDoc Flag of slots can be
1456
    overturned by the use of 'bEnable == 2', so this will be displayed again.
1457
    On the other slots it has no effect.
1458
1459
    // HACK(here should be used an enum) ???
1460
    @param nEnable  1==true: only enable specified slots, disable all other
1461
                    0==false: disable specified slots, first enable all other
1462
    @param nCount Number of SIDs in the following Array
1463
    @param pSIDs sorted Array of 'nCount' SIDs
1464
1465
    [Example]
1466
1467
    Targeted disabling of Slots 1, 2 and 3:
1468
1469
        static sal_uInt16 const pSIDs[] = { 1, 2, 3 };
1470
        pDisp->SetSlotFilter( sal_False, sizeof(pSIDs)/sizeof(sal_uInt16), pSIDs );
1471
1472
    only permit Slots 5, 6 and 7:
1473
1474
        static sal_uInt16 const pSIDs[] = { 5, 6, 7 };
1475
        pDisp->SetSlotFilter( sal_True, sizeof(pSIDs)/sizeof(sal_uInt16), pSIDs );
1476
1477
    Turn-off Filter:
1478
1479
        pDisp->SetSlotFilter();
1480
*/
1481
void SfxDispatcher::SetSlotFilter(SfxSlotFilterState nEnable,
1482
        std::span<sal_uInt16 const> pSIDs)
1483
0
{
1484
#ifdef DBG_UTIL
1485
    // Check Array
1486
    for ( std::size_t n = 1; n < pSIDs.size(); ++n )
1487
        DBG_ASSERT( pSIDs[n] > pSIDs[n-1], "SetSlotFilter: SIDs not sorted" );
1488
#endif
1489
1490
0
    xImp->nFilterEnabling = nEnable;
1491
0
    xImp->pFilterSIDs = pSIDs;
1492
1493
0
    GetBindings()->InvalidateAll(true);
1494
0
}
1495
1496
extern "C" {
1497
1498
static int SfxCompareSIDs_Impl(const void* pSmaller, const void* pBigger)
1499
0
{
1500
0
    return static_cast<tools::Long>(*static_cast<sal_uInt16 const *>(pSmaller)) - static_cast<tools::Long>(*static_cast<sal_uInt16 const *>(pBigger));
1501
0
}
1502
1503
}
1504
1505
/** Searches for 'nSID' in the Filter set by <SetSlotFilter()> and
1506
    returns sal_True, if the SIDis allowed, or sal_False, if it is
1507
    disabled by the Filter.
1508
1509
    @return             0       =>      disabled
1510
                        1       =>      enabled
1511
                        2       =>      enabled even if ReadOnlyDoc
1512
*/
1513
SfxSlotFilterState SfxDispatcher::IsSlotEnabledByFilter_Impl( sal_uInt16 nSID ) const
1514
9.15k
{
1515
    // no filter?
1516
9.15k
    if ( xImp->pFilterSIDs.empty() )
1517
        // => all SIDs allowed
1518
9.15k
        return SfxSlotFilterState::ENABLED;
1519
1520
    // search
1521
0
    bool bFound = nullptr != bsearch( &nSID, xImp->pFilterSIDs.data(), xImp->pFilterSIDs.size(),
1522
0
                                sizeof(sal_uInt16), SfxCompareSIDs_Impl );
1523
1524
    // even if ReadOnlyDoc
1525
0
    if ( SfxSlotFilterState::ENABLED_READONLY == xImp->nFilterEnabling )
1526
0
        return bFound ? SfxSlotFilterState::ENABLED_READONLY : SfxSlotFilterState::ENABLED;
1527
    // Otherwise after Negative/Positive Filter
1528
0
    else if ( SfxSlotFilterState::ENABLED == xImp->nFilterEnabling )
1529
0
        return bFound ? SfxSlotFilterState::ENABLED : SfxSlotFilterState::DISABLED;
1530
0
    else
1531
0
        return bFound ? SfxSlotFilterState::DISABLED : SfxSlotFilterState::ENABLED;
1532
0
}
1533
1534
/** This helper method searches for the <Slot-Server> which currently serves
1535
    the nSlot. As the result, rServe is filled accordingly.
1536
1537
    If known the SfxInterface which is currently served by nSlot can be
1538
    passed along.
1539
1540
    The SfxDispatcher is flushed while searching for nSlot.
1541
1542
    @param nSlot Slot-Id to search for
1543
    @param rServer <SfxSlotServer>-Instance to fill
1544
1545
    @return         true
1546
                    The Slot was found, rServer is valid.
1547
1548
                    false
1549
                    The Slot is currently not served, rServer is invalid.
1550
*/
1551
bool SfxDispatcher::FindServer_(sal_uInt16 nSlot, SfxSlotServer& rServer)
1552
9.15k
{
1553
9.15k
    SFX_STACK(SfxDispatcher::FindServer_);
1554
1555
    // Dispatcher locked? (nevertheless let SID_HELP_PI through)
1556
9.15k
    if ( IsLocked() )
1557
0
    {
1558
0
        xImp->bInvalidateOnUnlock = true;
1559
0
        return false;
1560
0
    }
1561
1562
    // Count the number of Shells in the linked dispatchers.
1563
9.15k
    Flush();
1564
9.15k
    sal_uInt16 nTotCount = xImp->aStack.size();
1565
1566
    // Verb-Slot?
1567
9.15k
    if (nSlot >= SID_VERB_START && nSlot <= SID_VERB_END)
1568
0
    {
1569
0
        for ( sal_uInt16 nShell = 0;; ++nShell )
1570
0
        {
1571
0
            SfxShell *pSh = GetShell(nShell);
1572
0
            if ( pSh == nullptr )
1573
0
                return false;
1574
0
            if ( dynamic_cast< const SfxViewShell *>( pSh ) !=  nullptr )
1575
0
            {
1576
0
                const SfxSlot* pSlot = pSh->GetVerbSlot_Impl(nSlot);
1577
0
                if ( pSlot )
1578
0
                {
1579
0
                    rServer.SetShellLevel(nShell);
1580
0
                    rServer.SetSlot( pSlot );
1581
0
                    return true;
1582
0
                }
1583
0
            }
1584
0
        }
1585
0
    }
1586
1587
    // SID check against set filter
1588
9.15k
    SfxSlotFilterState nSlotEnableMode = SfxSlotFilterState::DISABLED;
1589
9.15k
    if ( xImp->pFrame )
1590
9.15k
    {
1591
9.15k
        nSlotEnableMode = IsSlotEnabledByFilter_Impl( nSlot );
1592
9.15k
        if ( SfxSlotFilterState::DISABLED == nSlotEnableMode )
1593
0
            return false;
1594
9.15k
    }
1595
1596
    // In Quiet-Mode only Parent-Dispatcher
1597
9.15k
    if ( xImp->bQuiet )
1598
0
    {
1599
0
        return false;
1600
0
    }
1601
1602
9.15k
    const bool isViewerAppMode = officecfg::Office::Common::Misc::ViewerAppMode::get();
1603
9.15k
    const bool bReadOnlyGlobal = SfxSlotFilterState::ENABLED_READONLY != nSlotEnableMode && xImp->bReadOnly;
1604
1605
9.15k
    const bool bIsInPlace = xImp->pFrame && xImp->pFrame->GetObjectShell()->IsInPlaceActive();
1606
    // Shell belongs to Server?
1607
    // AppDispatcher or IPFrame-Dispatcher
1608
9.15k
    bool bIsServerShell = !xImp->pFrame || bIsInPlace;
1609
    // Of course ShellServer-Slots are also executable even when it is
1610
    // executed on a container dispatcher without an IPClient.
1611
9.15k
    if (!bIsServerShell)
1612
9.15k
    {
1613
9.15k
        SfxViewShell* pViewSh = xImp->pFrame->GetViewShell();
1614
9.15k
        bIsServerShell = !pViewSh || !pViewSh->GetUIActiveClient();
1615
9.15k
    }
1616
    // Shell belongs to Container?
1617
    // AppDispatcher or no IPFrameDispatcher
1618
9.15k
    const bool bIsContainerShell = !bIsInPlace;
1619
1620
    // search through all the shells of the chained dispatchers
1621
    // from top to bottom
1622
45.5k
    for (sal_uInt16 i = 0; i < nTotCount; ++i)
1623
45.5k
    {
1624
45.5k
        SfxShell *pObjShell = GetShell(i);
1625
45.5k
        if (!pObjShell)
1626
0
            continue;
1627
1628
45.5k
        SfxInterface *pIFace = pObjShell->GetInterface();
1629
45.5k
        const SfxSlot *pSlot = pIFace->GetSlot(nSlot);
1630
45.5k
        if (!pSlot)
1631
36.3k
            continue;
1632
1633
        // Slot belongs to Container?
1634
9.15k
        bool bIsContainerSlot = pSlot->IsMode(SfxSlotMode::CONTAINER);
1635
1636
        // Shell and Slot match
1637
9.15k
        if ( !( ( bIsContainerSlot && bIsContainerShell ) ||
1638
9.15k
                ( !bIsContainerSlot && bIsServerShell ) ) )
1639
0
            continue;
1640
1641
9.15k
        if ( pSlot->nDisableFlags != SfxDisableFlags::NONE &&
1642
504
             ( static_cast<int>(pSlot->nDisableFlags) & static_cast<int>(pObjShell->GetDisableFlags()) ) != 0 )
1643
0
            return false;
1644
1645
9.15k
        if (!(pSlot->nFlags & SfxSlotMode::VIEWERAPP) && isViewerAppMode)
1646
0
            return false;
1647
1648
        // The slot is not read-only
1649
9.15k
        if (!(pSlot->nFlags & SfxSlotMode::READONLYDOC))
1650
432
        {
1651
            // 1. The global context is read-only
1652
432
            if (bReadOnlyGlobal)
1653
0
            {
1654
0
                bool bAllowThis = false;
1655
                // Enable insert new annotation in Writer in read-only mode
1656
0
                if (getenv("EDIT_COMMENT_IN_READONLY_MODE") != nullptr)
1657
0
                {
1658
0
                    OUString sCommand = pSlot->GetCommand();
1659
0
                    if (sCommand == u".uno:InsertAnnotation"_ustr
1660
0
                        || sCommand == u".uno:Undo"_ustr
1661
0
                        || sCommand == u".uno:Redo"_ustr
1662
0
                        || ((sCommand == u".uno:FontDialog"_ustr
1663
0
                             || sCommand == u".uno:ParagraphDialog"_ustr)
1664
0
                            && pIFace->GetClassName() == "SwAnnotationShell"_ostr))
1665
0
                    {
1666
0
                        bAllowThis = true;
1667
0
                    }
1668
0
                }
1669
0
                if (!bAllowThis)
1670
0
                    return false;
1671
0
            }
1672
432
        }
1673
1674
9.15k
        rServer.SetSlot(pSlot);
1675
9.15k
        rServer.SetShellLevel(i);
1676
9.15k
        return true;
1677
9.15k
    }
1678
1679
0
    return false;
1680
9.15k
}
1681
1682
/** Helper method to obtain the status of the <Slot-Server>s rSvr.
1683
    The required slots IDs (partly converted to Which-IDs of the pool)
1684
    must be present in rstate.
1685
1686
    The SfxDispatcher is flushed before the query.
1687
1688
    @param rSvr Slot-Server to query
1689
    @param rState SfxItemSet to be filled
1690
    @param pRealSlot The actual Slot if possible
1691
*/
1692
bool SfxDispatcher::FillState_(const SfxSlotServer& rSvr, SfxItemSet& rState,
1693
        const SfxSlot* pRealSlot)
1694
72
{
1695
72
    SFX_STACK(SfxDispatcher::FillState_);
1696
1697
72
    const SfxSlot *pSlot = rSvr.GetSlot();
1698
72
    if ( pSlot && IsLocked() )
1699
0
    {
1700
0
        xImp->bInvalidateOnUnlock = true;
1701
0
        return false;
1702
0
    }
1703
1704
72
    if ( pSlot )
1705
72
    {
1706
72
        DBG_ASSERT(xImp->bFlushed,
1707
72
                "Dispatcher not flushed after retrieving slot servers!");
1708
72
        if (!xImp->bFlushed)
1709
0
            return false;
1710
1711
        // Determine the object and call the Message of this object
1712
72
        SfxShell *pSh = GetShell(rSvr.GetShellLevel());
1713
72
        if (!pSh)
1714
0
            return false;
1715
1716
72
        SfxStateFunc pFunc;
1717
1718
72
        if (pRealSlot)
1719
72
            pFunc = pRealSlot->GetStateFnc();
1720
0
        else
1721
0
            pFunc = pSlot->GetStateFnc();
1722
1723
72
        (*pFunc)(pSh, rState);
1724
#ifdef DBG_UTIL
1725
        // To examine the conformity of IDL (SlotMap) and current Items
1726
        if ( rState.Count() )
1727
        {
1728
            SfxInterface *pIF = pSh->GetInterface();
1729
            for (SfxItemIter aIter( rState ); !aIter.IsAtEnd(); aIter.Next())
1730
            {
1731
                const SfxPoolItem* pItem = aIter.GetCurItem();
1732
                if ( !IsInvalidItem(pItem) && !IsDisabledItem(pItem) )
1733
                {
1734
                    sal_uInt16 nSlotId = rState.GetPool()->GetSlotId(pItem->Which());
1735
                    SAL_INFO_IF(
1736
                        typeid(pItem) != *pIF->GetSlot(nSlotId)->GetType()->Type(),
1737
                        "sfx.control",
1738
                        "item-type unequal to IDL (=> no BASIC) with SID: "
1739
                            << nSlotId << " in " << pIF->GetClassName());
1740
                }
1741
            }
1742
        }
1743
#endif
1744
1745
72
        return true;
1746
72
    }
1747
1748
0
    return false;
1749
72
}
1750
1751
void SfxDispatcher::ExecutePopup( vcl::Window *pWin, const Point *pPos )
1752
0
{
1753
0
    SfxDispatcher &rDisp = *SfxGetpApp()->GetDispatcher_Impl();
1754
0
    sal_uInt16 nShLevel = 0;
1755
0
    SfxShell *pSh;
1756
1757
0
    if ( rDisp.xImp->bQuiet )
1758
0
        nShLevel = rDisp.xImp->aStack.size();
1759
1760
0
    for ( pSh = rDisp.GetShell(nShLevel); pSh; ++nShLevel, pSh = rDisp.GetShell(nShLevel) )
1761
0
    {
1762
0
        const OUString& rResName = pSh->GetInterface()->GetPopupMenuName();
1763
0
        if ( !rResName.isEmpty() )
1764
0
        {
1765
0
            rDisp.ExecutePopup( rResName, pWin, pPos );
1766
0
            return;
1767
0
        }
1768
0
    }
1769
0
}
1770
1771
namespace {
1772
1773
boost::property_tree::ptree fillPopupMenu(Menu* pMenu)
1774
0
{
1775
    // Activate this menu first
1776
0
    pMenu->HandleMenuActivateEvent(pMenu);
1777
0
    pMenu->HandleMenuDeActivateEvent(pMenu);
1778
1779
0
    boost::property_tree::ptree aTree;
1780
    // If last item inserted is some valid text
1781
0
    bool bIsLastItemText = false;
1782
0
    sal_uInt16 nCount = pMenu->GetItemCount();
1783
0
    for (sal_uInt16 nPos = 0; nPos < nCount; nPos++)
1784
0
    {
1785
0
        boost::property_tree::ptree aItemTree;
1786
0
        const MenuItemType aItemType = pMenu->GetItemType(nPos);
1787
1788
0
        if (aItemType == MenuItemType::DONTKNOW)
1789
0
            continue;
1790
1791
0
        if (aItemType == MenuItemType::SEPARATOR)
1792
0
        {
1793
0
            if (bIsLastItemText)
1794
0
                aItemTree.put("type", "separator");
1795
0
            bIsLastItemText = false;
1796
0
        }
1797
0
        else
1798
0
        {
1799
0
            const sal_uInt16 nItemId = pMenu->GetItemId(nPos);
1800
0
            OUString aCommandURL = pMenu->GetItemCommand(nItemId);
1801
1802
0
            if (aCommandURL.isEmpty())
1803
0
            {
1804
0
                const SfxSlot *pSlot = SFX_SLOTPOOL().GetSlot(nItemId);
1805
0
                if (pSlot)
1806
0
                    aCommandURL = pSlot->GetCommand();
1807
0
            }
1808
1809
0
            const OUString aItemText = pMenu->GetItemText(nItemId);
1810
0
            Menu* pPopupSubmenu = pMenu->GetPopupMenu(nItemId);
1811
1812
0
            if (!aItemText.isEmpty())
1813
0
                aItemTree.put("text", aItemText.toUtf8().getStr());
1814
1815
0
            if (pPopupSubmenu)
1816
0
            {
1817
0
                boost::property_tree::ptree aSubmenu = ::fillPopupMenu(pPopupSubmenu);
1818
0
                if (aSubmenu.empty())
1819
0
                    continue;
1820
1821
0
                aItemTree.put("type", "menu");
1822
0
                if (!aCommandURL.isEmpty())
1823
0
                    aItemTree.put("command", aCommandURL.toUtf8().getStr());
1824
0
                aItemTree.push_back(std::make_pair("menu", aSubmenu));
1825
0
            }
1826
0
            else
1827
0
            {
1828
                // no point in exposing choices that don't have the .uno:
1829
                // command
1830
0
                if (aCommandURL.isEmpty())
1831
0
                    continue;
1832
1833
0
                aItemTree.put("type", "command");
1834
0
                aItemTree.put("command", aCommandURL.toUtf8().getStr());
1835
0
            }
1836
1837
0
            aItemTree.put("enabled", pMenu->IsItemEnabled(nItemId));
1838
1839
0
            MenuItemBits aItemBits = pMenu->GetItemBits(nItemId);
1840
0
            bool bHasChecks = true;
1841
0
            if (aItemBits & MenuItemBits::CHECKABLE)
1842
0
                aItemTree.put("checktype", "checkmark");
1843
0
            else if (aItemBits & MenuItemBits::RADIOCHECK)
1844
0
                aItemTree.put("checktype", "radio");
1845
0
            else if (aItemBits & MenuItemBits::AUTOCHECK)
1846
0
                aItemTree.put("checktype", "auto");
1847
0
            else
1848
0
                bHasChecks = false;
1849
1850
0
            if (bHasChecks)
1851
0
                aItemTree.put("checked", pMenu->IsItemChecked(nItemId));
1852
0
        }
1853
1854
0
        if (!aItemTree.empty())
1855
0
        {
1856
0
            aTree.push_back(std::make_pair("", aItemTree));
1857
0
            if (aItemType != MenuItemType::SEPARATOR)
1858
0
                bIsLastItemText = true;
1859
0
        }
1860
0
    }
1861
1862
0
    return aTree;
1863
0
}
1864
1865
}
1866
1867
boost::property_tree::ptree SfxDispatcher::fillPopupMenu(const rtl::Reference<VCLXPopupMenu>& rPopupMenu)
1868
0
{
1869
0
    PopupMenu* pVCLMenu = static_cast<PopupMenu*>(rPopupMenu->GetMenu());
1870
0
    return ::fillPopupMenu(pVCLMenu);
1871
0
}
1872
1873
void SfxDispatcher::ExecutePopup( const OUString& rResName, vcl::Window* pWin, const Point* pPos )
1874
0
{
1875
0
    css::uno::Sequence< css::uno::Any > aArgs{
1876
0
        css::uno::Any(comphelper::makePropertyValue( u"Value"_ustr, rResName )),
1877
0
        css::uno::Any(comphelper::makePropertyValue( u"Frame"_ustr, GetFrame()->GetFrame().GetFrameInterface() )),
1878
0
        css::uno::Any(comphelper::makePropertyValue( u"IsContextMenu"_ustr, true ))
1879
0
    };
1880
1881
0
    const css::uno::Reference< css::uno::XComponentContext >& xContext = comphelper::getProcessComponentContext();
1882
0
    css::uno::Reference< css::frame::XPopupMenuController > xPopupController(
1883
0
        xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
1884
0
        u"com.sun.star.comp.framework.ResourceMenuController"_ustr, aArgs, xContext ), css::uno::UNO_QUERY );
1885
#if defined __EMSCRIPTEN__ && ENABLE_QT5
1886
    // At least under Emscripten with Qt5, the QMenu::exec underlying the below call to
1887
    // xPopupMenu->execute returns immediately, without going into a new event loop, and we need to
1888
    // keep the underlying QMenu instance alive via the static lastPopupController chain here, until
1889
    // the next popup menu is opened (there can only ever be a single popup menu open, so it
1890
    // suffices to have a single static lastPopupController instance):
1891
    static css::uno::Reference<css::frame::XPopupMenuController> lastPopupController;
1892
    if (lastPopupController.is()) {
1893
        if (css::uno::Reference<css::lang::XComponent> component(
1894
                lastPopupController, css::uno::UNO_QUERY);
1895
            component.is())
1896
        {
1897
            component->dispose();
1898
        }
1899
        lastPopupController = xPopupController;
1900
    }
1901
#endif
1902
1903
0
    rtl::Reference< VCLXPopupMenu > xPopupMenu = new VCLXPopupMenu();
1904
1905
0
    if ( !xPopupController.is() || !xPopupMenu.is() )
1906
0
        return;
1907
1908
0
    vcl::Window* pWindow = pWin ? pWin : xImp->pFrame->GetFrame().GetWorkWindow_Impl()->GetWindow();
1909
0
    Point aPos = pPos ? *pPos : pWindow->GetPointerPosPixel();
1910
1911
0
    css::ui::ContextMenuExecuteEvent aEvent;
1912
0
    aEvent.SourceWindow = VCLUnoHelper::GetInterface( pWindow );
1913
0
    aEvent.ExecutePosition.X = aPos.X();
1914
0
    aEvent.ExecutePosition.Y = aPos.Y();
1915
1916
0
    xPopupController->setPopupMenu( xPopupMenu );
1917
0
    if (comphelper::LibreOfficeKit::isActive())
1918
0
    {
1919
0
        boost::property_tree::ptree aMenu = fillPopupMenu(xPopupMenu);
1920
0
        boost::property_tree::ptree aRoot;
1921
0
        aRoot.add_child("menu", aMenu);
1922
1923
0
        std::stringstream aStream;
1924
0
        boost::property_tree::write_json(aStream, aRoot, true);
1925
0
        if (SfxViewShell* pViewShell = xImp->pFrame->GetViewShell())
1926
0
            pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_MENU, OString(aStream.str()));
1927
0
    }
1928
0
    else
1929
0
    {
1930
0
        OUString aMenuURL = "private:resource/popupmenu/" + rResName;
1931
0
        if (GetFrame()->GetViewShell()->TryContextMenuInterception(xPopupMenu, aMenuURL, aEvent))
1932
0
        {
1933
0
            css::uno::Reference<css::awt::XWindowPeer> xParent(aEvent.SourceWindow, css::uno::UNO_QUERY);
1934
0
            xPopupMenu->execute(xParent, css::awt::Rectangle(aPos.X(), aPos.Y(), 1, 1), css::awt::PopupMenuDirection::EXECUTE_DOWN);
1935
0
        }
1936
0
    }
1937
1938
0
#if !(defined __EMSCRIPTEN__ && ENABLE_QT5)
1939
0
    css::uno::Reference< css::lang::XComponent > xComponent( xPopupController, css::uno::UNO_QUERY );
1940
0
    if ( xComponent.is() )
1941
0
        xComponent->dispose();
1942
0
#endif
1943
0
}
1944
1945
/** With this method the SfxDispatcher can be locked and released. A locked
1946
    SfxDispatcher does not perform <SfxRequest>s and does no longer provide
1947
    status information. It behaves as if all the slots were disabled.
1948
*/
1949
void SfxDispatcher::Lock( bool bLock )
1950
34.7k
{
1951
34.7k
    SfxBindings* pBindings = GetBindings();
1952
34.7k
    if ( !bLock && xImp->bLocked && xImp->bInvalidateOnUnlock )
1953
0
    {
1954
0
        if ( pBindings )
1955
0
            pBindings->InvalidateAll(true);
1956
0
        xImp->bInvalidateOnUnlock = false;
1957
0
    }
1958
34.7k
    else if ( pBindings )
1959
34.7k
        pBindings->InvalidateAll(false);
1960
34.7k
    xImp->bLocked = bLock;
1961
34.7k
    if ( !bLock )
1962
17.3k
    {
1963
17.3k
        for(size_t i = 0; i < xImp->aReqArr.size(); ++i)
1964
0
            xImp->xPoster->Post(std::move(xImp->aReqArr[i]));
1965
17.3k
        xImp->aReqArr.clear();
1966
17.3k
    }
1967
34.7k
}
1968
1969
ToolbarId SfxDispatcher::GetObjectBarId( sal_uInt16 nPos ) const
1970
110
{
1971
110
    return xImp->aObjBars[nPos].eId;
1972
110
}
1973
1974
void SfxDispatcher::HideUI( bool bHide )
1975
8.61k
{
1976
8.61k
    bool bWasHidden = xImp->bNoUI;
1977
8.61k
    xImp->bNoUI = bHide;
1978
8.61k
    if ( xImp->pFrame )
1979
8.61k
    {
1980
8.61k
        SfxViewFrame* pTop = xImp->pFrame->GetTopViewFrame();
1981
8.61k
        if ( pTop && pTop->GetBindings().GetDispatcher() == this )
1982
8.61k
        {
1983
8.61k
            SfxFrame& rFrame = pTop->GetFrame();
1984
8.61k
            if ( rFrame.IsMenuBarOn_Impl() )
1985
8.61k
            {
1986
8.61k
                css::uno::Reference < css::beans::XPropertySet > xPropSet( rFrame.GetFrameInterface(), css::uno::UNO_QUERY );
1987
8.61k
                if ( xPropSet.is() )
1988
8.61k
                {
1989
8.61k
                    css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
1990
8.61k
                    css::uno::Any aValue = xPropSet->getPropertyValue(u"LayoutManager"_ustr);
1991
8.61k
                    aValue >>= xLayoutManager;
1992
8.61k
                    if ( xLayoutManager.is() )
1993
8.61k
                        xLayoutManager->setVisible( !bHide );
1994
8.61k
                }
1995
8.61k
            }
1996
8.61k
        }
1997
8.61k
    }
1998
1999
8.61k
    if ( bHide != bWasHidden )
2000
0
        Update_Impl( true );
2001
8.61k
}
2002
2003
void SfxDispatcher::SetReadOnly_Impl( bool bOn )
2004
8.61k
{
2005
8.61k
    xImp->bReadOnly = bOn;
2006
8.61k
}
2007
2008
bool SfxDispatcher::GetReadOnly_Impl() const
2009
0
{
2010
0
    return xImp->bReadOnly || SfxViewShell::IsCurrentLokViewReadOnly();
2011
0
}
2012
2013
/** With 'bOn' the Dispatcher is quasi dead and transfers everything to the
2014
    Parent-Dispatcher.
2015
*/
2016
void SfxDispatcher::SetQuietMode_Impl( bool bOn )
2017
0
{
2018
0
    xImp->bQuiet = bOn;
2019
0
    SfxBindings* pBindings = GetBindings();
2020
0
    if ( pBindings )
2021
0
        pBindings->InvalidateAll(true);
2022
0
}
2023
2024
SfxItemState SfxDispatcher::QueryState( sal_uInt16 nSlot, SfxPoolItemHolder& rState )
2025
8.61k
{
2026
8.61k
    SfxShell *pShell = nullptr;
2027
8.61k
    const SfxSlot *pSlot = nullptr;
2028
8.61k
    if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false, true ) )
2029
8.61k
    {
2030
8.61k
        rState = pShell->GetSlotState(nSlot);
2031
8.61k
        if (!rState)
2032
0
            return SfxItemState::DISABLED;
2033
8.61k
        else
2034
8.61k
            return SfxItemState::DEFAULT;
2035
8.61k
    }
2036
2037
0
    return SfxItemState::DISABLED;
2038
8.61k
}
2039
2040
SfxItemState SfxDispatcher::QueryState( sal_uInt16 nSID, css::uno::Any& rAny )
2041
0
{
2042
0
    SfxShell *pShell = nullptr;
2043
0
    const SfxSlot *pSlot = nullptr;
2044
0
    if ( GetShellAndSlot_Impl( nSID, &pShell, &pSlot, false, true ) )
2045
0
    {
2046
0
        SfxPoolItemHolder aItem(pShell->GetSlotState(nSID));
2047
0
        if (!aItem)
2048
0
            return SfxItemState::DISABLED;
2049
0
        else
2050
0
        {
2051
0
            css::uno::Any aState;
2052
0
            if ( !IsDisabledItem(aItem.getItem()) )
2053
0
            {
2054
0
                sal_uInt16 nSubId( 0 );
2055
0
                SfxItemPool& rPool = pShell->GetPool();
2056
0
                sal_uInt16 nWhich = rPool.GetWhichIDFromSlotID( nSID );
2057
0
                if ( rPool.GetMetric( nWhich ) == MapUnit::MapTwip )
2058
0
                    nSubId |= CONVERT_TWIPS;
2059
0
                aItem.getItem()->QueryValue( aState, static_cast<sal_uInt8>(nSubId) );
2060
0
            }
2061
0
            rAny = std::move(aState);
2062
2063
0
            return SfxItemState::DEFAULT;
2064
0
        }
2065
0
    }
2066
2067
0
    return SfxItemState::DISABLED;
2068
0
}
2069
2070
bool SfxDispatcher::IsReadOnlyShell_Impl( sal_uInt16 nShell ) const
2071
112k
{
2072
112k
    bool bResult = true;
2073
112k
    sal_uInt16 nShellCount = xImp->aStack.size();
2074
112k
    if ( nShell < nShellCount )
2075
112k
    {
2076
112k
        SfxShell* pShell = *( xImp->aStack.rbegin() + nShell );
2077
112k
        if( dynamic_cast< const SfxModule *>( pShell ) != nullptr || dynamic_cast< const SfxApplication *>( pShell ) != nullptr || dynamic_cast< const SfxViewFrame *>( pShell ) !=  nullptr )
2078
51.6k
            bResult = false;
2079
60.7k
        else
2080
60.7k
            bResult = xImp->bReadOnly;
2081
112k
    }
2082
2083
112k
    if (!bResult && SfxViewShell::IsCurrentLokViewReadOnly())
2084
0
            bResult = true;
2085
2086
112k
    return bResult;
2087
112k
}
2088
2089
void SfxDispatcher::RemoveShell_Impl( SfxShell& rShell )
2090
8.61k
{
2091
8.61k
    Flush();
2092
2093
8.61k
    sal_uInt16 nCount = xImp->aStack.size();
2094
17.2k
    for ( sal_uInt16 n=0; n<nCount; ++n )
2095
17.2k
    {
2096
17.2k
        if ( xImp->aStack[n] == &rShell )
2097
8.61k
        {
2098
8.61k
            xImp->aStack.erase( xImp->aStack.begin() + n );
2099
8.61k
            rShell.SetDisableFlags( SfxDisableFlags::NONE );
2100
8.61k
            rShell.DoDeactivate_Impl(xImp->pFrame, true);
2101
8.61k
            break;
2102
8.61k
        }
2103
17.2k
    }
2104
2105
8.61k
    if ( !SfxGetpApp()->IsDowning() )
2106
8.61k
    {
2107
8.61k
        xImp->bUpdated = false;
2108
8.61k
        InvalidateBindings_Impl(true);
2109
8.61k
    }
2110
8.61k
}
2111
2112
void SfxDispatcher::InvalidateBindings_Impl( bool bModify )
2113
51.8k
{
2114
    // App-Dispatcher?
2115
51.8k
    if ( IsAppDispatcher() )
2116
21
    {
2117
21
        for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst();
2118
21
                pFrame;
2119
21
                pFrame = SfxViewFrame::GetNext( *pFrame ) )
2120
0
            pFrame->GetBindings().InvalidateAll(bModify);
2121
21
    }
2122
51.8k
    else
2123
51.8k
    {
2124
51.8k
        SfxDispatcher *pDisp = GetBindings()->GetDispatcher_Impl();
2125
51.8k
        if ( pDisp == this )
2126
51.8k
        {
2127
51.8k
            GetBindings()->InvalidateAll( bModify );
2128
51.8k
        }
2129
51.8k
    }
2130
51.8k
}
2131
2132
bool SfxDispatcher::IsUpdated_Impl() const
2133
0
{
2134
0
    return xImp->bUpdated;
2135
0
}
2136
2137
void SfxDispatcher::SetDisableFlags( SfxDisableFlags nFlags )
2138
17.2k
{
2139
17.2k
    xImp->nDisableFlags = nFlags;
2140
68.9k
    for ( SfxShellStack_Impl::reverse_iterator it = xImp->aStack.rbegin(); it != xImp->aStack.rend(); ++it )
2141
51.7k
        (*it)->SetDisableFlags( nFlags );
2142
17.2k
}
2143
2144
SfxDisableFlags SfxDispatcher::GetDisableFlags() const
2145
49.1k
{
2146
49.1k
    return xImp->nDisableFlags;
2147
49.1k
}
2148
2149
SfxModule* SfxDispatcher::GetModule() const
2150
0
{
2151
0
    for ( sal_uInt16 nShell = 0;; ++nShell )
2152
0
    {
2153
0
        SfxShell *pSh = GetShell(nShell);
2154
0
        if ( pSh == nullptr )
2155
0
            return nullptr;
2156
0
        if ( auto pModule = dynamic_cast<SfxModule *>( pSh ) )
2157
0
            return pModule;
2158
0
    }
2159
0
}
2160
2161
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */