Coverage Report

Created: 2025-12-31 10:39

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