Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/control/bindings.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 <sal/config.h>
21
22
#include <iomanip>
23
24
#include <comphelper/servicehelper.hxx>
25
#include <osl/diagnose.h>
26
#include <sal/log.hxx>
27
#include <svl/itempool.hxx>
28
#include <svl/itemiter.hxx>
29
#include <svl/eitem.hxx>
30
#include <svl/intitem.hxx>
31
#include <svl/stritem.hxx>
32
#include <svl/voiditem.hxx>
33
#include <vcl/svapp.hxx>
34
#include <vcl/timer.hxx>
35
#include <com/sun/star/frame/XDispatch.hpp>
36
#include <com/sun/star/frame/XDispatchProvider.hpp>
37
#include <com/sun/star/frame/DispatchResultState.hpp>
38
39
//Includes below due to nInReschedule
40
#include <sfx2/bindings.hxx>
41
#include <sfx2/msg.hxx>
42
#include <statcach.hxx>
43
#include <sfx2/ctrlitem.hxx>
44
#include <sfx2/app.hxx>
45
#include <sfx2/dispatch.hxx>
46
#include <sfx2/module.hxx>
47
#include <sfx2/request.hxx>
48
#include <workwin.hxx>
49
#include <unoctitm.hxx>
50
#include <sfx2/viewfrm.hxx>
51
#include <sfx2/objsh.hxx>
52
#include <sfx2/msgpool.hxx>
53
#include <sfx2/lokhelper.hxx>
54
#include <comphelper/lok.hxx>
55
56
#include <cstddef>
57
#include <memory>
58
#include <unordered_map>
59
#include <utility>
60
#include <vector>
61
62
using namespace ::com::sun::star;
63
using namespace ::com::sun::star::uno;
64
using namespace ::com::sun::star::util;
65
66
52.3k
#define TIMEOUT_FIRST       300
67
0
#define TIMEOUT_UPDATING     20
68
69
struct SfxFoundCache_Impl
70
{
71
    sal_uInt16      nWhichId;  // If available: Which-Id, else: nSlotId
72
    const SfxSlot*  pSlot;     // Pointer to <Master-Slot>
73
    SfxStateCache&  rCache;    // Pointer to StatusCache
74
75
    SfxFoundCache_Impl(sal_uInt16 nW, const SfxSlot *pS, SfxStateCache& rC)
76
864
        : nWhichId(nW)
77
864
        , pSlot(pS)
78
864
        , rCache(rC)
79
864
    {}
80
};
81
82
class SfxFoundCacheArr_Impl
83
{
84
    std::vector<SfxFoundCache_Impl> maData;
85
86
public:
87
88
    SfxFoundCache_Impl& operator[] ( size_t i )
89
3.60k
    {
90
3.60k
        return maData[i];
91
3.60k
    }
92
93
    size_t size() const
94
2.44k
    {
95
2.44k
        return maData.size();
96
2.44k
    }
97
98
    void push_back( SfxFoundCache_Impl p )
99
864
    {
100
864
        maData.push_back(p);
101
864
    }
102
};
103
104
class SfxBindings_Impl
105
{
106
public:
107
    css::uno::Reference< css::frame::XDispatchRecorder > xRecorder;
108
    css::uno::Reference< css::frame::XDispatchProvider >  xProv;
109
    std::unique_ptr<SfxWorkWindow> mxWorkWin;
110
    SfxBindings*            pSubBindings;
111
    std::vector<std::unique_ptr<SfxStateCache>> pCaches; // One cache for each binding
112
    std::size_t             nCachedFunc1;   // index for the last one called
113
    std::size_t             nCachedFunc2;   // index for the second last called
114
    std::size_t             nMsgPos;        // Message-Position relative the one to be updated
115
    bool                    bContextChanged;
116
    bool                    bMsgDirty;      // Has a MessageServer been invalidated?
117
    bool                    bAllMsgDirty;   //  Has a MessageServer been invalidated?
118
    bool                    bAllDirty;      // After InvalidateAll
119
    bool                    bCtrlReleased;  // while EnterRegistrations
120
    AutoTimer               aAutoTimer { "sfx::SfxBindings aAutoTimer" }; // for volatile Slots
121
    bool                    bInUpdate;      // for Assertions
122
    bool                    bInNextJob;     // for Assertions
123
    bool                    bFirstRound;    // First round in Update
124
    sal_uInt16              nOwnRegLevel;   // Counts the real Locks, except those of the Super Bindings
125
    std::unordered_map< sal_uInt16, bool >
126
                            m_aInvalidateSlots; // store slots which are invalidated while in update
127
};
128
129
SfxBindings::SfxBindings()
130
8.61k
:   pImpl(new SfxBindings_Impl),
131
8.61k
    pDispatcher(nullptr),
132
8.61k
    nRegLevel(1)    // first becomes 0, when the Dispatcher is set
133
134
8.61k
{
135
8.61k
    pImpl->nMsgPos = 0;
136
8.61k
    pImpl->bAllMsgDirty = true;
137
8.61k
    pImpl->bContextChanged = false;
138
8.61k
    pImpl->bMsgDirty = true;
139
8.61k
    pImpl->bAllDirty = true;
140
8.61k
    pImpl->nCachedFunc1 = 0;
141
8.61k
    pImpl->nCachedFunc2 = 0;
142
8.61k
    pImpl->bCtrlReleased = false;
143
8.61k
    pImpl->bFirstRound = false;
144
8.61k
    pImpl->bInNextJob = false;
145
8.61k
    pImpl->bInUpdate = false;
146
8.61k
    pImpl->pSubBindings = nullptr;
147
8.61k
    pImpl->nOwnRegLevel = nRegLevel;
148
149
    // all caches are valid (no pending invalidate-job)
150
    // create the list of caches
151
8.61k
    pImpl->aAutoTimer.SetPriority(TaskPriority::DEFAULT_IDLE);
152
8.61k
    pImpl->aAutoTimer.SetInvokeHandler( LINK(this, SfxBindings, NextJob) );
153
8.61k
}
154
155
156
SfxBindings::~SfxBindings()
157
158
/*  [Description]
159
160
    Destructor of the SfxBindings class. The one, for each <SfxApplication>
161
    existing Instance is automatically destroyed by the <SfxApplication>
162
    after the execution of <SfxApplication::Exit()>.
163
164
    The still existing <SfxControllerItem> instances, which are registered
165
    by the SfxBindings instance, are automatically destroyed in the Destructor.
166
    These are usually the Floating-Toolboxen, Value-Sets
167
    etc. Arrays of SfxControllerItems may at this time no longer exist.
168
*/
169
170
8.61k
{
171
    // The SubBindings should not be locked!
172
8.61k
    pImpl->pSubBindings = nullptr;
173
174
8.61k
    ENTERREGISTRATIONS();
175
176
8.61k
    pImpl->aAutoTimer.Stop();
177
8.61k
    DeleteControllers_Impl();
178
179
    // Delete Caches
180
8.61k
    pImpl->pCaches.clear();
181
182
8.61k
    pImpl->mxWorkWin.reset();
183
8.61k
}
184
185
186
void SfxBindings::DeleteControllers_Impl()
187
8.61k
{
188
    // in the first round delete Controllers
189
8.61k
    std::size_t nCount = pImpl->pCaches.size();
190
8.61k
    std::size_t nCache = 0;
191
137k
    while (nCache < nCount)
192
129k
    {
193
        // Remember were you are
194
129k
        SfxStateCache *pCache = pImpl->pCaches[nCache].get();
195
129k
        sal_uInt16 nSlotId = pCache->GetId();
196
197
        // Re-align, because the cache may have been reduced
198
129k
        std::size_t nNewCount = pImpl->pCaches.size();
199
129k
        if ( nNewCount < nCount )
200
0
        {
201
0
            nCache = GetSlotPos(nSlotId);
202
0
            nCount = nNewCount;
203
0
            if ( nCache >= nNewCount ||
204
0
                 nSlotId != pImpl->pCaches[nCache]->GetId() )
205
0
            {
206
0
                continue;
207
0
            }
208
0
        }
209
210
129k
        ++nCache;
211
129k
    }
212
213
    // Delete all Caches
214
137k
    for ( nCache = pImpl->pCaches.size(); nCache > 0; --nCache )
215
129k
    {
216
        // Get Cache via css::sdbcx::Index
217
129k
        SfxStateCache *pCache = pImpl->pCaches[ nCache-1 ].get();
218
219
        // unbind all controllers in the cache
220
129k
        SfxControllerItem *pNext;
221
129k
        for ( SfxControllerItem *pCtrl = pCache->GetItemLink();
222
129k
              pCtrl; pCtrl = pNext )
223
0
        {
224
0
            pNext = pCtrl->GetItemLink();
225
0
            pCtrl->UnBind();
226
0
        }
227
228
129k
        if ( pCache->GetInternalController() )
229
540
            pCache->GetInternalController()->UnBind();
230
231
        // Delete Cache
232
129k
        pImpl->pCaches.erase(pImpl->pCaches.begin() + nCache - 1);
233
129k
    }
234
8.61k
}
235
236
237
void SfxBindings::HidePopups( bool bHide )
238
0
{
239
    // Hide SfxChildWindows
240
0
    DBG_ASSERT( pDispatcher, "HidePopups not allowed without dispatcher" );
241
0
    if ( pImpl->mxWorkWin )
242
0
        pImpl->mxWorkWin->HidePopups_Impl( bHide );
243
0
}
244
245
void SfxBindings::Update_Impl(SfxStateCache& rCache /*The up to date SfxStatusCache*/)
246
72
{
247
72
    if (rCache.GetDispatch().is() && rCache.GetItemLink())
248
0
    {
249
0
        rCache.SetCachedState(true);
250
0
        if (!rCache.GetInternalController())
251
0
            return;
252
0
    }
253
254
72
    if ( !pDispatcher )
255
0
        return;
256
257
    // gather together all with the same status method which are dirty
258
72
    SfxDispatcher &rDispat = *pDispatcher;
259
72
    const SfxSlot *pRealSlot = nullptr;
260
72
    const SfxSlotServer* pMsgServer = nullptr;
261
72
    SfxFoundCacheArr_Impl aFound;
262
72
    std::optional<SfxItemSet> pSet = CreateSet_Impl(rCache, pRealSlot, &pMsgServer, aFound);
263
72
    bool bUpdated = false;
264
72
    if ( pSet )
265
72
    {
266
        // Query Status
267
72
        if ( rDispat.FillState_( *pMsgServer, *pSet, pRealSlot ) )
268
72
        {
269
            // Post Status
270
936
            for ( size_t nPos = 0; nPos < aFound.size(); ++nPos )
271
864
            {
272
864
                const SfxFoundCache_Impl& rFound = aFound[nPos];
273
864
                sal_uInt16 nWhich = rFound.nWhichId;
274
864
                const SfxPoolItem *pItem = nullptr;
275
864
                SfxItemState eState = pSet->GetItemState(nWhich, true, &pItem);
276
864
                if ( eState == SfxItemState::DEFAULT && SfxItemPool::IsWhich(nWhich) )
277
0
                    pItem = &pSet->Get(nWhich);
278
864
                UpdateControllers_Impl( rFound, pItem, eState );
279
864
            }
280
72
            bUpdated = true;
281
72
        }
282
283
72
        pSet.reset();
284
72
    }
285
286
72
    if (!bUpdated)
287
0
    {
288
0
        SfxFoundCache_Impl aFoundCache(0, pRealSlot, rCache);
289
0
        UpdateControllers_Impl( aFoundCache, nullptr, SfxItemState::DISABLED);
290
0
    }
291
72
}
292
293
void SfxBindings::InvalidateSlotsInMap_Impl()
294
72
{
295
72
    for (auto const& slot : pImpl->m_aInvalidateSlots)
296
0
        Invalidate( slot.first );
297
298
72
    pImpl->m_aInvalidateSlots.clear();
299
72
}
300
301
302
void SfxBindings::AddSlotToInvalidateSlotsMap_Impl( sal_uInt16 nId )
303
0
{
304
0
    pImpl->m_aInvalidateSlots[nId] = true;
305
0
}
306
307
308
void SfxBindings::Update
309
(
310
    sal_uInt16      nId     // the bound and up-to-date Slot-Id
311
)
312
72
{
313
72
    if ( pDispatcher )
314
72
        pDispatcher->Flush();
315
316
72
    if ( pImpl->pSubBindings )
317
0
        pImpl->pSubBindings->Update( nId );
318
319
72
    SfxStateCache* pCache = GetStateCache( nId );
320
72
    if ( !pCache )
321
0
        return;
322
323
72
    pImpl->bInUpdate = true;
324
72
    if ( pImpl->bMsgDirty )
325
36
    {
326
36
        UpdateSlotServer_Impl();
327
36
        pCache = GetStateCache( nId );
328
36
    }
329
330
72
    if (pCache)
331
72
    {
332
72
        bool bInternalUpdate = true;
333
72
        if( pCache->GetDispatch().is() && pCache->GetItemLink() )
334
0
        {
335
0
            pCache->SetCachedState(true);
336
0
            bInternalUpdate = ( pCache->GetInternalController() != nullptr );
337
0
        }
338
339
72
        if ( bInternalUpdate )
340
72
        {
341
            // Query Status
342
72
            const SfxSlotServer* pMsgServer = pDispatcher ? pCache->GetSlotServer(*pDispatcher, pImpl->xProv) : nullptr;
343
72
            if ( !pCache->IsControllerDirty() )
344
0
            {
345
0
                pImpl->bInUpdate = false;
346
0
                InvalidateSlotsInMap_Impl();
347
0
                return;
348
0
            }
349
72
            if (!pMsgServer)
350
0
            {
351
0
                pCache->SetState(SfxItemState::DISABLED, nullptr);
352
0
                pImpl->bInUpdate = false;
353
0
                InvalidateSlotsInMap_Impl();
354
0
                return;
355
0
            }
356
357
72
            Update_Impl(*pCache);
358
72
        }
359
360
72
        pImpl->bAllDirty = false;
361
72
    }
362
363
72
    pImpl->bInUpdate = false;
364
72
    InvalidateSlotsInMap_Impl();
365
72
}
366
367
368
void SfxBindings::Update()
369
0
{
370
0
    if ( pImpl->pSubBindings )
371
0
        pImpl->pSubBindings->Update();
372
373
0
    if ( !pDispatcher )
374
0
        return;
375
376
0
    if ( nRegLevel )
377
0
        return;
378
379
0
    pImpl->bInUpdate = true;
380
0
    pDispatcher->Flush();
381
0
    pDispatcher->Update_Impl();
382
0
    while ( !NextJob_Impl(nullptr) )
383
0
        ; // loop
384
0
    pImpl->bInUpdate = false;
385
0
    InvalidateSlotsInMap_Impl();
386
0
}
387
388
389
void SfxBindings::SetState
390
(
391
    const SfxItemSet&   rSet    // status values to be set
392
)
393
0
{
394
    // when locked then only invalidate
395
0
    if ( nRegLevel )
396
0
    {
397
0
        for (SfxItemIter aIter( rSet ); !aIter.IsAtEnd(); aIter.Next())
398
0
            Invalidate( aIter.GetCurItem()->Which() );
399
0
    }
400
0
    else
401
0
    {
402
        // Status may be accepted only if all slot-pointers are set
403
0
        if ( pImpl->bMsgDirty )
404
0
            UpdateSlotServer_Impl();
405
406
        // Iterate over the itemset, update if the slot bound
407
        //! Bug: Use WhichIter and possibly send VoidItems up
408
0
        for (SfxItemIter aIter( rSet ); !aIter.IsAtEnd(); aIter.Next())
409
0
        {
410
0
            const SfxPoolItem* pItem = aIter.GetCurItem();
411
0
            SfxStateCache* pCache =
412
0
                    GetStateCache( rSet.GetPool()->GetSlotId(pItem->Which()) );
413
0
            if ( pCache )
414
0
            {
415
                // Update status
416
0
                if ( !pCache->IsControllerDirty() )
417
0
                    pCache->Invalidate(false);
418
0
                pCache->SetState( SfxItemState::DEFAULT, pItem );
419
420
                //! Not implemented: Updates from EnumSlots via master slots
421
0
            }
422
0
        }
423
0
    }
424
0
}
425
426
427
void SfxBindings::SetState
428
(
429
    const SfxPoolItem&  rItem   // Status value to be set
430
)
431
0
{
432
0
    if ( nRegLevel )
433
0
    {
434
0
        Invalidate( rItem.Which() );
435
0
    }
436
0
    else
437
0
    {
438
        // Status may be accepted only if all slot-pointers are set
439
0
        if ( pImpl->bMsgDirty )
440
0
            UpdateSlotServer_Impl();
441
442
        //update if the slot bound
443
0
        DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
444
0
                    "cannot set items with which-id" );
445
0
        SfxStateCache* pCache = GetStateCache( rItem.Which() );
446
0
        if ( pCache )
447
0
        {
448
            // Update Status
449
0
            if ( !pCache->IsControllerDirty() )
450
0
                pCache->Invalidate(false);
451
0
            pCache->SetState( SfxItemState::DEFAULT, &rItem );
452
453
            //! Not implemented: Updates from EnumSlots via master slots
454
0
        }
455
0
    }
456
0
}
457
458
459
SfxStateCache* SfxBindings::GetAnyStateCache_Impl( sal_uInt16 nId )
460
0
{
461
0
    SfxStateCache* pCache = GetStateCache( nId );
462
0
    if ( !pCache && pImpl->pSubBindings )
463
0
        return pImpl->pSubBindings->GetAnyStateCache_Impl( nId );
464
0
    return pCache;
465
0
}
466
467
SfxStateCache* SfxBindings::GetStateCache
468
(
469
    sal_uInt16   nId   /*  Slot-Id, which SfxStatusCache is to be found */
470
)
471
1.15k
{
472
1.15k
    return GetStateCache(nId, nullptr);
473
1.15k
}
474
475
SfxStateCache* SfxBindings::GetStateCache
476
(
477
    sal_uInt16   nId,   /*  Slot-Id, which SfxStatusCache is to be found */
478
    std::size_t * pPos  /*  NULL for instance the position from which the
479
                           bindings are to be searched binary. Returns the
480
                           position back for where the nId was found,
481
                           or where it was inserted. */
482
)
483
3.17k
{
484
    // is the specified function bound?
485
3.17k
    const std::size_t nStart = ( pPos ? *pPos : 0 );
486
3.17k
    const std::size_t nPos = GetSlotPos( nId, nStart );
487
488
3.17k
    if ( nPos < pImpl->pCaches.size() &&
489
3.13k
         pImpl->pCaches[nPos]->GetId() == nId )
490
1.44k
    {
491
1.44k
        if ( pPos )
492
792
            *pPos = nPos;
493
1.44k
        return pImpl->pCaches[nPos].get();
494
1.44k
    }
495
1.73k
    return nullptr;
496
3.17k
}
497
498
499
void SfxBindings::InvalidateAll
500
(
501
    bool  bWithMsg  /* true   Mark Slot Server as invalid
502
                       false  Slot Server remains valid */
503
)
504
145k
{
505
145k
    DBG_ASSERT( !pImpl->bInUpdate, "SfxBindings::Invalidate while in update" );
506
507
145k
    if ( pImpl->pSubBindings )
508
0
        pImpl->pSubBindings->InvalidateAll( bWithMsg );
509
510
    // everything is already set dirty or downing => nothing to do
511
145k
    if ( !pDispatcher ||
512
128k
         ( pImpl->bAllDirty && ( !bWithMsg || pImpl->bAllMsgDirty ) ) ||
513
108
         SfxGetpApp()->IsDowning() )
514
145k
    {
515
145k
        return;
516
145k
    }
517
518
108
    pImpl->bAllMsgDirty = pImpl->bAllMsgDirty || bWithMsg;
519
108
    pImpl->bMsgDirty = pImpl->bMsgDirty || pImpl->bAllMsgDirty || bWithMsg;
520
108
    pImpl->bAllDirty = true;
521
522
108
    for (std::unique_ptr<SfxStateCache>& pCache : pImpl->pCaches)
523
1.62k
        pCache->Invalidate(bWithMsg);
524
525
108
    pImpl->nMsgPos = 0;
526
108
    if ( !nRegLevel )
527
36
    {
528
36
        pImpl->aAutoTimer.Stop();
529
36
        pImpl->aAutoTimer.SetTimeout(TIMEOUT_FIRST);
530
36
        pImpl->aAutoTimer.Start();
531
36
    }
532
108
}
533
534
535
void SfxBindings::Invalidate
536
(
537
    const sal_uInt16* pIds /* numerically sorted NULL-terminated array of
538
                              slot IDs (individual, not as a couple!) */
539
)
540
17.6k
{
541
17.6k
    if ( pImpl->bInUpdate )
542
0
    {
543
0
        sal_Int32 i = 0;
544
0
        while ( pIds[i] != 0 )
545
0
            AddSlotToInvalidateSlotsMap_Impl( pIds[i++] );
546
547
0
        if ( pImpl->pSubBindings )
548
0
            pImpl->pSubBindings->Invalidate( pIds );
549
0
        return;
550
0
    }
551
552
17.6k
    if ( pImpl->pSubBindings )
553
0
        pImpl->pSubBindings->Invalidate( pIds );
554
555
    // everything is already set dirty or downing => nothing to do
556
17.6k
    if ( !pDispatcher || pImpl->bAllDirty || SfxGetpApp()->IsDowning() )
557
17.6k
        return;
558
559
    // Search binary in always smaller areas
560
0
    for ( std::size_t n = GetSlotPos(*pIds);
561
0
          *pIds && n < pImpl->pCaches.size();
562
0
          n = GetSlotPos(*pIds, n) )
563
0
    {
564
        // If SID is ever bound, then invalidate the cache
565
0
        SfxStateCache *pCache = pImpl->pCaches[n].get();
566
0
        if ( pCache->GetId() == *pIds )
567
0
            pCache->Invalidate(false);
568
569
        // Next SID
570
0
        if ( !*++pIds )
571
0
            break;
572
0
        assert( *pIds > *(pIds-1) );
573
0
    }
574
575
    // if not enticed to start update timer
576
0
    pImpl->nMsgPos = 0;
577
0
    if ( !nRegLevel )
578
0
    {
579
0
        pImpl->aAutoTimer.Stop();
580
0
        pImpl->aAutoTimer.SetTimeout(TIMEOUT_FIRST);
581
0
        pImpl->aAutoTimer.Start();
582
0
    }
583
0
}
584
585
586
void SfxBindings::InvalidateShell
587
(
588
    const SfxShell&  rSh,  /* <SfxShell> whose Slot-Ids should be
589
                              invalidated */
590
    bool             bDeep /* true
591
                              also the SfxShell's inherited slot IDs are invalidated
592
593
                              false
594
                              the inherited and not overridden Slot-Ids are
595
                              invalidated */
596
                             // for now always bDeep
597
)
598
0
{
599
0
    DBG_ASSERT( !pImpl->bInUpdate, "SfxBindings::Invalidate while in update" );
600
601
0
    if ( pImpl->pSubBindings )
602
0
        pImpl->pSubBindings->InvalidateShell( rSh, bDeep );
603
604
0
    if ( !pDispatcher || pImpl->bAllDirty || SfxGetpApp()->IsDowning() )
605
0
        return;
606
607
    // flush now already, it is done in GetShellLevel (rsh) anyway,
608
    // important so that is set correctly: pImpl-> ball(Msg)Dirty
609
0
    pDispatcher->Flush();
610
611
0
    if ((pImpl->bAllDirty && pImpl->bAllMsgDirty) || SfxGetpApp()->IsDowning())
612
0
    {
613
        // if the next one is anyway, then all the servers are collected
614
0
        return;
615
0
    }
616
617
    // Find Level
618
0
    sal_uInt16 nLevel = pDispatcher->GetShellLevel(rSh);
619
0
    if ( nLevel == USHRT_MAX )
620
0
        return;
621
622
0
    for (std::unique_ptr<SfxStateCache>& pCache : pImpl->pCaches)
623
0
    {
624
0
        const SfxSlotServer *pMsgServer =
625
0
            pCache->GetSlotServer(*pDispatcher, pImpl->xProv);
626
0
        if ( pMsgServer && pMsgServer->GetShellLevel() == nLevel )
627
0
            pCache->Invalidate(false);
628
0
    }
629
0
    pImpl->nMsgPos = 0;
630
0
    if ( !nRegLevel )
631
0
    {
632
0
        pImpl->aAutoTimer.Stop();
633
0
        pImpl->aAutoTimer.SetTimeout(TIMEOUT_FIRST);
634
0
        pImpl->aAutoTimer.Start();
635
0
        pImpl->bFirstRound = true;
636
0
    }
637
0
}
638
639
640
void SfxBindings::Invalidate
641
(
642
    sal_uInt16 nId              // Status value to be set
643
)
644
234k
{
645
234k
    if ( pImpl->bInUpdate )
646
0
    {
647
0
        AddSlotToInvalidateSlotsMap_Impl( nId );
648
0
        if ( pImpl->pSubBindings )
649
0
            pImpl->pSubBindings->Invalidate( nId );
650
0
        return;
651
0
    }
652
653
234k
    if ( pImpl->pSubBindings )
654
0
        pImpl->pSubBindings->Invalidate( nId );
655
656
234k
    if ( !pDispatcher || pImpl->bAllDirty || SfxGetpApp()->IsDowning() )
657
233k
        return;
658
659
396
    SfxStateCache* pCache = GetStateCache(nId);
660
396
    if ( pCache )
661
0
    {
662
0
        pCache->Invalidate(false);
663
0
        pImpl->nMsgPos = std::min(GetSlotPos(nId), pImpl->nMsgPos);
664
0
        if ( !nRegLevel )
665
0
        {
666
0
            pImpl->aAutoTimer.Stop();
667
0
            pImpl->aAutoTimer.SetTimeout(TIMEOUT_FIRST);
668
0
            pImpl->aAutoTimer.Start();
669
0
        }
670
0
    }
671
396
}
672
673
674
void SfxBindings::Invalidate
675
(
676
    sal_uInt16  nId,                // Status value to be set
677
    bool        bWithItem,          // Clear StateCache?
678
    bool        bWithMsg            // Get new SlotServer?
679
)
680
0
{
681
0
    DBG_ASSERT( !pImpl->bInUpdate, "SfxBindings::Invalidate while in update" );
682
683
0
    if ( pImpl->pSubBindings )
684
0
        pImpl->pSubBindings->Invalidate( nId, bWithItem, bWithMsg );
685
686
0
    if ( SfxGetpApp()->IsDowning() )
687
0
        return;
688
689
0
    SfxStateCache* pCache = GetStateCache(nId);
690
0
    if ( !pCache )
691
0
        return;
692
693
0
    if ( bWithItem )
694
0
        pCache->ClearCache();
695
0
    pCache->Invalidate(bWithMsg);
696
697
0
    if ( !pDispatcher || pImpl->bAllDirty )
698
0
        return;
699
700
0
    pImpl->nMsgPos = std::min(GetSlotPos(nId), pImpl->nMsgPos);
701
0
    if ( !nRegLevel )
702
0
    {
703
0
        pImpl->aAutoTimer.Stop();
704
0
        pImpl->aAutoTimer.SetTimeout(TIMEOUT_FIRST);
705
0
        pImpl->aAutoTimer.Start();
706
0
    }
707
0
}
708
709
710
std::size_t SfxBindings::GetSlotPos( sal_uInt16 nId, std::size_t nStartSearchAt )
711
348k
{
712
    // answer immediately if a function-seek comes repeated
713
348k
    if ( pImpl->nCachedFunc1 < pImpl->pCaches.size() &&
714
339k
         pImpl->pCaches[pImpl->nCachedFunc1]->GetId() == nId )
715
36
    {
716
36
        return pImpl->nCachedFunc1;
717
36
    }
718
348k
    if ( pImpl->nCachedFunc2 < pImpl->pCaches.size() &&
719
339k
         pImpl->pCaches[pImpl->nCachedFunc2]->GetId() == nId )
720
0
    {
721
        // swap the caches
722
0
        std::swap(pImpl->nCachedFunc1, pImpl->nCachedFunc2);
723
0
        return pImpl->nCachedFunc1;
724
0
    }
725
726
    // binary search, if not found, seek to target-position
727
348k
    if ( pImpl->pCaches.size() <= nStartSearchAt )
728
8.61k
    {
729
8.61k
        return 0;
730
8.61k
    }
731
340k
    if ( pImpl->pCaches.size() == (nStartSearchAt+1) )
732
9.87k
    {
733
9.87k
        return pImpl->pCaches[nStartSearchAt]->GetId() >= nId ? 0 : 1;
734
9.87k
    }
735
330k
    std::size_t nLow = nStartSearchAt;
736
330k
    std::size_t nMid = 0;
737
330k
    std::size_t nHigh = 0;
738
330k
    bool bFound = false;
739
330k
    nHigh = pImpl->pCaches.size() - 1;
740
1.31M
    while ( !bFound && nLow <= nHigh )
741
1.00M
    {
742
1.00M
        nMid = (nLow + nHigh) >> 1;
743
1.00M
        DBG_ASSERT( nMid < pImpl->pCaches.size(), "bsearch is buggy" );
744
1.00M
        int nDiff = static_cast<int>(nId) - static_cast<int>( (pImpl->pCaches[nMid])->GetId() );
745
1.00M
        if ( nDiff < 0)
746
348k
        {   if ( nMid == 0 )
747
17.4k
                break;
748
330k
            nHigh = nMid - 1;
749
330k
        }
750
651k
        else if ( nDiff > 0 )
751
434k
        {   nLow = nMid + 1;
752
434k
            if ( nLow == 0 )
753
0
                break;
754
434k
        }
755
217k
        else
756
217k
            bFound = true;
757
1.00M
    }
758
330k
    std::size_t nPos = bFound ? nMid : nLow;
759
330k
    DBG_ASSERT( nPos <= pImpl->pCaches.size(), "" );
760
330k
    DBG_ASSERT( nPos == pImpl->pCaches.size() ||
761
330k
                nId <= pImpl->pCaches[nPos]->GetId(), "" );
762
330k
    DBG_ASSERT( nPos == nStartSearchAt ||
763
330k
                nId > pImpl->pCaches[nPos-1]->GetId(), "" );
764
330k
    DBG_ASSERT( ( (nPos+1) >= pImpl->pCaches.size() ) ||
765
330k
                nId < pImpl->pCaches[nPos+1]->GetId(), "" );
766
330k
    pImpl->nCachedFunc2 = pImpl->nCachedFunc1;
767
330k
    pImpl->nCachedFunc1 = nPos;
768
330k
    return nPos;
769
340k
}
770
771
void SfxBindings::RegisterInternal_Impl( SfxControllerItem& rItem )
772
540
{
773
540
    Register_Impl( rItem, true );
774
775
540
}
776
777
void SfxBindings::Register( SfxControllerItem& rItem )
778
172k
{
779
172k
    Register_Impl( rItem, false );
780
172k
}
781
782
void SfxBindings::Register_Impl( SfxControllerItem& rItem, bool bInternal )
783
172k
{
784
//    DBG_ASSERT( nRegLevel > 0, "registration without EnterRegistrations" );
785
    // Re-entrant registration can happen when Update_Impl triggers
786
    // FillState_ which queries slot state through the dispatch chain,
787
    // causing SfxBindings::GetDispatch to construct new dispatch
788
    // controllers that register themselves. The update loop in
789
    // NextJob_Impl will restart when it detects bMsgDirty was set.
790
172k
    SAL_INFO_IF(pImpl->bInNextJob, "sfx.control",
791
172k
                "SfxBindings::Register while status-updating");
792
793
    // insert new cache if it does not already exist
794
172k
    sal_uInt16 nId = rItem.GetId();
795
172k
    std::size_t nPos = GetSlotPos(nId);
796
172k
    if ( nPos >= pImpl->pCaches.size() ||
797
138k
         pImpl->pCaches[nPos]->GetId() != nId )
798
129k
    {
799
129k
        pImpl->pCaches.insert( pImpl->pCaches.begin() + nPos, std::make_unique<SfxStateCache>(nId) );
800
129k
        DBG_ASSERT( nPos == 0 ||
801
129k
                    pImpl->pCaches[nPos]->GetId() >
802
129k
                        pImpl->pCaches[nPos-1]->GetId(), "" );
803
129k
        DBG_ASSERT( (nPos == pImpl->pCaches.size()-1) ||
804
129k
                    pImpl->pCaches[nPos]->GetId() <
805
129k
                        pImpl->pCaches[nPos+1]->GetId(), "" );
806
129k
        pImpl->bMsgDirty = true;
807
129k
    }
808
809
    // enqueue the new binding
810
172k
    if ( bInternal )
811
540
    {
812
540
        pImpl->pCaches[nPos]->SetInternalController( &rItem );
813
540
    }
814
172k
    else
815
172k
    {
816
172k
        SfxControllerItem *pOldItem = pImpl->pCaches[nPos]->ChangeItemLink(&rItem);
817
172k
        rItem.ChangeItemLink(pOldItem);
818
172k
    }
819
172k
}
820
821
822
void SfxBindings::Release( SfxControllerItem& rItem )
823
172k
{
824
    // Re-entrant release can happen when Update_Impl triggers
825
    // FillState_ which queries slot state through the dispatch chain,
826
    // causing controllers to unregister. Same situation as Register_Impl.
827
172k
    SAL_INFO_IF(pImpl->bInNextJob, "sfx.control",
828
172k
                "SfxBindings::Release while status-updating");
829
172k
    ENTERREGISTRATIONS();
830
831
    // find the bound function
832
172k
    sal_uInt16 nId = rItem.GetId();
833
172k
    std::size_t nPos = GetSlotPos(nId);
834
172k
    SfxStateCache* pCache = (nPos < pImpl->pCaches.size()) ? pImpl->pCaches[nPos].get() : nullptr;
835
172k
    if ( pCache && pCache->GetId() == nId )
836
172k
    {
837
172k
        if ( pCache->GetInternalController() == &rItem )
838
540
        {
839
540
            pCache->ReleaseInternalController();
840
540
        }
841
172k
        else
842
172k
        {
843
            // is this the first binding in the list?
844
172k
            SfxControllerItem* pItem = pCache->GetItemLink();
845
172k
            if ( pItem == &rItem )
846
129k
                pCache->ChangeItemLink( rItem.GetItemLink() );
847
43.0k
            else
848
43.0k
            {
849
                // search the binding in the list
850
43.0k
                while ( pItem && pItem->GetItemLink() != &rItem )
851
0
                    pItem = pItem->GetItemLink();
852
853
                // unlink it if it was found
854
43.0k
                if ( pItem )
855
43.0k
                    pItem->ChangeItemLink( rItem.GetItemLink() );
856
43.0k
            }
857
172k
        }
858
859
        // was this the last controller?
860
172k
        if ( pCache->GetItemLink() == nullptr && !pCache->GetInternalController() )
861
129k
        {
862
129k
            pImpl->bCtrlReleased = true;
863
            // Signal NextJob_Impl to restart, same as Register_Impl.
864
            // LeaveRegistrations will remove this empty cache, changing
865
            // the pCaches vector while NextJob_Impl is iterating it.
866
129k
            pImpl->bMsgDirty = true;
867
129k
        }
868
172k
    }
869
870
172k
    LEAVEREGISTRATIONS();
871
172k
}
872
873
874
SfxPoolItemHolder SfxBindings::ExecuteSynchron( sal_uInt16 nId, const SfxPoolItem** ppItems )
875
0
{
876
0
    return Execute(nId, ppItems, SfxCallMode::SYNCHRON);
877
0
}
878
879
SfxPoolItemHolder SfxBindings::Execute( sal_uInt16 nId, const SfxPoolItem** ppItems, SfxCallMode nCallMode )
880
0
{
881
0
    if( !nId || !pDispatcher )
882
0
        return SfxPoolItemHolder();
883
884
0
    return Execute_Impl(nId, ppItems, nCallMode);
885
0
}
886
887
SfxPoolItemHolder SfxBindings::Execute_Impl( sal_uInt16 nId, const SfxPoolItem** ppItems, SfxCallMode nCallMode )
888
0
{
889
0
    SfxStateCache *pCache = GetStateCache( nId );
890
0
    if ( !pCache )
891
0
    {
892
0
        SfxBindings *pBind = pImpl->pSubBindings;
893
0
        while ( pBind )
894
0
        {
895
0
            if ( pBind->GetStateCache( nId ) )
896
0
                return pBind->Execute_Impl(nId, ppItems, nCallMode);
897
0
            pBind = pBind->pImpl->pSubBindings;
898
0
        }
899
0
    }
900
901
0
    SfxDispatcher &rDispatcher = *pDispatcher;
902
0
    rDispatcher.Flush();
903
904
    // get SlotServer (Slot+ShellLevel) and Shell from cache
905
0
    std::unique_ptr<SfxStateCache> xCache;
906
0
    if ( !pCache )
907
0
    {
908
        // Execution of non cached slots (Accelerators don't use Controllers)
909
        // slot is uncached, use SlotCache to handle external dispatch providers
910
0
        xCache.reset(new SfxStateCache(nId));
911
0
        pCache = xCache.get();
912
0
    }
913
914
0
    pCache->GetSlotServer( rDispatcher, pImpl->xProv ); // make pCache->GetDispatch() up to date
915
0
    if ( pCache->GetDispatch().is() )
916
0
    {
917
0
        SfxItemPool &rPool = GetDispatcher()->GetFrame()->GetObjectShell()->GetPool();
918
0
        SfxRequest aReq( nId, nCallMode, rPool );
919
0
        if( ppItems )
920
0
            while( *ppItems )
921
0
                aReq.AppendItem( **ppItems++ );
922
923
        // cache binds to an external dispatch provider
924
0
        sal_Int16 eRet = pCache->Dispatch( aReq.GetArgs(), nCallMode == SfxCallMode::SYNCHRON );
925
0
        SfxPoolItem* pPoolItem(nullptr);
926
0
        if ( eRet == css::frame::DispatchResultState::DONTKNOW )
927
0
            pPoolItem = new SfxVoidItem( nId );
928
0
        else
929
0
            pPoolItem = new SfxBoolItem( nId, eRet == css::frame::DispatchResultState::SUCCESS);
930
931
0
        return SfxPoolItemHolder(rPool, pPoolItem, true);
932
0
    }
933
934
    // slot is handled internally by SfxDispatcher
935
0
    if ( pImpl->bMsgDirty )
936
0
        UpdateSlotServer_Impl();
937
938
0
    const SfxSlotServer* pServer = pCache->GetSlotServer( rDispatcher, pImpl->xProv );
939
0
    if (!pServer)
940
0
        return SfxPoolItemHolder();
941
942
0
    SfxShell* pShell = rDispatcher.GetShell(pServer->GetShellLevel());
943
0
    const SfxSlot* pSlot = pServer->GetSlot();
944
945
0
    if (!pShell)
946
0
        return SfxPoolItemHolder();
947
948
0
    SfxItemPool &rPool = pShell->GetPool();
949
0
    SfxRequest aReq( nId, nCallMode, rPool );
950
0
    if( ppItems )
951
0
        while( *ppItems )
952
0
            aReq.AppendItem( **ppItems++ );
953
954
0
    Execute_Impl(aReq, pSlot, *pShell);
955
956
0
    const SfxPoolItemHolder& rRetval(aReq.GetReturnValue());
957
958
0
    if (!rRetval)
959
0
        return SfxPoolItemHolder(rPool, new SfxVoidItem( nId ), true);
960
961
0
    return rRetval;
962
0
}
963
964
void SfxBindings::Execute_Impl(SfxRequest& aReq, const SfxSlot* pSlot, SfxShell& rShell)
965
0
{
966
0
    SfxItemPool& rPool = rShell.GetPool();
967
968
0
    if ( SfxSlotKind::Attribute == pSlot->GetKind() )
969
0
    {
970
        // Which value has to be mapped for Attribute slots
971
0
        const sal_uInt16 nSlotId = pSlot->GetSlotId();
972
0
        aReq.SetSlot( nSlotId );
973
0
        if ( pSlot->IsMode(SfxSlotMode::TOGGLE) )
974
0
        {
975
            // The value is attached to a toggleable attribute (Bools)
976
0
            sal_uInt16 nWhich = pSlot->GetWhich(rPool);
977
0
            SfxItemSet aSet(rPool, nWhich, nWhich);
978
0
            SfxStateFunc pFunc = pSlot->GetStateFnc();
979
0
            (*pFunc)(&rShell, aSet);
980
0
            const SfxPoolItem *pOldItem;
981
0
            SfxItemState eState = aSet.GetItemState(nWhich, true, &pOldItem);
982
0
            if ( eState == SfxItemState::DISABLED )
983
0
                return;
984
985
0
            if ( SfxItemState::DEFAULT == eState && SfxItemPool::IsWhich(nWhich) )
986
0
                pOldItem = &aSet.Get(nWhich);
987
988
0
            if ( SfxItemState::SET == eState ||
989
0
                 ( SfxItemState::DEFAULT == eState &&
990
0
                   SfxItemPool::IsWhich(nWhich) &&
991
0
                   pOldItem ) )
992
0
            {
993
0
                if ( auto pOldBoolItem = dynamic_cast< const SfxBoolItem *>( pOldItem ) )
994
0
                {
995
                    // we can toggle Bools
996
0
                    bool bOldValue = pOldBoolItem->GetValue();
997
0
                    std::unique_ptr<SfxBoolItem> pNewItem(static_cast<SfxBoolItem*>(pOldItem->Clone()));
998
0
                    pNewItem->SetValue( !bOldValue );
999
0
                    aReq.AppendItem( *pNewItem );
1000
0
                }
1001
0
                else if ( auto pOldEnumItem = dynamic_cast< const SfxEnumItemInterface *>( pOldItem ) )
1002
0
                {
1003
0
                    if (pOldEnumItem->HasBoolValue())
1004
0
                    {
1005
                        // and Enums with Bool-Interface
1006
0
                        std::unique_ptr<SfxEnumItemInterface> pNewItem(
1007
0
                            static_cast<SfxEnumItemInterface*>(pOldEnumItem->Clone()));
1008
0
                        pNewItem->SetBoolValue(!pOldEnumItem->GetBoolValue());
1009
0
                        aReq.AppendItem( *pNewItem );
1010
0
                    }
1011
0
                }
1012
0
                else {
1013
0
                    OSL_FAIL( "Toggle only for Enums and Bools allowed" );
1014
0
                }
1015
0
            }
1016
0
            else if ( SfxItemState::INVALID == eState )
1017
0
            {
1018
                // Create one Status-Item for each Factory
1019
0
                std::unique_ptr<SfxPoolItem> pNewItem = pSlot->GetType()->CreateItem();
1020
0
                DBG_ASSERT( pNewItem, "Toggle to slot without ItemFactory" );
1021
0
                pNewItem->SetWhich( nWhich );
1022
1023
0
                if ( auto pNewBoolItem = dynamic_cast<SfxBoolItem *>( pNewItem.get() ) )
1024
0
                {
1025
                  // we can toggle Bools
1026
0
                    pNewBoolItem->SetValue( true );
1027
0
                    aReq.AppendItem( *pNewItem );
1028
0
                }
1029
0
                else if ( auto pEnumItem = dynamic_cast<SfxEnumItemInterface *>( pNewItem.get() ) )
1030
0
                {
1031
0
                    if (pEnumItem->HasBoolValue())
1032
0
                    {
1033
                        // and Enums with Bool-Interface
1034
0
                        pEnumItem->SetBoolValue(true);
1035
0
                        aReq.AppendItem( *pNewItem );
1036
0
                    }
1037
0
                }
1038
0
                else {
1039
0
                    OSL_FAIL( "Toggle only for Enums and Bools allowed" );
1040
0
                }
1041
0
            }
1042
0
            else {
1043
0
                OSL_FAIL( "suspicious Toggle-Slot" );
1044
0
            }
1045
0
        }
1046
1047
0
        pDispatcher->Execute_(rShell, *pSlot, aReq, aReq.GetCallMode() | SfxCallMode::RECORD );
1048
0
    }
1049
0
    else
1050
0
        pDispatcher->Execute_(rShell, *pSlot, aReq, aReq.GetCallMode() | SfxCallMode::RECORD );
1051
0
}
1052
1053
1054
void SfxBindings::UpdateSlotServer_Impl()
1055
36
{
1056
    // synchronize
1057
36
    pDispatcher->Flush();
1058
1059
36
    if ( pImpl->bAllMsgDirty )
1060
36
    {
1061
36
        if ( !nRegLevel )
1062
36
        {
1063
36
            pImpl->bContextChanged = false;
1064
36
        }
1065
0
        else
1066
0
            pImpl->bContextChanged = true;
1067
36
    }
1068
1069
576
    for (size_t i = 0; i < pImpl->pCaches.size(); ++i)
1070
540
    {
1071
        //GetSlotServer can modify pImpl->pCaches
1072
540
        pImpl->pCaches[i]->GetSlotServer(*pDispatcher, pImpl->xProv);
1073
540
    }
1074
36
    pImpl->bMsgDirty = pImpl->bAllMsgDirty = false;
1075
1076
36
    Broadcast( SfxHint(SfxHintId::DocChanged) );
1077
36
}
1078
1079
1080
std::optional<SfxItemSet> SfxBindings::CreateSet_Impl
1081
(
1082
    SfxStateCache&          rCache,     // in: Status-Cache from nId
1083
    const SfxSlot*&         pRealSlot,  // out: RealSlot to nId
1084
    const SfxSlotServer**   pMsgServer, // out: Slot-Server to nId
1085
    SfxFoundCacheArr_Impl&  rFound      // out: List of Caches for Siblings
1086
)
1087
72
{
1088
72
    DBG_ASSERT( !pImpl->bMsgDirty, "CreateSet_Impl with dirty MessageServer" );
1089
72
    assert(pDispatcher);
1090
1091
72
    const SfxSlotServer* pMsgSvr = rCache.GetSlotServer(*pDispatcher, pImpl->xProv);
1092
72
    if (!pMsgSvr)
1093
0
        return {};
1094
1095
72
    pRealSlot = nullptr;
1096
72
    *pMsgServer = pMsgSvr;
1097
1098
72
    sal_uInt16 nShellLevel = pMsgSvr->GetShellLevel();
1099
72
    SfxShell *pShell = pDispatcher->GetShell( nShellLevel );
1100
72
    if ( !pShell ) // rare GPF when browsing through update from Inet-Notify
1101
0
        return {};
1102
1103
72
    SfxItemPool &rPool = pShell->GetPool();
1104
1105
    // get the status method, which is served by the rCache
1106
72
    SfxStateFunc pFnc = nullptr;
1107
72
    pRealSlot = pMsgSvr->GetSlot();
1108
1109
72
    pFnc = pRealSlot->GetStateFnc();
1110
1111
    // the RealSlot is always on
1112
72
    SfxFoundCache_Impl aFound(pRealSlot->GetWhich(rPool), pRealSlot, rCache);
1113
72
    rFound.push_back( aFound );
1114
1115
    // Search through the bindings for slots served by the same function. This ,    // will only affect slots which are present in the found interface.
1116
1117
    // The position of the  Statecaches in StateCache-Array
1118
72
    std::size_t nCachePos = pImpl->nMsgPos;
1119
72
    const SfxSlot *pSibling = pRealSlot->GetNextSlot();
1120
1121
    // the Slots ODF and interfaces are linked in a circle
1122
2.08k
    while ( pSibling > pRealSlot )
1123
2.01k
    {
1124
2.01k
        SfxStateFunc pSiblingFnc=nullptr;
1125
2.01k
        SfxStateCache *pSiblingCache =
1126
2.01k
                GetStateCache( pSibling->GetSlotId(), &nCachePos );
1127
1128
        // Is the slot cached ?
1129
2.01k
        if ( pSiblingCache )
1130
792
        {
1131
792
            const SfxSlotServer *pServ = pSiblingCache->GetSlotServer(*pDispatcher, pImpl->xProv);
1132
792
            if ( pServ && pServ->GetShellLevel() == nShellLevel )
1133
792
                pSiblingFnc = pServ->GetSlot()->GetStateFnc();
1134
792
        }
1135
1136
        // Does the slot have to be updated at all?
1137
2.01k
        bool bInsert = pSiblingCache && pSiblingCache->IsControllerDirty();
1138
1139
        // It is not enough to ask for the same shell!!
1140
2.01k
        bool bSameMethod = pSiblingCache && pFnc == pSiblingFnc;
1141
1142
2.01k
        if ( bInsert && bSameMethod )
1143
792
        {
1144
792
            SfxFoundCache_Impl aFoundCache(
1145
792
                pSibling->GetWhich(rPool),
1146
792
                pSibling, *pSiblingCache);
1147
1148
792
            rFound.push_back( aFoundCache );
1149
792
        }
1150
1151
2.01k
        pSibling = pSibling->GetNextSlot();
1152
2.01k
    }
1153
1154
    // Create a Set from the ranges
1155
72
    WhichRangesContainer ranges;
1156
72
    size_t i = 0;
1157
648
    while ( i < rFound.size() )
1158
576
    {
1159
576
        const sal_uInt16 nWhich1 = rFound[i].nWhichId;
1160
            // consecutive numbers
1161
864
        for ( ; i < rFound.size()-1; ++i )
1162
792
            if ( rFound[i].nWhichId+1 != rFound[i+1].nWhichId )
1163
504
                break;
1164
576
        const sal_uInt16 nWhich2 = rFound[i++].nWhichId;
1165
576
        ranges = ranges.MergeRange(nWhich1, nWhich2);
1166
576
    }
1167
72
    SfxItemSet aSet(rPool, std::move(ranges));
1168
72
    return aSet;
1169
72
}
1170
1171
1172
void SfxBindings::UpdateControllers_Impl
1173
(
1174
    const SfxFoundCache_Impl&   rFound, // Cache, Slot, Which etc.
1175
    const SfxPoolItem*          pItem,  // item to send to controller
1176
    SfxItemState                eState  // state of item
1177
)
1178
864
{
1179
864
    SfxStateCache& rCache = rFound.rCache;
1180
864
    const SfxSlot* pSlot = rFound.pSlot;
1181
864
    DBG_ASSERT( !pSlot || rCache.GetId() == pSlot->GetSlotId(), "SID mismatch" );
1182
1183
    // bound until now, the Controller to update the Slot.
1184
864
    if (!rCache.IsControllerDirty())
1185
0
        return;
1186
1187
864
    if ( SfxItemState::INVALID == eState )
1188
0
    {
1189
        // ambiguous
1190
0
        rCache.SetState( SfxItemState::INVALID, INVALID_POOL_ITEM );
1191
0
    }
1192
864
    else if ( SfxItemState::DEFAULT == eState &&
1193
0
              SfxItemPool::IsSlot(rFound.nWhichId) )
1194
0
    {
1195
        // no Status or Default but without Pool
1196
        // tdf#162666 note that use DISABLED_POOL_ITEM needs to be
1197
        // handled correctly in the cache, see comments there
1198
0
        rCache.SetState( SfxItemState::UNKNOWN, DISABLED_POOL_ITEM );
1199
0
    }
1200
864
    else if ( SfxItemState::DISABLED == eState )
1201
360
        rCache.SetState(SfxItemState::DISABLED, nullptr);
1202
504
    else
1203
504
        rCache.SetState(SfxItemState::DEFAULT, pItem);
1204
864
}
1205
1206
IMPL_LINK( SfxBindings, NextJob, Timer *, pTimer, void )
1207
0
{
1208
0
    SfxViewFrame* pFrame = pDispatcher ? pDispatcher->GetFrame() : nullptr;
1209
0
    SfxLokLanguageGuard aGuard(pFrame ? pFrame->GetViewShell() : nullptr);
1210
1211
0
    NextJob_Impl(pTimer);
1212
0
}
1213
1214
bool SfxBindings::NextJob_Impl(Timer const * pTimer)
1215
0
{
1216
0
    const unsigned MAX_INPUT_DELAY = 200;
1217
1218
0
    if ( Application::GetLastInputInterval() < MAX_INPUT_DELAY && pTimer )
1219
0
    {
1220
0
        pImpl->aAutoTimer.SetTimeout(TIMEOUT_UPDATING);
1221
0
        return true;
1222
0
    }
1223
1224
0
    SfxApplication *pSfxApp = SfxGetpApp();
1225
1226
0
    if( pDispatcher )
1227
0
        pDispatcher->Update_Impl();
1228
1229
    // modifying the SfxObjectInterface-stack without SfxBindings => nothing to do
1230
0
    SfxViewFrame* pFrame = pDispatcher ? pDispatcher->GetFrame() : nullptr;
1231
0
    if ( (pFrame && !pFrame->GetObjectShell()->AcceptStateUpdate()) || pSfxApp->IsDowning() || pImpl->pCaches.empty() )
1232
0
    {
1233
0
        return true;
1234
0
    }
1235
0
    if ( !pDispatcher || !pDispatcher->IsFlushed() )
1236
0
    {
1237
0
        return true;
1238
0
    }
1239
1240
    // if possible Update all server / happens in its own time slice
1241
0
    if ( pImpl->bMsgDirty )
1242
0
    {
1243
0
        UpdateSlotServer_Impl();
1244
0
        return false;
1245
0
    }
1246
1247
0
    pImpl->bAllDirty = false;
1248
0
    pImpl->aAutoTimer.SetTimeout(TIMEOUT_UPDATING);
1249
1250
    // at least 10 loops and further if more jobs are available but no input
1251
0
    bool bPreEmptive = pTimer;
1252
0
    sal_uInt16 nLoops = 10;
1253
0
    pImpl->bInNextJob = true;
1254
0
    const std::size_t nCount = pImpl->pCaches.size();
1255
0
    while ( pImpl->nMsgPos < nCount )
1256
0
    {
1257
        // iterate through the bound functions
1258
0
        bool bJobDone = false;
1259
0
        while ( !bJobDone )
1260
0
        {
1261
0
            SfxStateCache* pCache = pImpl->pCaches[pImpl->nMsgPos].get();
1262
0
            assert(pCache && "invalid SfxStateCache-position in job queue");
1263
0
            bool bWasDirty = pCache->IsControllerDirty();
1264
0
            if ( bWasDirty )
1265
0
            {
1266
0
                Update_Impl(*pCache);
1267
0
                if ( pImpl->bMsgDirty )
1268
0
                {
1269
                    // Re-entrant registration/release happened during
1270
                    // the update. Restart so UpdateSlotServer_Impl
1271
                    // runs first.
1272
0
                    pImpl->bInNextJob = false;
1273
0
                    return false;
1274
0
                }
1275
0
            }
1276
1277
            // skip to next function binding
1278
0
            ++pImpl->nMsgPos;
1279
1280
            // keep job if it is not completed, but any input is available
1281
0
            bJobDone = pImpl->nMsgPos >= nCount;
1282
0
            if ( bJobDone && pImpl->bFirstRound )
1283
0
            {
1284
1285
                // Update of the  preferred shell has been done, now may
1286
                // also the others shells be updated
1287
0
                bJobDone = false;
1288
0
                pImpl->bFirstRound = false;
1289
0
                pImpl->nMsgPos = 0;
1290
0
            }
1291
1292
0
            if ( bWasDirty && !bJobDone && bPreEmptive && (--nLoops == 0) )
1293
0
            {
1294
0
                pImpl->bInNextJob = false;
1295
0
                return false;
1296
0
            }
1297
0
        }
1298
0
    }
1299
1300
0
    pImpl->nMsgPos = 0;
1301
1302
0
    pImpl->aAutoTimer.Stop();
1303
1304
    // Update round is finished
1305
0
    pImpl->bInNextJob = false;
1306
0
    Broadcast(SfxHint(SfxHintId::UpdateDone));
1307
0
    return true;
1308
0
}
1309
1310
1311
sal_uInt16 SfxBindings::EnterRegistrations(std::string_view pFile, int nLine)
1312
337k
{
1313
337k
    SAL_INFO(
1314
337k
        "sfx.control",
1315
337k
        std::setw(std::min(nRegLevel, sal_uInt16(8))) << ' ' << "this = " << this
1316
337k
            << " Level = " << nRegLevel << " SfxBindings::EnterRegistrations "
1317
337k
            << (!pFile.empty()
1318
337k
                ? SAL_STREAM("File: " << pFile << " Line: " << nLine) : ""));
1319
1320
    // When bindings are locked, also lock sub bindings.
1321
337k
    if ( pImpl->pSubBindings )
1322
0
    {
1323
0
        pImpl->pSubBindings->ENTERREGISTRATIONS();
1324
1325
        // These EnterRegistrations are not "real" for the SubBindings
1326
0
        pImpl->pSubBindings->pImpl->nOwnRegLevel--;
1327
1328
        // Synchronize Bindings
1329
0
        pImpl->pSubBindings->nRegLevel = nRegLevel + pImpl->pSubBindings->pImpl->nOwnRegLevel + 1;
1330
0
    }
1331
1332
337k
    pImpl->nOwnRegLevel++;
1333
1334
    // check if this is the outer most level
1335
337k
    if ( ++nRegLevel == 1 )
1336
69.5k
    {
1337
        // stop background-processing
1338
69.5k
        pImpl->aAutoTimer.Stop();
1339
1340
        // flush the cache
1341
69.5k
        pImpl->nCachedFunc1 = 0;
1342
69.5k
        pImpl->nCachedFunc2 = 0;
1343
1344
        // Mark if the all of the Caches have disappeared.
1345
69.5k
        pImpl->bCtrlReleased = false;
1346
69.5k
    }
1347
1348
337k
    return nRegLevel;
1349
337k
}
1350
1351
1352
void SfxBindings::LeaveRegistrations(  std::string_view pFile, int nLine )
1353
319k
{
1354
319k
    DBG_ASSERT( nRegLevel, "Leave without Enter" );
1355
1356
    // Only when the SubBindings are still locked by the Superbindings,
1357
    // remove this lock (i.e. if there are more locks than "real" ones)
1358
319k
    if ( pImpl->pSubBindings && pImpl->pSubBindings->nRegLevel > pImpl->pSubBindings->pImpl->nOwnRegLevel )
1359
0
    {
1360
        // Synchronize Bindings
1361
0
        pImpl->pSubBindings->nRegLevel = nRegLevel + pImpl->pSubBindings->pImpl->nOwnRegLevel;
1362
1363
        // This LeaveRegistrations is not "real" for SubBindings
1364
0
        pImpl->pSubBindings->pImpl->nOwnRegLevel++;
1365
0
        pImpl->pSubBindings->LEAVEREGISTRATIONS();
1366
0
    }
1367
1368
319k
    pImpl->nOwnRegLevel--;
1369
1370
    // check if this is the outer most level
1371
319k
    if ( --nRegLevel == 0 && SfxGetpApp() && !SfxGetpApp()->IsDowning() )
1372
69.5k
    {
1373
69.5k
        if ( pImpl->bContextChanged )
1374
0
        {
1375
0
            pImpl->bContextChanged = false;
1376
0
        }
1377
1378
69.5k
        SfxViewFrame* pFrame = pDispatcher->GetFrame();
1379
1380
        // If possible remove unused Caches, for example prepare PlugInInfo
1381
69.5k
        if ( pImpl->bCtrlReleased )
1382
0
        {
1383
0
            for ( sal_uInt16 nCache = pImpl->pCaches.size(); nCache > 0; --nCache )
1384
0
            {
1385
                // Get Cache via css::sdbcx::Index
1386
0
                SfxStateCache *pCache = pImpl->pCaches[nCache-1].get();
1387
1388
                // No interested Controller present
1389
0
                if ( pCache->GetItemLink() == nullptr && !pCache->GetInternalController() )
1390
0
                {
1391
                    // Remove Cache. Safety: first remove and then delete
1392
0
                    pImpl->pCaches.erase(pImpl->pCaches.begin() + nCache - 1);
1393
0
                }
1394
0
            }
1395
0
        }
1396
1397
        // restart background-processing
1398
69.5k
        pImpl->nMsgPos = 0;
1399
69.5k
        if ( !pFrame || !pFrame->GetObjectShell() )
1400
8.61k
            return;
1401
60.9k
        if ( !pImpl->pCaches.empty() )
1402
52.3k
        {
1403
52.3k
            pImpl->aAutoTimer.Stop();
1404
52.3k
            pImpl->aAutoTimer.SetTimeout(TIMEOUT_FIRST);
1405
52.3k
            pImpl->aAutoTimer.Start();
1406
52.3k
        }
1407
60.9k
    }
1408
1409
311k
    SAL_INFO(
1410
311k
        "sfx.control",
1411
311k
        std::setw(std::min(nRegLevel, sal_uInt16(8))) << ' ' << "this = " << this
1412
311k
            << " Level = " << nRegLevel << " SfxBindings::LeaveRegistrations "
1413
311k
            << (!pFile.empty()
1414
311k
                ? SAL_STREAM("File: " << pFile << " Line: " << nLine) : ""));
1415
311k
}
1416
1417
1418
void SfxBindings::SetDispatcher( SfxDispatcher *pDisp )
1419
25.8k
{
1420
25.8k
    SfxDispatcher *pOldDispat = pDispatcher;
1421
25.8k
    if ( pDisp == pDispatcher )
1422
8.61k
        return;
1423
1424
17.2k
    if ( pOldDispat )
1425
8.61k
    {
1426
8.61k
        SfxBindings* pBind = pOldDispat->GetBindings();
1427
17.2k
        while ( pBind )
1428
8.61k
        {
1429
8.61k
            if ( pBind->pImpl->pSubBindings == this && pBind->pDispatcher != pDisp )
1430
0
                pBind->SetSubBindings_Impl( nullptr );
1431
8.61k
            pBind = pBind->pImpl->pSubBindings;
1432
8.61k
        }
1433
8.61k
    }
1434
1435
17.2k
    pDispatcher = pDisp;
1436
1437
17.2k
    css::uno::Reference < css::frame::XDispatchProvider > xProv;
1438
17.2k
    if ( pDisp )
1439
8.61k
        xProv.set( pDisp->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
1440
1441
17.2k
    SetDispatchProvider_Impl( xProv );
1442
17.2k
    InvalidateAll( true );
1443
1444
17.2k
    if ( pDispatcher && !pOldDispat )
1445
8.61k
    {
1446
8.61k
        if ( pImpl->pSubBindings && pImpl->pSubBindings->pDispatcher != pOldDispat )
1447
0
        {
1448
0
            OSL_FAIL( "SubBindings already set before activating!" );
1449
0
            pImpl->pSubBindings->ENTERREGISTRATIONS();
1450
0
        }
1451
8.61k
        LEAVEREGISTRATIONS();
1452
8.61k
    }
1453
8.61k
    else if( !pDispatcher )
1454
8.61k
    {
1455
8.61k
        ENTERREGISTRATIONS();
1456
8.61k
        if ( pImpl->pSubBindings && pImpl->pSubBindings->pDispatcher != pOldDispat )
1457
0
        {
1458
0
            OSL_FAIL( "SubBindings still set even when deactivating!" );
1459
0
            pImpl->pSubBindings->LEAVEREGISTRATIONS();
1460
0
        }
1461
8.61k
    }
1462
1463
17.2k
    Broadcast( SfxHint( SfxHintId::DataChanged ) );
1464
1465
17.2k
    if ( !pDisp )
1466
8.61k
        return;
1467
1468
8.61k
    SfxBindings* pBind = pDisp->GetBindings();
1469
8.61k
    while ( pBind && pBind != this )
1470
0
    {
1471
0
        if ( !pBind->pImpl->pSubBindings )
1472
0
        {
1473
0
            pBind->SetSubBindings_Impl( this );
1474
0
            break;
1475
0
        }
1476
1477
0
        pBind = pBind->pImpl->pSubBindings;
1478
0
    }
1479
8.61k
}
1480
1481
1482
void SfxBindings::ClearCache_Impl( sal_uInt16 nSlotId )
1483
0
{
1484
0
    SfxStateCache* pCache = GetStateCache(nSlotId);
1485
0
    if (!pCache)
1486
0
        return;
1487
0
    pCache->ClearCache();
1488
0
}
1489
1490
1491
void SfxBindings::StartUpdate_Impl( bool bComplete )
1492
0
{
1493
0
    if ( pImpl->pSubBindings )
1494
0
        pImpl->pSubBindings->StartUpdate_Impl( bComplete );
1495
1496
0
    if ( !bComplete )
1497
        // Update may be interrupted
1498
0
        NextJob_Impl(&pImpl->aAutoTimer);
1499
0
    else
1500
        // Update all slots in a row
1501
0
        NextJob_Impl(nullptr);
1502
0
}
1503
1504
1505
SfxItemState SfxBindings::QueryState( sal_uInt16 nSlot, std::unique_ptr<SfxPoolItem> &rpState )
1506
0
{
1507
0
    css::uno::Reference< css::frame::XDispatch >  xDisp;
1508
0
    SfxStateCache *pCache = GetStateCache( nSlot );
1509
0
    if ( pCache )
1510
0
        xDisp = pCache->GetDispatch();
1511
0
    if ( xDisp.is() || !pCache )
1512
0
    {
1513
0
        const SfxSlot* pSlot = SfxSlotPool::GetSlotPool( pDispatcher->GetFrame() ).GetSlot( nSlot );
1514
0
        if ( !pSlot || pSlot->aUnoName.isEmpty() )
1515
0
            return SfxItemState::DISABLED;
1516
1517
0
        css::util::URL aURL;
1518
0
        OUString aCmd( u".uno:"_ustr );
1519
0
        aURL.Protocol = aCmd;
1520
0
        aURL.Path = pSlot->GetUnoName();
1521
0
        aCmd += aURL.Path;
1522
0
        aURL.Complete = aCmd;
1523
0
        aURL.Main = aCmd;
1524
1525
0
        if ( !xDisp.is() )
1526
0
            xDisp = pImpl->xProv->queryDispatch( aURL, OUString(), 0 );
1527
1528
0
        if ( xDisp.is() )
1529
0
        {
1530
0
            if (!dynamic_cast<SfxOfficeDispatch*>(xDisp.get()))
1531
0
            {
1532
0
                bool bDeleteCache = false;
1533
0
                if ( !pCache )
1534
0
                {
1535
0
                    pCache = new SfxStateCache( nSlot );
1536
0
                    pCache->GetSlotServer( *GetDispatcher_Impl(), pImpl->xProv );
1537
0
                    bDeleteCache = true;
1538
0
                }
1539
1540
0
                SfxItemState eState = SfxItemState::SET;
1541
0
                rtl::Reference<BindDispatch_Impl> xBind(new BindDispatch_Impl( xDisp, aURL, pCache, pSlot ));
1542
0
                xDisp->addStatusListener( xBind, aURL );
1543
0
                if ( !xBind->GetStatus().IsEnabled )
1544
0
                {
1545
0
                    eState = SfxItemState::DISABLED;
1546
0
                }
1547
0
                else
1548
0
                {
1549
0
                    css::uno::Any aAny = xBind->GetStatus().State;
1550
0
                    const css::uno::Type& aType = aAny.getValueType();
1551
1552
0
                    if ( aType == cppu::UnoType<bool>::get() )
1553
0
                    {
1554
0
                        bool bTemp = false;
1555
0
                        aAny >>= bTemp ;
1556
0
                        rpState.reset(new SfxBoolItem( nSlot, bTemp ));
1557
0
                    }
1558
0
                    else if ( aType == ::cppu::UnoType< ::cppu::UnoUnsignedShortType >::get() )
1559
0
                    {
1560
0
                        sal_uInt16 nTemp = 0;
1561
0
                        aAny >>= nTemp ;
1562
0
                        rpState.reset(new SfxUInt16Item( nSlot, nTemp ));
1563
0
                    }
1564
0
                    else if ( aType == cppu::UnoType<sal_uInt32>::get() )
1565
0
                    {
1566
0
                        sal_uInt32 nTemp = 0;
1567
0
                        aAny >>= nTemp ;
1568
0
                        rpState.reset(new SfxUInt32Item( nSlot, nTemp ));
1569
0
                    }
1570
0
                    else if ( aType == cppu::UnoType<OUString>::get() )
1571
0
                    {
1572
0
                        OUString sTemp ;
1573
0
                        aAny >>= sTemp ;
1574
0
                        rpState.reset(new SfxStringItem( nSlot, sTemp ));
1575
0
                    }
1576
0
                    else
1577
0
                        rpState.reset(new SfxVoidItem( nSlot ));
1578
0
                }
1579
1580
0
                xDisp->removeStatusListener( xBind, aURL );
1581
0
                xBind->Release();
1582
0
                xBind.clear();
1583
0
                if ( bDeleteCache )
1584
0
                {
1585
0
                    delete pCache;
1586
0
                    pCache = nullptr;
1587
0
                }
1588
0
                return eState;
1589
0
            }
1590
0
        }
1591
0
    }
1592
1593
    // Then test at the dispatcher to check if the returned items from
1594
    // there are always DELETE_ON_IDLE, a copy of it has to be made in
1595
    // order to allow for transition of ownership.
1596
0
    SfxPoolItemHolder aResult;
1597
0
    const SfxItemState eState(pDispatcher->QueryState(nSlot, aResult));
1598
1599
0
    if (SfxItemState::SET == eState)
1600
0
    {
1601
0
        DBG_ASSERT( aResult.getItem(), "SfxItemState::SET but no item!" );
1602
0
        if (aResult)
1603
0
            rpState.reset(aResult.getItem()->Clone());
1604
0
    }
1605
0
    else if (SfxItemState::DEFAULT == eState && aResult)
1606
0
    {
1607
0
        rpState.reset(aResult.getItem()->Clone());
1608
0
    }
1609
1610
0
    return eState;
1611
0
}
1612
1613
void SfxBindings::QueryControlState( sal_uInt16 nSlot, boost::property_tree::ptree& rState )
1614
0
{
1615
0
    if ( SfxGetpApp()->IsDowning() )
1616
0
        return;
1617
1618
0
    if ( pDispatcher )
1619
0
        pDispatcher->Flush();
1620
1621
0
    if ( pImpl->pSubBindings )
1622
0
        pImpl->pSubBindings->QueryControlState( nSlot, rState );
1623
1624
0
    SfxStateCache* pCache = GetStateCache( nSlot );
1625
0
    if ( !pCache )
1626
0
        return;
1627
1628
0
    if ( pImpl->bMsgDirty )
1629
0
    {
1630
0
        UpdateSlotServer_Impl();
1631
0
        pCache = GetStateCache( nSlot );
1632
0
    }
1633
1634
0
    if (pCache && pCache->GetItemLink() )
1635
0
    {
1636
0
        pCache->GetState(rState);
1637
0
    }
1638
0
}
1639
1640
sal_uInt16 SfxBindings::QuerySlotId( const util::URL& aURL )
1641
0
{
1642
0
    if (!pImpl)
1643
0
        return 0;
1644
1645
0
    css::uno::Reference<css::frame::XDispatch> xDispatch =
1646
0
        pImpl->xProv->queryDispatch(aURL, OUString(), 0);
1647
0
    if (!xDispatch.is())
1648
0
        return 0;
1649
1650
0
    SfxOfficeDispatch* pDispatch = dynamic_cast<SfxOfficeDispatch*>(xDispatch.get());
1651
0
    if (!pDispatch)
1652
0
        return 0;
1653
1654
0
    return pDispatch->GetId();
1655
0
}
1656
1657
void SfxBindings::SetSubBindings_Impl( SfxBindings *pSub )
1658
0
{
1659
0
    if ( pImpl->pSubBindings )
1660
0
    {
1661
0
        pImpl->pSubBindings->SetDispatchProvider_Impl( css::uno::Reference< css::frame::XDispatchProvider > () );
1662
0
    }
1663
1664
0
    pImpl->pSubBindings = pSub;
1665
1666
0
    if ( pSub )
1667
0
    {
1668
0
        pImpl->pSubBindings->SetDispatchProvider_Impl( pImpl->xProv );
1669
0
    }
1670
0
}
1671
1672
SfxBindings* SfxBindings::GetSubBindings_Impl() const
1673
8.61k
{
1674
8.61k
    return pImpl->pSubBindings;
1675
8.61k
}
1676
1677
void SfxBindings::SetWorkWindow_Impl( std::unique_ptr<SfxWorkWindow> xWork )
1678
8.61k
{
1679
8.61k
    pImpl->mxWorkWin = std::move(xWork);
1680
8.61k
}
1681
1682
SfxWorkWindow* SfxBindings::GetWorkWindow_Impl() const
1683
0
{
1684
0
    return pImpl->mxWorkWin.get();
1685
0
}
1686
1687
bool SfxBindings::IsInUpdate() const
1688
24.5k
{
1689
24.5k
    bool bInUpdate = pImpl->bInUpdate;
1690
24.5k
    if ( !bInUpdate && pImpl->pSubBindings )
1691
0
        bInUpdate = pImpl->pSubBindings->IsInUpdate();
1692
24.5k
    return bInUpdate;
1693
24.5k
}
1694
1695
void SfxBindings::SetVisibleState( sal_uInt16 nId, bool bShow )
1696
0
{
1697
0
    SfxStateCache *pCache = GetStateCache( nId );
1698
0
    if ( pCache )
1699
0
        pCache->SetVisibleState( bShow );
1700
0
}
1701
1702
void SfxBindings::SetActiveFrame( const css::uno::Reference< css::frame::XFrame > & rFrame )
1703
17.2k
{
1704
17.2k
    if ( rFrame.is() || !pDispatcher )
1705
8.61k
        SetDispatchProvider_Impl( css::uno::Reference< css::frame::XDispatchProvider > ( rFrame, css::uno::UNO_QUERY ) );
1706
8.61k
    else
1707
8.61k
        SetDispatchProvider_Impl( css::uno::Reference< css::frame::XDispatchProvider > (
1708
8.61k
            pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), css::uno::UNO_QUERY ) );
1709
17.2k
}
1710
1711
css::uno::Reference< css::frame::XFrame > SfxBindings::GetActiveFrame() const
1712
17.2k
{
1713
17.2k
    const css::uno::Reference< css::frame::XFrame > xFrame( pImpl->xProv, css::uno::UNO_QUERY );
1714
17.2k
    if ( xFrame.is() || !pDispatcher )
1715
17.2k
        return xFrame;
1716
0
    else
1717
0
        return pDispatcher->GetFrame()->GetFrame().GetFrameInterface();
1718
17.2k
}
1719
1720
void SfxBindings::SetDispatchProvider_Impl( const css::uno::Reference< css::frame::XDispatchProvider > & rProv )
1721
34.4k
{
1722
34.4k
    bool bInvalidate = ( rProv != pImpl->xProv );
1723
34.4k
    if ( bInvalidate )
1724
17.2k
    {
1725
17.2k
        pImpl->xProv = rProv;
1726
17.2k
        InvalidateAll( true );
1727
17.2k
    }
1728
1729
34.4k
    if ( pImpl->pSubBindings )
1730
0
        pImpl->pSubBindings->SetDispatchProvider_Impl( pImpl->xProv );
1731
34.4k
}
1732
1733
const css::uno::Reference< css::frame::XDispatchRecorder >& SfxBindings::GetRecorder() const
1734
0
{
1735
0
    return pImpl->xRecorder;
1736
0
}
1737
1738
void SfxBindings::SetRecorder_Impl( css::uno::Reference< css::frame::XDispatchRecorder > const & rRecorder )
1739
8.61k
{
1740
8.61k
    pImpl->xRecorder = rRecorder;
1741
8.61k
}
1742
1743
void SfxBindings::ContextChanged_Impl()
1744
0
{
1745
0
    if ( !pImpl->bInUpdate && ( !pImpl->bContextChanged || !pImpl->bAllMsgDirty ) )
1746
0
    {
1747
0
        InvalidateAll( true );
1748
0
    }
1749
0
}
1750
1751
uno::Reference < frame::XDispatch > SfxBindings::GetDispatch( const SfxSlot* pSlot, const util::URL& aURL, bool bMasterCommand )
1752
540
{
1753
540
    uno::Reference < frame::XDispatch > xRet;
1754
540
    SfxStateCache* pCache = GetStateCache( pSlot->nSlotId );
1755
540
    if ( pCache && !bMasterCommand )
1756
540
        xRet = pCache->GetInternalDispatch();
1757
540
    if ( !xRet.is() )
1758
540
    {
1759
        // dispatches for slaves are unbound, they don't have a state
1760
540
        SfxOfficeDispatch* pDispatch = bMasterCommand ?
1761
0
            new SfxOfficeDispatch( pDispatcher, pSlot, aURL ) :
1762
540
            new SfxOfficeDispatch( *this, pDispatcher, pSlot, aURL );
1763
1764
540
        pDispatch->SetMasterUnoCommand( bMasterCommand );
1765
540
        xRet.set( pDispatch );
1766
540
        if ( !pCache )
1767
0
            pCache = GetStateCache( pSlot->nSlotId );
1768
1769
540
        DBG_ASSERT( bMasterCommand || pCache, "No cache for OfficeDispatch!" );
1770
540
        if ( pCache && !bMasterCommand )
1771
540
            pCache->SetInternalDispatch( xRet );
1772
540
    }
1773
1774
540
    return xRet;
1775
540
}
1776
1777
Timer& SfxBindings::GetTimer()
1778
0
{
1779
0
    return pImpl->aAutoTimer;
1780
0
}
1781
1782
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */