Coverage Report

Created: 2026-04-09 11:41

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
67.0k
        : pCluster(&rCluster)
91
67.0k
        , bPush(bOpPush)
92
67.0k
        , bDelete(bOpDelete)
93
67.0k
        , bDeleted(false)
94
67.0k
        , bUntil(bOpUntil)
95
67.0k
                {}
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
103k
    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
59.0k
{
161
59.0k
    if (!xImp->bFlushed) FlushImpl();
162
59.0k
}
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
31.5k
{
175
31.5k
    Pop( rShell, SfxDispatcherPopFlags::PUSH );
176
31.5k
}
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
26.3k
{
202
26.3k
    return xImp->bLocked;
203
26.3k
}
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
31.5k
{
212
31.5k
    return !xImp->pFrame;
213
31.5k
}
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
3.96k
{
291
3.96k
    xImp.reset(new SfxDispatcher_Impl);
292
3.96k
    xImp->bFlushed = true;
293
294
3.96k
    xImp->bFlushing = false;
295
3.96k
    xImp->bUpdated = false;
296
3.96k
    xImp->bLocked = false;
297
3.96k
    xImp->bActive = false;
298
3.96k
    xImp->bNoUI = false;
299
3.96k
    xImp->bReadOnly = false;
300
3.96k
    xImp->bQuiet = false;
301
3.96k
    xImp->pInCallAliveFlag = nullptr;
302
3.96k
    xImp->nFilterEnabling = SfxSlotFilterState::DISABLED;
303
3.96k
    xImp->nDisableFlags = SfxDisableFlags::NONE;
304
305
3.96k
    xImp->bInvalidateOnUnlock = false;
306
307
3.96k
    for (SfxObjectBars_Impl & rObjBar : xImp->aObjBars)
308
51.5k
        rObjBar.eId = ToolbarId::None;
309
310
3.96k
    xImp->xPoster = new SfxHintPoster(this);
311
312
3.96k
    xImp->aIdle.SetPriority(TaskPriority::HIGH_IDLE );
313
3.96k
    xImp->aIdle.SetInvokeHandler( LINK(this, SfxDispatcher, EventHdl_Impl ) );
314
3.96k
}
315
316
SfxDispatcher::SfxDispatcher()
317
27
{
318
27
    Construct_Impl();
319
27
    xImp->pFrame = nullptr;
320
27
}
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
3.93k
{
327
3.93k
    Construct_Impl();
328
3.93k
    xImp->pFrame = pViewFrame;
329
3.93k
}
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
3.93k
{
337
3.93k
    SAL_INFO("sfx.control", "Delete Dispatcher " << reinterpret_cast<sal_Int64>(this));
338
3.93k
    DBG_ASSERT( !xImp->bActive, "deleting active Dispatcher" );
339
340
    // So that no timer by Reschedule in PlugComm strikes the LeaveRegistrations
341
3.93k
    xImp->aIdle.Stop();
342
3.93k
    xImp->xPoster->ClearLink();
343
344
    // Notify the stack variables in Call_Impl
345
3.93k
    if ( xImp->pInCallAliveFlag )
346
0
        *xImp->pInCallAliveFlag = false;
347
348
    // Get bindings and application
349
3.93k
    SfxApplication *pSfxApp = SfxGetpApp();
350
3.93k
    SfxBindings* pBindings = GetBindings();
351
352
    // When not flushed, revive the bindings
353
3.93k
    if (pBindings && !pSfxApp->IsDowning() && !xImp->bFlushed)
354
3.93k
        pBindings->DLEAVEREGISTRATIONS();
355
356
    // may unregister the bindings
357
7.87k
    while ( pBindings )
358
3.93k
    {
359
3.93k
        if ( pBindings->GetDispatcher_Impl() == this)
360
3.93k
            pBindings->SetDispatcher(nullptr);
361
3.93k
        pBindings = pBindings->GetSubBindings_Impl();
362
3.93k
    }
363
3.93k
}
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
47.3k
{
386
47.3k
    DBG_ASSERT( rShell.GetInterface(),
387
47.3k
                "pushing SfxShell without previous RegisterInterface()" );
388
389
47.3k
    bool bDelete = bool(nMode & SfxDispatcherPopFlags::POP_DELETE);
390
47.3k
    bool bUntil = bool(nMode & SfxDispatcherPopFlags::POP_UNTIL);
391
47.3k
    bool bPush = bool(nMode & SfxDispatcherPopFlags::PUSH);
392
393
47.3k
    SfxApplication *pSfxApp = SfxGetpApp();
394
395
47.3k
    SAL_INFO(
396
47.3k
        "sfx.control",
397
47.3k
        "-SfxDispatcher(" << this << (bPush ? ")::Push(" : ")::Pop(")
398
47.3k
            << (rShell.GetInterface()
399
47.3k
                ? rShell.GetInterface()->GetClassName() : SAL_STREAM(&rShell))
400
47.3k
            << (bDelete ? ") with delete" : ")")
401
47.3k
            << (bUntil ? " (up to)" : ""));
402
403
    // same shell as on top of the to-do stack?
404
47.3k
    if(!xImp->aToDoStack.empty() && xImp->aToDoStack.front().pCluster == &rShell)
405
4
    {
406
        // cancel inverse actions
407
4
        if ( xImp->aToDoStack.front().bPush != bPush )
408
4
            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
4
    }
415
47.3k
    else
416
47.3k
    {
417
        // Remember Action
418
47.3k
        xImp->aToDoStack.push_front( SfxToDo_Impl(bPush, bDelete, bUntil, rShell) );
419
47.3k
        if (xImp->bFlushed)
420
23.6k
        {
421
23.6k
            SAL_INFO("sfx.control", "Unflushed dispatcher!");
422
23.6k
            xImp->bFlushed = false;
423
23.6k
            xImp->bUpdated = false;
424
425
            // Put bindings to sleep
426
23.6k
            SfxBindings* pBindings = GetBindings();
427
23.6k
            if ( pBindings )
428
23.6k
                pBindings->DENTERREGISTRATIONS();
429
23.6k
        }
430
47.3k
    }
431
432
47.3k
    if(!pSfxApp->IsDowning() && !xImp->aToDoStack.empty())
433
47.3k
    {
434
        // No immediate update is requested
435
47.3k
        xImp->aIdle.Start();
436
47.3k
    }
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
47.3k
}
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
3.93k
{
516
3.93k
    SFX_STACK(SfxDispatcher::GetShellLevel);
517
3.93k
    Flush();
518
519
15.7k
    for ( size_t n = 0; n < xImp->aStack.size(); ++n )
520
15.7k
        if ( *( xImp->aStack.rbegin() + n ) == &rShell )
521
3.93k
            return n;
522
523
0
    return USHRT_MAX;
524
3.93k
}
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
78.7k
{
535
78.7k
    sal_uInt16 nShellCount = xImp->aStack.size();
536
78.7k
    if ( nIdx < nShellCount )
537
78.7k
        return *(xImp->aStack.rbegin() + nIdx);
538
0
    return nullptr;
539
78.7k
}
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
150k
{
551
150k
    if ( xImp->pFrame )
552
150k
        return &xImp->pFrame->GetBindings();
553
81
    else
554
81
        return nullptr;
555
150k
}
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
188k
{
563
188k
    return xImp->pFrame;
564
188k
}
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
3.96k
{
579
3.96k
    SFX_STACK(SfxDispatcher::DoActivate);
580
3.96k
    if ( bMDI )
581
3.96k
    {
582
3.96k
        SAL_INFO("sfx.control", "Activate Dispatcher " << reinterpret_cast<sal_Int64>(this));
583
3.96k
        DBG_ASSERT( !xImp->bActive, "Activation error" );
584
585
3.96k
        xImp->bActive = true;
586
3.96k
        xImp->bUpdated = false;
587
3.96k
        SfxBindings* pBindings = GetBindings();
588
3.96k
        if ( pBindings )
589
3.93k
        {
590
3.93k
            pBindings->SetDispatcher(this);
591
3.93k
            pBindings->SetActiveFrame( xImp->pFrame->GetFrame().GetFrameInterface() );
592
3.93k
        }
593
3.96k
    }
594
0
    else
595
0
    {
596
0
        SAL_INFO("sfx.control", "Non-MDI-Activate Dispatcher " << reinterpret_cast<sal_Int64>(this));
597
0
    }
598
599
3.96k
    if ( IsAppDispatcher() )
600
27
        return;
601
602
23.6k
    for ( int i = int(xImp->aStack.size()) - 1; i >= 0; --i )
603
19.6k
        (*(xImp->aStack.rbegin() + i ))->DoActivate_Impl(xImp->pFrame, bMDI);
604
605
3.93k
    if ( bMDI && xImp->pFrame )
606
3.93k
    {
607
3.93k
        xImp->pFrame->GetFrame().GetWorkWindow_Impl()->HidePopups_Impl( false, 1 );
608
3.93k
    }
609
610
3.93k
    if(!xImp->aToDoStack.empty())
611
0
    {
612
        // No immediate update is requested
613
0
        xImp->aIdle.Start();
614
0
    }
615
3.93k
}
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
3.93k
{
630
3.93k
    SFX_STACK(SfxDispatcher::DoDeactivate);
631
632
3.93k
    SfxApplication *pSfxApp = SfxGetpApp();
633
634
3.93k
    if ( bMDI )
635
3.93k
    {
636
3.93k
        SAL_INFO("sfx.control", "Deactivate Dispatcher " << this);
637
3.93k
        DBG_ASSERT( xImp->bActive, "Deactivate error" );
638
3.93k
        xImp->bActive = false;
639
640
3.93k
        if ( xImp->pFrame && !(xImp->pFrame->GetObjectShell()->IsInPlaceActive() ) )
641
3.93k
        {
642
3.93k
            SfxWorkWindow *pWorkWin = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
643
3.93k
            if ( pWorkWin )
644
3.93k
            {
645
145k
                for (size_t n=0; n<xImp->aChildWins.size();)
646
141k
                {
647
141k
                    SfxChildWindow *pWin = pWorkWin->GetChildWindow_Impl( static_cast<sal_uInt16>( xImp->aChildWins[n] & 0xFFFF ) );
648
141k
                    if (!pWin || pWin->GetAlignment() == SfxChildAlignment::NOALIGNMENT)
649
141k
                        xImp->aChildWins.erase(xImp->aChildWins.begin()+n);
650
0
                    else
651
0
                        n++;
652
141k
                }
653
3.93k
            }
654
3.93k
        }
655
3.93k
    }
656
0
    else {
657
0
        SAL_INFO("sfx.control", "Non-MDI-DeActivate Dispatcher " << this);
658
0
    }
659
660
3.93k
    if ( IsAppDispatcher() && !pSfxApp->IsDowning() )
661
0
        return;
662
663
35.4k
    for ( size_t i = 0; i < xImp->aStack.size(); ++i )
664
31.5k
        (*(xImp->aStack.rbegin() + i))->DoDeactivate_Impl(xImp->pFrame, bMDI);
665
666
3.93k
    bool bHidePopups = bMDI && xImp->pFrame;
667
3.93k
    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
3.93k
    if ( bHidePopups )
680
3.93k
    {
681
3.93k
        xImp->pFrame->GetFrame().GetWorkWindow_Impl()->HidePopups_Impl( true, 1 );
682
3.93k
    }
683
684
3.93k
    Flush();
685
3.93k
}
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
3.93k
{
703
3.93k
    SFX_STACK(SfxDispatcher::GetShellAndSlot_Impl);
704
705
3.93k
    Flush();
706
3.93k
    SfxSlotServer aSvr;
707
3.93k
    if ( FindServer_(nSlot, aSvr) )
708
3.93k
    {
709
3.93k
        if ( bOwnShellsOnly && aSvr.GetShellLevel() >= xImp->aStack.size() )
710
0
            return false;
711
712
3.93k
        *ppShell = GetShell(aSvr.GetShellLevel());
713
3.93k
        *ppSlot = aSvr.GetSlot();
714
3.93k
        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
3.93k
        return !bRealSlot || ((nullptr != *ppSlot) && (nullptr != (*ppSlot)->GetExecFnc()) );
718
3.93k
    }
719
720
0
    return false;
721
3.93k
}
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
7.87k
{
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
7.87k
}
1038
1039
void SfxDispatcher::Update_Impl( bool bForce )
1040
7.87k
{
1041
7.87k
    SFX_STACK(SfxDispatcher::Update_Impl);
1042
1043
7.87k
    Flush();
1044
1045
7.87k
    if ( !xImp->pFrame )
1046
0
        return;
1047
1048
7.87k
    bool bUpdate = bForce;
1049
7.87k
    if ( xImp->pFrame )
1050
7.87k
    {
1051
7.87k
        SfxWorkWindow *pWork = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1052
7.87k
        SfxDispatcher *pAct = pWork->GetBindings().GetDispatcher_Impl();
1053
7.87k
        if (pAct == this)
1054
7.87k
        {
1055
7.87k
            if ( !bUpdate )
1056
3.93k
                bUpdate = !xImp->bUpdated;
1057
7.87k
            xImp->bUpdated = true;
1058
7.87k
        }
1059
7.87k
    }
1060
1061
7.87k
    if ( !bUpdate || xImp->pFrame->GetFrame().IsClosing_Impl() )
1062
0
        return;
1063
1064
7.87k
    SfxViewFrame* pTop = xImp->pFrame ? xImp->pFrame->GetTopViewFrame() : nullptr;
1065
7.87k
    bool bUIActive = pTop && pTop->GetBindings().GetDispatcher() == this;
1066
1067
7.87k
    if ( !bUIActive && pTop && GetBindings() == &pTop->GetBindings() )
1068
        // keep own tools internally for collecting
1069
0
        GetBindings()->GetDispatcher()->xImp->bUpdated = false;
1070
1071
7.87k
    css::uno::Reference< css::frame::XFrame > xFrame;
1072
7.87k
    SfxBindings* pBindings = GetBindings();
1073
7.87k
    if (pBindings)
1074
7.87k
    {
1075
7.87k
        pBindings->DENTERREGISTRATIONS();
1076
7.87k
        xFrame = pBindings->GetActiveFrame();
1077
7.87k
    }
1078
7.87k
    css::uno::Reference< css::beans::XPropertySet > xPropSet( xFrame, css::uno::UNO_QUERY );
1079
7.87k
    css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
1080
7.87k
    if ( xPropSet.is() )
1081
7.87k
    {
1082
7.87k
        try
1083
7.87k
        {
1084
7.87k
            css::uno::Any aValue = xPropSet->getPropertyValue(u"LayoutManager"_ustr);
1085
7.87k
            aValue >>= xLayoutManager;
1086
7.87k
        }
1087
7.87k
        catch (const css::uno::Exception&)
1088
7.87k
        {
1089
0
        }
1090
7.87k
    }
1091
1092
7.87k
    if ( xLayoutManager.is() )
1093
7.87k
        xLayoutManager->lock();
1094
1095
7.87k
    bool bIsIPActive = xImp->pFrame && xImp->pFrame->GetObjectShell()->IsInPlaceActive();
1096
7.87k
    SfxInPlaceClient *pClient = xImp->pFrame ? xImp->pFrame->GetViewShell()->GetUIActiveClient() : nullptr;
1097
7.87k
    if ( bUIActive && /* !bIsIPActive && */ ( !pClient || !pClient->IsObjectUIActive() ) )
1098
7.87k
        SetMenu_Impl();
1099
1100
7.87k
    SfxWorkWindow *pWorkWin = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1101
7.87k
    pWorkWin->ResetStatusBar_Impl();
1102
1103
7.87k
    {
1104
7.87k
        SfxWorkWindow *pWork = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1105
7.87k
        SfxDispatcher *pAct = pWork->GetBindings().GetDispatcher_Impl();
1106
7.87k
        if (pAct == this)
1107
7.87k
        {
1108
7.87k
            pWork->ResetObjectBars_Impl();
1109
7.87k
            pWork->ResetChildWindows_Impl();
1110
7.87k
        }
1111
7.87k
    }
1112
1113
7.87k
    bool bIsActive = false;
1114
7.87k
    SfxDispatcher *pActDispat = pWorkWin->GetBindings().GetDispatcher_Impl();
1115
7.87k
    if ( this == pActDispat )
1116
7.87k
        bIsActive = true;
1117
1118
7.87k
    Update_Impl_( bUIActive, !bIsIPActive, bIsIPActive, pWorkWin );
1119
7.87k
    if (bUIActive || bIsActive)
1120
7.87k
        pWorkWin->UpdateObjectBars_Impl();
1121
1122
7.87k
    if ( pBindings )
1123
7.87k
        pBindings->DLEAVEREGISTRATIONS();
1124
1125
7.87k
    if ( xLayoutManager.is() )
1126
7.87k
        xLayoutManager->unlock();
1127
1128
7.87k
    const SfxViewShell* pViewShell = SfxViewShell::Current();
1129
7.87k
    if (pViewShell && pViewShell->GetDispatcher())
1130
3.93k
    {
1131
3.93k
        SfxPoolItemHolder aItem;
1132
3.93k
        pViewShell->GetDispatcher()->QueryState(SID_NOTEBOOKBAR, aItem);
1133
3.93k
    }
1134
7.87k
}
1135
1136
void SfxDispatcher::Update_Impl_( bool bUIActive, bool bIsMDIApp, bool bIsIPOwner, SfxWorkWindow *pTaskWin )
1137
7.87k
{
1138
7.87k
    SfxWorkWindow *pWorkWin = xImp->pFrame->GetFrame().GetWorkWindow_Impl();
1139
7.87k
    bool bIsActive = false;
1140
7.87k
    SfxDispatcher *pActDispat = pWorkWin->GetBindings().GetDispatcher_Impl();
1141
7.87k
    if ( pActDispat )
1142
7.87k
    {
1143
7.87k
        if ( this == pActDispat )
1144
7.87k
            bIsActive = true;
1145
7.87k
    }
1146
1147
7.87k
    for (SfxObjectBars_Impl & rObjBar : xImp->aObjBars)
1148
102k
        rObjBar.eId = ToolbarId::None;
1149
7.87k
    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
7.87k
    if ( xImp->bQuiet || xImp->bNoUI || (xImp->pFrame && xImp->pFrame->GetObjectShell()->IsPreview()) )
1154
0
        return;
1155
1156
7.87k
    StatusBarId eStatBarId = StatusBarId::None;
1157
7.87k
    const bool isViewerAppMode = officecfg::Office::Common::Misc::ViewerAppMode::get();
1158
1159
7.87k
    SfxSlotPool* pSlotPool = &SfxSlotPool::GetSlotPool( GetFrame() );
1160
7.87k
    sal_uInt16 nTotCount = xImp->aStack.size();
1161
59.0k
    for ( sal_uInt16 nShell = nTotCount; nShell > 0; --nShell )
1162
51.1k
    {
1163
51.1k
        SfxShell *pShell = GetShell( nShell-1 );
1164
51.1k
        if (!pShell)
1165
0
            continue;
1166
1167
51.1k
        SfxInterface *pIFace = pShell->GetInterface();
1168
1169
        // don't consider shells if "Hidden" or "Quiet"
1170
51.1k
        bool bReadOnlyShell = IsReadOnlyShell_Impl( nShell-1 );
1171
51.1k
        sal_uInt16 nNo;
1172
90.5k
        for ( nNo = 0; pIFace && nNo<pIFace->GetObjectBarCount(); ++nNo )
1173
39.3k
        {
1174
39.3k
            sal_uInt16 nPos = pIFace->GetObjectBarPos(nNo);
1175
39.3k
            SfxVisibilityFlags nFlags = pIFace->GetObjectBarFlags(nNo);
1176
39.3k
            if ( bReadOnlyShell && !( nFlags & SfxVisibilityFlags::ReadonlyDoc ) )
1177
0
                continue;
1178
1179
            // check whether toolbar needs activation of a special feature
1180
39.3k
            SfxShellFeature nFeature = pIFace->GetObjectBarFeature(nNo);
1181
39.3k
            if ((nFeature != SfxShellFeature::NONE) && !pShell->HasUIFeature(nFeature))
1182
11.8k
                continue;
1183
1184
            // check for toolboxes that are exclusively for a viewer
1185
27.5k
            if ( xImp->pFrame)
1186
27.5k
            {
1187
27.5k
                bool bViewerTbx( nFlags & SfxVisibilityFlags::Viewer );
1188
27.5k
                SfxObjectShell* pSh = xImp->pFrame->GetObjectShell();
1189
27.5k
                const SfxMedium* pMedium = pSh->GetMedium();
1190
27.5k
                const SfxBoolItem* pItem = pMedium ? pMedium->GetItemSet().GetItem(SID_VIEWONLY, false) : nullptr;
1191
27.5k
                bool bIsViewer = pItem && pItem->GetValue();
1192
27.5k
                if ( bIsViewer != bViewerTbx )
1193
7.87k
                    continue;
1194
27.5k
            }
1195
1196
            // always register toolbars, allows to switch them on
1197
19.6k
            bool bVisible = pIFace->IsObjectBarVisible(nNo);
1198
19.6k
            if ( !bVisible )
1199
0
                nFlags = SfxVisibilityFlags::Invisible;
1200
1201
19.6k
            SfxObjectBars_Impl& rBar = xImp->aObjBars[nPos];
1202
19.6k
            rBar.nPos = nPos;
1203
19.6k
            rBar.nFlags = nFlags;
1204
19.6k
            rBar.eId = pIFace->GetObjectBarId(nNo);
1205
1206
19.6k
            if ( bUIActive || bIsActive )
1207
19.6k
            {
1208
19.6k
                pWorkWin->SetObjectBar_Impl(nPos, nFlags, rBar.eId);
1209
19.6k
            }
1210
1211
19.6k
            if ( !bVisible )
1212
0
                rBar.eId = ToolbarId::None;
1213
19.6k
        }
1214
1215
307k
        for ( nNo=0; pIFace && nNo<pIFace->GetChildWindowCount(); nNo++ )
1216
255k
        {
1217
255k
            sal_uInt32 nId = pIFace->GetChildWindowId(nNo);
1218
255k
            const SfxSlot *pSlot = pSlotPool->GetSlot( static_cast<sal_uInt16>(nId) );
1219
255k
            SAL_INFO_IF( !pSlot, "sfx.control", "Childwindow slot missing: " << nId );
1220
1221
255k
            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
255k
            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
255k
            SfxShellFeature nFeature = pIFace->GetChildWindowFeature(nNo);
1236
255k
            if ((nFeature != SfxShellFeature::NONE) && !pShell->HasUIFeature(nFeature))
1237
23.6k
                continue;
1238
1239
            // slot decides whether a ChildWindow is shown when document is OLE server or OLE client
1240
232k
            SfxVisibilityFlags nMode = SfxVisibilityFlags::Standard;
1241
232k
            if( pSlot )
1242
232k
            {
1243
232k
                if ( pSlot->IsMode(SfxSlotMode::CONTAINER) )
1244
23.6k
                {
1245
23.6k
                    if ( pWorkWin->IsVisible_Impl( SfxVisibilityFlags::Client ) )
1246
23.6k
                        nMode |= SfxVisibilityFlags::Client;
1247
23.6k
                }
1248
208k
                else
1249
208k
                {
1250
208k
                    if ( pWorkWin->IsVisible_Impl( SfxVisibilityFlags::Server ) )
1251
208k
                        nMode |= SfxVisibilityFlags::Server;
1252
208k
                }
1253
232k
            }
1254
1255
232k
            if ( bUIActive || bIsActive )
1256
232k
                pWorkWin->SetChildWindowVisible_Impl( nId, true, nMode );
1257
232k
            if ( bUIActive || bIsActive || !pWorkWin->IsFloating( static_cast<sal_uInt16>( nId & 0xFFFF ) ) )
1258
232k
                xImp->aChildWins.push_back( nId );
1259
232k
        }
1260
1261
51.1k
        if ( bIsMDIApp || bIsIPOwner )
1262
51.1k
        {
1263
51.1k
            StatusBarId eId = pIFace ? pIFace->GetStatusBarId() : StatusBarId::None;
1264
51.1k
            if (eId != StatusBarId::None)
1265
15.7k
                eStatBarId = eId;
1266
51.1k
        }
1267
51.1k
    }
1268
1269
110k
    for ( sal_uInt16 nPos=0; nPos<SFX_OBJECTBAR_MAX; nPos++ )
1270
102k
    {
1271
102k
        SfxObjectBars_Impl& rFixed = xImp->aFixedObjBars[nPos];
1272
102k
        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
102k
    }
1280
1281
7.87k
    if ( !pTaskWin || ( !bIsMDIApp && !bIsIPOwner ) )
1282
0
        return;
1283
1284
7.87k
    bool bIsTaskActive = false;
1285
1286
7.87k
    SfxDispatcher *pActDispatcher = pTaskWin->GetBindings().GetDispatcher_Impl();
1287
7.87k
    if ( pActDispatcher )
1288
7.87k
    {
1289
7.87k
        if ( this == pActDispatcher )
1290
7.87k
            bIsTaskActive = true;
1291
7.87k
    }
1292
1293
7.87k
    if (bIsTaskActive && eStatBarId != StatusBarId::None && xImp->pFrame)
1294
7.87k
    {
1295
        // internal frames also may control statusbar
1296
7.87k
        xImp->pFrame->GetFrame().GetWorkWindow_Impl()->SetStatusBar_Impl(eStatBarId);
1297
7.87k
    }
1298
7.87k
}
1299
1300
/** Helper method to execute the outstanding push and pop commands.
1301
*/
1302
void SfxDispatcher::FlushImpl()
1303
19.7k
{
1304
19.7k
    SFX_STACK(SfxDispatcher::FlushImpl);
1305
1306
19.7k
    SAL_INFO("sfx.control", "Flushing dispatcher!");
1307
1308
19.7k
    xImp->aIdle.Stop();
1309
1310
19.7k
    xImp->bFlushing = !xImp->bFlushing;
1311
19.7k
    if ( !xImp->bFlushing )
1312
0
    {
1313
0
        xImp->bFlushing = true;
1314
0
        return;
1315
0
    }
1316
1317
19.7k
    SfxApplication *pSfxApp = SfxGetpApp();
1318
1319
    // Re-build the true stack in the first round
1320
19.7k
    std::deque<SfxToDo_Impl> aToDoCopy;
1321
19.7k
    bool bModify = false;
1322
63.0k
    for(std::deque<SfxToDo_Impl>::reverse_iterator i = xImp->aToDoStack.rbegin(); i != xImp->aToDoStack.rend(); ++i)
1323
43.3k
    {
1324
43.3k
        bModify = true;
1325
1326
43.3k
        if(i->bPush)
1327
31.5k
        {
1328
            // Actually push
1329
31.5k
            DBG_ASSERT( std::find(xImp->aStack.begin(), xImp->aStack.end(), i->pCluster) == xImp->aStack.end(),
1330
31.5k
                       "pushed SfxShell already on stack" );
1331
31.5k
            xImp->aStack.push_back(i->pCluster);
1332
31.5k
            i->pCluster->SetDisableFlags(xImp->nDisableFlags);
1333
1334
            // Mark the moved shell
1335
31.5k
            aToDoCopy.push_front(*i);
1336
31.5k
        }
1337
11.8k
        else
1338
11.8k
        {
1339
            // Actually pop
1340
11.8k
            bool bFound = false;
1341
11.8k
            if (!i->bUntil)
1342
7.88k
            {
1343
                // pop exactly the requested shell
1344
7.88k
                if (auto it = std::find(xImp->aStack.begin(), xImp->aStack.end(), i->pCluster);
1345
7.88k
                    it != xImp->aStack.end())
1346
7.88k
                {
1347
7.88k
                    xImp->aStack.erase(it);
1348
7.88k
                    i->pCluster->SetDisableFlags(SfxDisableFlags::NONE);
1349
7.88k
                    bFound = true;
1350
1351
                    // Mark the moved Shell
1352
7.88k
                    aToDoCopy.push_front(SfxToDo_Impl(false, i->bDelete, false, *i->pCluster));
1353
7.88k
                }
1354
7.88k
            }
1355
23.6k
            while (!bFound)
1356
11.8k
            {
1357
11.8k
                DBG_ASSERT( !xImp->aStack.empty(), "popping from empty stack" );
1358
11.8k
                SfxShell* pPopped = xImp->aStack.back();
1359
11.8k
                xImp->aStack.pop_back();
1360
11.8k
                pPopped->SetDisableFlags( SfxDisableFlags::NONE );
1361
11.8k
                bFound = (pPopped == i->pCluster);
1362
1363
                // Mark the moved Shell
1364
11.8k
                aToDoCopy.push_front(SfxToDo_Impl(false, i->bDelete, false, *pPopped));
1365
11.8k
                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
11.8k
            }
1373
11.8k
            DBG_ASSERT( bFound, "wrong SfxShell popped" );
1374
11.8k
        }
1375
43.3k
    }
1376
19.7k
    xImp->aToDoStack.clear();
1377
1378
    // Invalidate bindings, if possible
1379
19.7k
    if ( !pSfxApp->IsDowning() )
1380
19.7k
    {
1381
19.7k
        InvalidateBindings_Impl( bModify );
1382
19.7k
    }
1383
1384
19.7k
    xImp->bFlushing = false;
1385
19.7k
    xImp->bUpdated = false; // not only when bModify, if Doc/Template-Config
1386
19.7k
    xImp->bFlushed = true;
1387
19.7k
    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
19.7k
    xImp->aToDoCopyStack.push_back(aToDoCopy);
1394
19.7k
    std::deque<SfxToDo_Impl>& rToDoCopy = xImp->aToDoCopyStack.back();
1395
    // Activate the Shells and possible delete them in the 2nd round
1396
70.9k
    for(std::deque<SfxToDo_Impl>::reverse_iterator i = rToDoCopy.rbegin(); i != rToDoCopy.rend(); ++i)
1397
51.2k
    {
1398
51.2k
        if (i->bDeleted)
1399
0
            continue;
1400
51.2k
        if (!xImp->bActive)
1401
39.4k
            continue;
1402
11.8k
        if (i->bPush)
1403
11.8k
            i->pCluster->DoActivate_Impl(xImp->pFrame, true);
1404
10
        else
1405
10
            i->pCluster->DoDeactivate_Impl(xImp->pFrame, true);
1406
11.8k
    }
1407
1408
19.7k
    aToDoCopy = xImp->aToDoCopyStack.back();
1409
19.7k
    xImp->aToDoCopyStack.pop_back();
1410
1411
70.9k
    for(std::deque<SfxToDo_Impl>::reverse_iterator i = aToDoCopy.rbegin(); i != aToDoCopy.rend(); ++i)
1412
51.2k
    {
1413
51.2k
        if (i->bDelete && !i->bDeleted)
1414
11.8k
        {
1415
11.8k
            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
11.8k
            delete i->pCluster;
1429
11.8k
        }
1430
51.2k
    }
1431
19.7k
    bool bAwakeBindings = !aToDoCopy.empty();
1432
19.7k
    if( bAwakeBindings )
1433
19.7k
        aToDoCopy.clear();
1434
1435
    // If more changes have occurred on the stack when
1436
    // Activate/Deactivate/Delete:
1437
19.7k
    if (!xImp->bFlushed)
1438
        // If Push/Pop has been called by someone, then also EnterReg was called!
1439
0
        FlushImpl();
1440
1441
19.7k
    if( bAwakeBindings && GetBindings() )
1442
19.6k
        GetBindings()->DLEAVEREGISTRATIONS();
1443
1444
19.7k
    for (SfxObjectBars_Impl & rFixedObjBar : xImp->aFixedObjBars)
1445
256k
        rFixedObjBar.eId = ToolbarId::None;
1446
1447
19.7k
    SAL_INFO("sfx.control", "SfxDispatcher(" << this << ")::Flush() done");
1448
19.7k
}
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
3.93k
{
1515
    // no filter?
1516
3.93k
    if ( xImp->pFilterSIDs.empty() )
1517
        // => all SIDs allowed
1518
3.93k
        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
static bool IsCommandAllowedInLokReadOnlyViewMode(std::u16string_view commandName,
1535
                                                  const SfxViewShell& viewShell)
1536
0
{
1537
0
    if (viewShell.IsAllowChangeComments())
1538
0
    {
1539
0
        static constexpr std::u16string_view allowed[] = {
1540
0
            u".uno:InsertAnnotation",
1541
0
            u".uno:ReplyComment",
1542
0
            u".uno:ResolveComment",
1543
0
            u".uno:ResolveCommentThread",
1544
0
            u".uno:DeleteComment",
1545
0
            u".uno:DeleteAnnotation",
1546
0
            u".uno:EditAnnotation",
1547
0
            u".uno:PromoteComment",
1548
0
            u".uno:Save",
1549
0
        };
1550
1551
0
        if (std::find(std::begin(allowed), std::end(allowed), commandName) != std::end(allowed))
1552
0
            return true;
1553
0
    }
1554
0
    if (viewShell.IsAllowManageRedlines())
1555
0
    {
1556
0
        static constexpr std::u16string_view allowed[] = {
1557
0
            u".uno:AcceptTrackedChange",
1558
0
            u".uno:RejectTrackedChange",
1559
0
            u".uno:AcceptAllTrackedChanges",
1560
0
            u".uno:RejectAllTrackedChanges",
1561
0
            u".uno:AcceptTrackedChangeToNext",
1562
0
            u".uno:RejectTrackedChangeToNext",
1563
0
            u".uno:CommentChangeTracking",
1564
0
            u".uno:Save",
1565
0
        };
1566
1567
0
        if (std::find(std::begin(allowed), std::end(allowed), commandName) != std::end(allowed))
1568
0
            return true;
1569
0
    }
1570
0
    return false;
1571
0
}
1572
1573
/** This helper method searches for the <Slot-Server> which currently serves
1574
    the nSlot. As the result, rServe is filled accordingly.
1575
1576
    If known the SfxInterface which is currently served by nSlot can be
1577
    passed along.
1578
1579
    The SfxDispatcher is flushed while searching for nSlot.
1580
1581
    @param nSlot Slot-Id to search for
1582
    @param rServer <SfxSlotServer>-Instance to fill
1583
1584
    @return         true
1585
                    The Slot was found, rServer is valid.
1586
1587
                    false
1588
                    The Slot is currently not served, rServer is invalid.
1589
*/
1590
bool SfxDispatcher::FindServer_(sal_uInt16 nSlot, SfxSlotServer& rServer)
1591
3.93k
{
1592
3.93k
    SFX_STACK(SfxDispatcher::FindServer_);
1593
1594
    // Dispatcher locked? (nevertheless let SID_HELP_PI through)
1595
3.93k
    if ( IsLocked() )
1596
0
    {
1597
0
        xImp->bInvalidateOnUnlock = true;
1598
0
        return false;
1599
0
    }
1600
1601
    // Count the number of Shells in the linked dispatchers.
1602
3.93k
    Flush();
1603
3.93k
    sal_uInt16 nTotCount = xImp->aStack.size();
1604
1605
    // Verb-Slot?
1606
3.93k
    if (nSlot >= SID_VERB_START && nSlot <= SID_VERB_END)
1607
0
    {
1608
0
        for ( sal_uInt16 nShell = 0;; ++nShell )
1609
0
        {
1610
0
            SfxShell *pSh = GetShell(nShell);
1611
0
            if ( pSh == nullptr )
1612
0
                return false;
1613
0
            if ( dynamic_cast< const SfxViewShell *>( pSh ) !=  nullptr )
1614
0
            {
1615
0
                const SfxSlot* pSlot = pSh->GetVerbSlot_Impl(nSlot);
1616
0
                if ( pSlot )
1617
0
                {
1618
0
                    rServer.SetShellLevel(nShell);
1619
0
                    rServer.SetSlot( pSlot );
1620
0
                    return true;
1621
0
                }
1622
0
            }
1623
0
        }
1624
0
    }
1625
1626
    // SID check against set filter
1627
3.93k
    SfxSlotFilterState nSlotEnableMode = SfxSlotFilterState::DISABLED;
1628
3.93k
    if ( xImp->pFrame )
1629
3.93k
    {
1630
3.93k
        nSlotEnableMode = IsSlotEnabledByFilter_Impl( nSlot );
1631
3.93k
        if ( SfxSlotFilterState::DISABLED == nSlotEnableMode )
1632
0
            return false;
1633
3.93k
    }
1634
1635
    // In Quiet-Mode only Parent-Dispatcher
1636
3.93k
    if ( xImp->bQuiet )
1637
0
    {
1638
0
        return false;
1639
0
    }
1640
1641
3.93k
    const bool isViewerAppMode = officecfg::Office::Common::Misc::ViewerAppMode::get();
1642
3.93k
    const bool bReadOnlyGlobal = SfxSlotFilterState::ENABLED_READONLY != nSlotEnableMode && xImp->bReadOnly;
1643
3.93k
    const bool bReadOnlyLokView = !bReadOnlyGlobal && comphelper::LibreOfficeKit::isActive()
1644
0
                                  && xImp->pFrame && xImp->pFrame->GetViewShell()
1645
0
                                  && xImp->pFrame->GetViewShell()->IsLokReadOnlyView();
1646
1647
3.93k
    const bool bIsInPlace = xImp->pFrame && xImp->pFrame->GetObjectShell()->IsInPlaceActive();
1648
    // Shell belongs to Server?
1649
    // AppDispatcher or IPFrame-Dispatcher
1650
3.93k
    bool bIsServerShell = !xImp->pFrame || bIsInPlace;
1651
    // Of course ShellServer-Slots are also executable even when it is
1652
    // executed on a container dispatcher without an IPClient.
1653
3.93k
    if (!bIsServerShell)
1654
3.93k
    {
1655
3.93k
        SfxViewShell* pViewSh = xImp->pFrame->GetViewShell();
1656
3.93k
        bIsServerShell = !pViewSh || !pViewSh->GetUIActiveClient();
1657
3.93k
    }
1658
    // Shell belongs to Container?
1659
    // AppDispatcher or no IPFrameDispatcher
1660
3.93k
    const bool bIsContainerShell = !bIsInPlace;
1661
1662
    // search through all the shells of the chained dispatchers
1663
    // from top to bottom
1664
19.6k
    for (sal_uInt16 i = 0; i < nTotCount; ++i)
1665
19.6k
    {
1666
19.6k
        SfxShell *pObjShell = GetShell(i);
1667
19.6k
        if (!pObjShell)
1668
0
            continue;
1669
1670
19.6k
        SfxInterface *pIFace = pObjShell->GetInterface();
1671
19.6k
        const SfxSlot *pSlot = pIFace->GetSlot(nSlot);
1672
19.6k
        if (!pSlot)
1673
15.7k
            continue;
1674
1675
        // Slot belongs to Container?
1676
3.93k
        bool bIsContainerSlot = pSlot->IsMode(SfxSlotMode::CONTAINER);
1677
1678
        // Shell and Slot match
1679
3.93k
        if ( !( ( bIsContainerSlot && bIsContainerShell ) ||
1680
3.93k
                ( !bIsContainerSlot && bIsServerShell ) ) )
1681
0
            continue;
1682
1683
3.93k
        if ( pSlot->nDisableFlags != SfxDisableFlags::NONE &&
1684
0
             ( static_cast<int>(pSlot->nDisableFlags) & static_cast<int>(pObjShell->GetDisableFlags()) ) != 0 )
1685
0
            return false;
1686
1687
3.93k
        if (!(pSlot->nFlags & SfxSlotMode::VIEWERAPP) && isViewerAppMode)
1688
0
            return false;
1689
1690
        // The slot is not read-only
1691
3.93k
        if (!(pSlot->nFlags & SfxSlotMode::READONLYDOC))
1692
0
        {
1693
            // 1. The global context is read-only
1694
0
            if (bReadOnlyGlobal)
1695
0
            {
1696
0
                bool bAllowThis = false;
1697
                // Enable insert new annotation in Writer in read-only mode
1698
0
                if (getenv("EDIT_COMMENT_IN_READONLY_MODE") != nullptr)
1699
0
                {
1700
0
                    OUString sCommand = pSlot->GetCommand();
1701
0
                    if (sCommand == u".uno:InsertAnnotation"_ustr
1702
0
                        || sCommand == u".uno:Undo"_ustr
1703
0
                        || sCommand == u".uno:Redo"_ustr
1704
0
                        || ((sCommand == u".uno:FontDialog"_ustr
1705
0
                             || sCommand == u".uno:ParagraphDialog"_ustr)
1706
0
                            && pIFace->GetClassName() == "SwAnnotationShell"_ostr))
1707
0
                    {
1708
0
                        bAllowThis = true;
1709
0
                    }
1710
0
                }
1711
0
                if (!bAllowThis)
1712
0
                    return false;
1713
0
            }
1714
1715
            // 2. LOK view context is read-only
1716
0
            if (bReadOnlyLokView)
1717
0
            {
1718
0
                if (!IsCommandAllowedInLokReadOnlyViewMode(pSlot->GetCommand(),
1719
0
                                                           *xImp->pFrame->GetViewShell()))
1720
0
                {
1721
0
                    SAL_WARN("sfx.control", "SfxDispatcher::FindServer_: rejecting command '"
1722
0
                                                << pSlot->GetCommand()
1723
0
                                                << "', not allowed in LOK read-only view mode");
1724
0
                    return false;
1725
0
                }
1726
0
            }
1727
0
        }
1728
1729
3.93k
        rServer.SetSlot(pSlot);
1730
3.93k
        rServer.SetShellLevel(i);
1731
3.93k
        return true;
1732
3.93k
    }
1733
1734
0
    return false;
1735
3.93k
}
1736
1737
/** Helper method to obtain the status of the <Slot-Server>s rSvr.
1738
    The required slots IDs (partly converted to Which-IDs of the pool)
1739
    must be present in rstate.
1740
1741
    The SfxDispatcher is flushed before the query.
1742
1743
    @param rSvr Slot-Server to query
1744
    @param rState SfxItemSet to be filled
1745
    @param pRealSlot The actual Slot if possible
1746
*/
1747
bool SfxDispatcher::FillState_(const SfxSlotServer& rSvr, SfxItemSet& rState,
1748
        const SfxSlot* pRealSlot)
1749
0
{
1750
0
    SFX_STACK(SfxDispatcher::FillState_);
1751
1752
0
    const SfxSlot *pSlot = rSvr.GetSlot();
1753
0
    if ( pSlot && IsLocked() )
1754
0
    {
1755
0
        xImp->bInvalidateOnUnlock = true;
1756
0
        return false;
1757
0
    }
1758
1759
0
    if ( pSlot )
1760
0
    {
1761
0
        DBG_ASSERT(xImp->bFlushed,
1762
0
                "Dispatcher not flushed after retrieving slot servers!");
1763
0
        if (!xImp->bFlushed)
1764
0
            return false;
1765
1766
        // Determine the object and call the Message of this object
1767
0
        SfxShell *pSh = GetShell(rSvr.GetShellLevel());
1768
0
        if (!pSh)
1769
0
            return false;
1770
1771
0
        SfxStateFunc pFunc;
1772
1773
0
        if (pRealSlot)
1774
0
            pFunc = pRealSlot->GetStateFnc();
1775
0
        else
1776
0
            pFunc = pSlot->GetStateFnc();
1777
1778
0
        (*pFunc)(pSh, rState);
1779
#ifdef DBG_UTIL
1780
        // To examine the conformity of IDL (SlotMap) and current Items
1781
        if ( rState.Count() )
1782
        {
1783
            SfxInterface *pIF = pSh->GetInterface();
1784
            for (SfxItemIter aIter( rState ); !aIter.IsAtEnd(); aIter.Next())
1785
            {
1786
                const SfxPoolItem* pItem = aIter.GetCurItem();
1787
                if ( !IsInvalidItem(pItem) && !IsDisabledItem(pItem) )
1788
                {
1789
                    sal_uInt16 nSlotId = rState.GetPool()->GetSlotId(pItem->Which());
1790
                    SAL_INFO_IF(
1791
                        typeid(pItem) != *pIF->GetSlot(nSlotId)->GetType()->Type(),
1792
                        "sfx.control",
1793
                        "item-type unequal to IDL (=> no BASIC) with SID: "
1794
                            << nSlotId << " in " << pIF->GetClassName());
1795
                }
1796
            }
1797
        }
1798
#endif
1799
1800
0
        return true;
1801
0
    }
1802
1803
0
    return false;
1804
0
}
1805
1806
void SfxDispatcher::ExecutePopup( vcl::Window *pWin, const Point *pPos )
1807
0
{
1808
0
    SfxDispatcher &rDisp = *SfxGetpApp()->GetDispatcher_Impl();
1809
0
    sal_uInt16 nShLevel = 0;
1810
0
    SfxShell *pSh;
1811
1812
0
    if ( rDisp.xImp->bQuiet )
1813
0
        nShLevel = rDisp.xImp->aStack.size();
1814
1815
0
    for ( pSh = rDisp.GetShell(nShLevel); pSh; ++nShLevel, pSh = rDisp.GetShell(nShLevel) )
1816
0
    {
1817
0
        const OUString& rResName = pSh->GetInterface()->GetPopupMenuName();
1818
0
        if ( !rResName.isEmpty() )
1819
0
        {
1820
0
            rDisp.ExecutePopup( rResName, pWin, pPos );
1821
0
            return;
1822
0
        }
1823
0
    }
1824
0
}
1825
1826
namespace {
1827
1828
boost::property_tree::ptree fillPopupMenu(Menu* pMenu)
1829
0
{
1830
    // Activate this menu first
1831
0
    pMenu->HandleMenuActivateEvent(pMenu);
1832
0
    pMenu->HandleMenuDeActivateEvent(pMenu);
1833
1834
0
    boost::property_tree::ptree aTree;
1835
    // If last item inserted is some valid text
1836
0
    bool bIsLastItemText = false;
1837
0
    sal_uInt16 nCount = pMenu->GetItemCount();
1838
0
    for (sal_uInt16 nPos = 0; nPos < nCount; nPos++)
1839
0
    {
1840
0
        boost::property_tree::ptree aItemTree;
1841
0
        const MenuItemType aItemType = pMenu->GetItemType(nPos);
1842
1843
0
        if (aItemType == MenuItemType::DONTKNOW)
1844
0
            continue;
1845
1846
0
        if (aItemType == MenuItemType::SEPARATOR)
1847
0
        {
1848
0
            if (bIsLastItemText)
1849
0
                aItemTree.put("type", "separator");
1850
0
            bIsLastItemText = false;
1851
0
        }
1852
0
        else
1853
0
        {
1854
0
            const sal_uInt16 nItemId = pMenu->GetItemId(nPos);
1855
0
            OUString aCommandURL = pMenu->GetItemCommand(nItemId);
1856
1857
0
            if (aCommandURL.isEmpty())
1858
0
            {
1859
0
                const SfxSlot *pSlot = SFX_SLOTPOOL().GetSlot(nItemId);
1860
0
                if (pSlot)
1861
0
                    aCommandURL = pSlot->GetCommand();
1862
0
            }
1863
1864
0
            const OUString aItemText = pMenu->GetItemText(nItemId);
1865
0
            Menu* pPopupSubmenu = pMenu->GetPopupMenu(nItemId);
1866
1867
0
            if (!aItemText.isEmpty())
1868
0
                aItemTree.put("text", aItemText.toUtf8().getStr());
1869
1870
0
            if (pPopupSubmenu)
1871
0
            {
1872
0
                boost::property_tree::ptree aSubmenu = ::fillPopupMenu(pPopupSubmenu);
1873
0
                if (aSubmenu.empty())
1874
0
                    continue;
1875
1876
0
                aItemTree.put("type", "menu");
1877
0
                if (!aCommandURL.isEmpty())
1878
0
                    aItemTree.put("command", aCommandURL.toUtf8().getStr());
1879
0
                aItemTree.push_back(std::make_pair("menu", aSubmenu));
1880
0
            }
1881
0
            else
1882
0
            {
1883
                // no point in exposing choices that don't have the .uno:
1884
                // command
1885
0
                if (aCommandURL.isEmpty())
1886
0
                    continue;
1887
1888
0
                aItemTree.put("type", "command");
1889
0
                aItemTree.put("command", aCommandURL.toUtf8().getStr());
1890
0
            }
1891
1892
0
            aItemTree.put("enabled", pMenu->IsItemEnabled(nItemId));
1893
1894
0
            MenuItemBits aItemBits = pMenu->GetItemBits(nItemId);
1895
0
            bool bHasChecks = true;
1896
0
            if (aItemBits & MenuItemBits::CHECKABLE)
1897
0
                aItemTree.put("checktype", "checkmark");
1898
0
            else if (aItemBits & MenuItemBits::RADIOCHECK)
1899
0
                aItemTree.put("checktype", "radio");
1900
0
            else if (aItemBits & MenuItemBits::AUTOCHECK)
1901
0
                aItemTree.put("checktype", "auto");
1902
0
            else
1903
0
                bHasChecks = false;
1904
1905
0
            if (bHasChecks)
1906
0
                aItemTree.put("checked", pMenu->IsItemChecked(nItemId));
1907
0
        }
1908
1909
0
        if (!aItemTree.empty())
1910
0
        {
1911
0
            aTree.push_back(std::make_pair("", aItemTree));
1912
0
            if (aItemType != MenuItemType::SEPARATOR)
1913
0
                bIsLastItemText = true;
1914
0
        }
1915
0
    }
1916
1917
0
    return aTree;
1918
0
}
1919
1920
}
1921
1922
boost::property_tree::ptree SfxDispatcher::fillPopupMenu(const rtl::Reference<VCLXPopupMenu>& rPopupMenu)
1923
0
{
1924
0
    PopupMenu* pVCLMenu = static_cast<PopupMenu*>(rPopupMenu->GetMenu());
1925
0
    return ::fillPopupMenu(pVCLMenu);
1926
0
}
1927
1928
void SfxDispatcher::ExecutePopup( const OUString& rResName, vcl::Window* pWin, const Point* pPos )
1929
0
{
1930
0
    css::uno::Sequence< css::uno::Any > aArgs{
1931
0
        css::uno::Any(comphelper::makePropertyValue( u"Value"_ustr, rResName )),
1932
0
        css::uno::Any(comphelper::makePropertyValue( u"Frame"_ustr, GetFrame()->GetFrame().GetFrameInterface() )),
1933
0
        css::uno::Any(comphelper::makePropertyValue( u"IsContextMenu"_ustr, true ))
1934
0
    };
1935
1936
0
    const css::uno::Reference< css::uno::XComponentContext >& xContext = comphelper::getProcessComponentContext();
1937
0
    css::uno::Reference< css::frame::XPopupMenuController > xPopupController(
1938
0
        xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
1939
0
        u"com.sun.star.comp.framework.ResourceMenuController"_ustr, aArgs, xContext ), css::uno::UNO_QUERY );
1940
#if defined EMSCRIPTEN && ENABLE_QT5
1941
    // At least under Emscripten with Qt5, the QMenu::exec underlying the below call to
1942
    // xPopupMenu->execute returns immediately, without going into a new event loop, and we need to
1943
    // keep the underlying QMenu instance alive via the static lastPopupController chain here, until
1944
    // the next popup menu is opened (there can only ever be a single popup menu open, so it
1945
    // suffices to have a single static lastPopupController instance):
1946
    static css::uno::Reference<css::frame::XPopupMenuController> lastPopupController;
1947
    if (lastPopupController.is()) {
1948
        if (css::uno::Reference<css::lang::XComponent> component(
1949
                lastPopupController, css::uno::UNO_QUERY);
1950
            component.is())
1951
        {
1952
            component->dispose();
1953
        }
1954
        lastPopupController = xPopupController;
1955
    }
1956
#endif
1957
1958
0
    rtl::Reference< VCLXPopupMenu > xPopupMenu = new VCLXPopupMenu();
1959
1960
0
    if ( !xPopupController.is() || !xPopupMenu.is() )
1961
0
        return;
1962
1963
0
    vcl::Window* pWindow = pWin ? pWin : xImp->pFrame->GetFrame().GetWorkWindow_Impl()->GetWindow();
1964
0
    Point aPos = pPos ? *pPos : pWindow->GetPointerPosPixel();
1965
1966
0
    css::ui::ContextMenuExecuteEvent aEvent;
1967
0
    aEvent.SourceWindow = VCLUnoHelper::GetInterface( pWindow );
1968
0
    aEvent.ExecutePosition.X = aPos.X();
1969
0
    aEvent.ExecutePosition.Y = aPos.Y();
1970
1971
0
    xPopupController->setPopupMenu( xPopupMenu );
1972
0
    if (comphelper::LibreOfficeKit::isActive())
1973
0
    {
1974
0
        boost::property_tree::ptree aMenu = fillPopupMenu(xPopupMenu);
1975
0
        boost::property_tree::ptree aRoot;
1976
0
        aRoot.add_child("menu", aMenu);
1977
1978
0
        std::stringstream aStream;
1979
0
        boost::property_tree::write_json(aStream, aRoot, true);
1980
0
        if (SfxViewShell* pViewShell = xImp->pFrame->GetViewShell())
1981
0
            pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_MENU, OString(aStream.str()));
1982
0
    }
1983
0
    else
1984
0
    {
1985
0
        OUString aMenuURL = "private:resource/popupmenu/" + rResName;
1986
0
        if (GetFrame()->GetViewShell()->TryContextMenuInterception(xPopupMenu, aMenuURL, aEvent))
1987
0
        {
1988
0
            css::uno::Reference<css::awt::XWindowPeer> xParent(aEvent.SourceWindow, css::uno::UNO_QUERY);
1989
0
            xPopupMenu->execute(xParent, css::awt::Rectangle(aPos.X(), aPos.Y(), 1, 1), css::awt::PopupMenuDirection::EXECUTE_DOWN);
1990
0
        }
1991
0
    }
1992
1993
0
#if !(defined EMSCRIPTEN && ENABLE_QT5)
1994
0
    css::uno::Reference< css::lang::XComponent > xComponent( xPopupController, css::uno::UNO_QUERY );
1995
0
    if ( xComponent.is() )
1996
0
        xComponent->dispose();
1997
0
#endif
1998
0
}
1999
2000
/** With this method the SfxDispatcher can be locked and released. A locked
2001
    SfxDispatcher does not perform <SfxRequest>s and does no longer provide
2002
    status information. It behaves as if all the slots were disabled.
2003
*/
2004
void SfxDispatcher::Lock( bool bLock )
2005
16.0k
{
2006
16.0k
    SfxBindings* pBindings = GetBindings();
2007
16.0k
    if ( !bLock && xImp->bLocked && xImp->bInvalidateOnUnlock )
2008
0
    {
2009
0
        if ( pBindings )
2010
0
            pBindings->InvalidateAll(true);
2011
0
        xImp->bInvalidateOnUnlock = false;
2012
0
    }
2013
16.0k
    else if ( pBindings )
2014
16.0k
        pBindings->InvalidateAll(false);
2015
16.0k
    xImp->bLocked = bLock;
2016
16.0k
    if ( !bLock )
2017
8.02k
    {
2018
8.02k
        for(size_t i = 0; i < xImp->aReqArr.size(); ++i)
2019
0
            xImp->xPoster->Post(std::move(xImp->aReqArr[i]));
2020
8.02k
        xImp->aReqArr.clear();
2021
8.02k
    }
2022
16.0k
}
2023
2024
ToolbarId SfxDispatcher::GetObjectBarId( sal_uInt16 nPos ) const
2025
4
{
2026
4
    return xImp->aObjBars[nPos].eId;
2027
4
}
2028
2029
void SfxDispatcher::HideUI( bool bHide )
2030
3.93k
{
2031
3.93k
    bool bWasHidden = xImp->bNoUI;
2032
3.93k
    xImp->bNoUI = bHide;
2033
3.93k
    if ( xImp->pFrame )
2034
3.93k
    {
2035
3.93k
        SfxViewFrame* pTop = xImp->pFrame->GetTopViewFrame();
2036
3.93k
        if ( pTop && pTop->GetBindings().GetDispatcher() == this )
2037
3.93k
        {
2038
3.93k
            SfxFrame& rFrame = pTop->GetFrame();
2039
3.93k
            if ( rFrame.IsMenuBarOn_Impl() )
2040
3.93k
            {
2041
3.93k
                css::uno::Reference < css::beans::XPropertySet > xPropSet( rFrame.GetFrameInterface(), css::uno::UNO_QUERY );
2042
3.93k
                if ( xPropSet.is() )
2043
3.93k
                {
2044
3.93k
                    css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
2045
3.93k
                    css::uno::Any aValue = xPropSet->getPropertyValue(u"LayoutManager"_ustr);
2046
3.93k
                    aValue >>= xLayoutManager;
2047
3.93k
                    if ( xLayoutManager.is() )
2048
3.93k
                        xLayoutManager->setVisible( !bHide );
2049
3.93k
                }
2050
3.93k
            }
2051
3.93k
        }
2052
3.93k
    }
2053
2054
3.93k
    if ( bHide != bWasHidden )
2055
0
        Update_Impl( true );
2056
3.93k
}
2057
2058
void SfxDispatcher::SetReadOnly_Impl( bool bOn )
2059
3.93k
{
2060
3.93k
    xImp->bReadOnly = bOn;
2061
3.93k
}
2062
2063
bool SfxDispatcher::GetReadOnly_Impl() const
2064
0
{
2065
0
    return xImp->bReadOnly || SfxViewShell::IsCurrentLokViewReadOnly();
2066
0
}
2067
2068
/** With 'bOn' the Dispatcher is quasi dead and transfers everything to the
2069
    Parent-Dispatcher.
2070
*/
2071
void SfxDispatcher::SetQuietMode_Impl( bool bOn )
2072
0
{
2073
0
    xImp->bQuiet = bOn;
2074
0
    SfxBindings* pBindings = GetBindings();
2075
0
    if ( pBindings )
2076
0
        pBindings->InvalidateAll(true);
2077
0
}
2078
2079
SfxItemState SfxDispatcher::QueryState( sal_uInt16 nSlot, SfxPoolItemHolder& rState )
2080
3.93k
{
2081
3.93k
    SfxShell *pShell = nullptr;
2082
3.93k
    const SfxSlot *pSlot = nullptr;
2083
3.93k
    if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, false, true ) )
2084
3.93k
    {
2085
3.93k
        rState = pShell->GetSlotState(nSlot);
2086
3.93k
        if (!rState)
2087
0
            return SfxItemState::DISABLED;
2088
3.93k
        else
2089
3.93k
            return SfxItemState::DEFAULT;
2090
3.93k
    }
2091
2092
0
    return SfxItemState::DISABLED;
2093
3.93k
}
2094
2095
SfxItemState SfxDispatcher::QueryState( sal_uInt16 nSID, css::uno::Any& rAny )
2096
0
{
2097
0
    SfxShell *pShell = nullptr;
2098
0
    const SfxSlot *pSlot = nullptr;
2099
0
    if ( GetShellAndSlot_Impl( nSID, &pShell, &pSlot, false, true ) )
2100
0
    {
2101
0
        SfxPoolItemHolder aItem(pShell->GetSlotState(nSID));
2102
0
        if (!aItem)
2103
0
            return SfxItemState::DISABLED;
2104
0
        else
2105
0
        {
2106
0
            css::uno::Any aState;
2107
0
            if ( !IsDisabledItem(aItem.getItem()) )
2108
0
            {
2109
0
                sal_uInt16 nSubId( 0 );
2110
0
                SfxItemPool& rPool = pShell->GetPool();
2111
0
                sal_uInt16 nWhich = rPool.GetWhichIDFromSlotID( nSID );
2112
0
                if ( rPool.GetMetric( nWhich ) == MapUnit::MapTwip )
2113
0
                    nSubId |= CONVERT_TWIPS;
2114
0
                aItem.getItem()->QueryValue( aState, static_cast<sal_uInt8>(nSubId) );
2115
0
            }
2116
0
            rAny = std::move(aState);
2117
2118
0
            return SfxItemState::DEFAULT;
2119
0
        }
2120
0
    }
2121
2122
0
    return SfxItemState::DISABLED;
2123
0
}
2124
2125
bool SfxDispatcher::IsReadOnlyShell_Impl( sal_uInt16 nShell ) const
2126
51.1k
{
2127
51.1k
    bool bResult = true;
2128
51.1k
    sal_uInt16 nShellCount = xImp->aStack.size();
2129
51.1k
    if ( nShell < nShellCount )
2130
51.1k
    {
2131
51.1k
        SfxShell* pShell = *( xImp->aStack.rbegin() + nShell );
2132
51.1k
        if( dynamic_cast< const SfxModule *>( pShell ) != nullptr || dynamic_cast< const SfxApplication *>( pShell ) != nullptr || dynamic_cast< const SfxViewFrame *>( pShell ) !=  nullptr )
2133
23.6k
            bResult = false;
2134
27.5k
        else
2135
27.5k
            bResult = xImp->bReadOnly;
2136
51.1k
    }
2137
2138
51.1k
    if (!bResult && SfxViewShell::IsCurrentLokViewReadOnly())
2139
0
            bResult = true;
2140
2141
51.1k
    return bResult;
2142
51.1k
}
2143
2144
void SfxDispatcher::RemoveShell_Impl( SfxShell& rShell )
2145
3.93k
{
2146
3.93k
    Flush();
2147
2148
3.93k
    sal_uInt16 nCount = xImp->aStack.size();
2149
7.87k
    for ( sal_uInt16 n=0; n<nCount; ++n )
2150
7.87k
    {
2151
7.87k
        if ( xImp->aStack[n] == &rShell )
2152
3.93k
        {
2153
3.93k
            xImp->aStack.erase( xImp->aStack.begin() + n );
2154
3.93k
            rShell.SetDisableFlags( SfxDisableFlags::NONE );
2155
3.93k
            rShell.DoDeactivate_Impl(xImp->pFrame, true);
2156
3.93k
            break;
2157
3.93k
        }
2158
7.87k
    }
2159
2160
3.93k
    if ( !SfxGetpApp()->IsDowning() )
2161
3.93k
    {
2162
3.93k
        xImp->bUpdated = false;
2163
3.93k
        InvalidateBindings_Impl(true);
2164
3.93k
    }
2165
3.93k
}
2166
2167
void SfxDispatcher::InvalidateBindings_Impl( bool bModify )
2168
23.6k
{
2169
    // App-Dispatcher?
2170
23.6k
    if ( IsAppDispatcher() )
2171
27
    {
2172
27
        for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst();
2173
27
                pFrame;
2174
27
                pFrame = SfxViewFrame::GetNext( *pFrame ) )
2175
0
            pFrame->GetBindings().InvalidateAll(bModify);
2176
27
    }
2177
23.6k
    else
2178
23.6k
    {
2179
23.6k
        SfxDispatcher *pDisp = GetBindings()->GetDispatcher_Impl();
2180
23.6k
        if ( pDisp == this )
2181
23.6k
        {
2182
23.6k
            GetBindings()->InvalidateAll( bModify );
2183
23.6k
        }
2184
23.6k
    }
2185
23.6k
}
2186
2187
bool SfxDispatcher::IsUpdated_Impl() const
2188
0
{
2189
0
    return xImp->bUpdated;
2190
0
}
2191
2192
void SfxDispatcher::SetDisableFlags( SfxDisableFlags nFlags )
2193
7.87k
{
2194
7.87k
    xImp->nDisableFlags = nFlags;
2195
31.4k
    for ( SfxShellStack_Impl::reverse_iterator it = xImp->aStack.rbegin(); it != xImp->aStack.rend(); ++it )
2196
23.6k
        (*it)->SetDisableFlags( nFlags );
2197
7.87k
}
2198
2199
SfxDisableFlags SfxDispatcher::GetDisableFlags() const
2200
20.8k
{
2201
20.8k
    return xImp->nDisableFlags;
2202
20.8k
}
2203
2204
SfxModule* SfxDispatcher::GetModule() const
2205
0
{
2206
0
    for ( sal_uInt16 nShell = 0;; ++nShell )
2207
0
    {
2208
0
        SfxShell *pSh = GetShell(nShell);
2209
0
        if ( pSh == nullptr )
2210
0
            return nullptr;
2211
0
        if ( auto pModule = dynamic_cast<SfxModule *>( pSh ) )
2212
0
            return pModule;
2213
0
    }
2214
0
}
2215
2216
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */