Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/control/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
24.4k
#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
0
        : nWhichId(nW)
77
0
        , pSlot(pS)
78
0
        , rCache(rC)
79
0
    {}
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
0
    {
90
0
        return maData[i];
91
0
    }
92
93
    size_t size() const
94
0
    {
95
0
        return maData.size();
96
0
    }
97
98
    void push_back( SfxFoundCache_Impl p )
99
0
    {
100
0
        maData.push_back(p);
101
0
    }
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
4.08k
:   pImpl(new SfxBindings_Impl),
131
4.08k
    pDispatcher(nullptr),
132
4.08k
    nRegLevel(1)    // first becomes 0, when the Dispatcher is set
133
134
4.08k
{
135
4.08k
    pImpl->nMsgPos = 0;
136
4.08k
    pImpl->bAllMsgDirty = true;
137
4.08k
    pImpl->bContextChanged = false;
138
4.08k
    pImpl->bMsgDirty = true;
139
4.08k
    pImpl->bAllDirty = true;
140
4.08k
    pImpl->nCachedFunc1 = 0;
141
4.08k
    pImpl->nCachedFunc2 = 0;
142
4.08k
    pImpl->bCtrlReleased = false;
143
4.08k
    pImpl->bFirstRound = false;
144
4.08k
    pImpl->bInNextJob = false;
145
4.08k
    pImpl->bInUpdate = false;
146
4.08k
    pImpl->pSubBindings = nullptr;
147
4.08k
    pImpl->nOwnRegLevel = nRegLevel;
148
149
    // all caches are valid (no pending invalidate-job)
150
    // create the list of caches
151
4.08k
    pImpl->aAutoTimer.SetPriority(TaskPriority::DEFAULT_IDLE);
152
4.08k
    pImpl->aAutoTimer.SetInvokeHandler( LINK(this, SfxBindings, NextJob) );
153
4.08k
}
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
4.08k
{
171
    // The SubBindings should not be locked!
172
4.08k
    pImpl->pSubBindings = nullptr;
173
174
4.08k
    ENTERREGISTRATIONS();
175
176
4.08k
    pImpl->aAutoTimer.Stop();
177
4.08k
    DeleteControllers_Impl();
178
179
    // Delete Caches
180
4.08k
    pImpl->pCaches.clear();
181
182
4.08k
    pImpl->mxWorkWin.reset();
183
4.08k
}
184
185
186
void SfxBindings::DeleteControllers_Impl()
187
4.08k
{
188
    // in the first round delete Controllers
189
4.08k
    std::size_t nCount = pImpl->pCaches.size();
190
4.08k
    std::size_t nCache = 0;
191
65.3k
    while (nCache < nCount)
192
61.2k
    {
193
        // Remember were you are
194
61.2k
        SfxStateCache *pCache = pImpl->pCaches[nCache].get();
195
61.2k
        sal_uInt16 nSlotId = pCache->GetId();
196
197
        // Re-align, because the cache may have been reduced
198
61.2k
        std::size_t nNewCount = pImpl->pCaches.size();
199
61.2k
        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
61.2k
        ++nCache;
211
61.2k
    }
212
213
    // Delete all Caches
214
65.3k
    for ( nCache = pImpl->pCaches.size(); nCache > 0; --nCache )
215
61.2k
    {
216
        // Get Cache via css::sdbcx::Index
217
61.2k
        SfxStateCache *pCache = pImpl->pCaches[ nCache-1 ].get();
218
219
        // unbind all controllers in the cache
220
61.2k
        SfxControllerItem *pNext;
221
61.2k
        for ( SfxControllerItem *pCtrl = pCache->GetItemLink();
222
61.2k
              pCtrl; pCtrl = pNext )
223
0
        {
224
0
            pNext = pCtrl->GetItemLink();
225
0
            pCtrl->UnBind();
226
0
        }
227
228
61.2k
        if ( pCache->GetInternalController() )
229
0
            pCache->GetInternalController()->UnBind();
230
231
        // Delete Cache
232
61.2k
        pImpl->pCaches.erase(pImpl->pCaches.begin() + nCache - 1);
233
61.2k
    }
234
4.08k
}
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
0
{
247
0
    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
0
    if ( !pDispatcher )
255
0
        return;
256
257
    // gather together all with the same status method which are dirty
258
0
    SfxDispatcher &rDispat = *pDispatcher;
259
0
    const SfxSlot *pRealSlot = nullptr;
260
0
    const SfxSlotServer* pMsgServer = nullptr;
261
0
    SfxFoundCacheArr_Impl aFound;
262
0
    std::optional<SfxItemSet> pSet = CreateSet_Impl(rCache, pRealSlot, &pMsgServer, aFound);
263
0
    bool bUpdated = false;
264
0
    if ( pSet )
265
0
    {
266
        // Query Status
267
0
        if ( rDispat.FillState_( *pMsgServer, *pSet, pRealSlot ) )
268
0
        {
269
            // Post Status
270
0
            for ( size_t nPos = 0; nPos < aFound.size(); ++nPos )
271
0
            {
272
0
                const SfxFoundCache_Impl& rFound = aFound[nPos];
273
0
                sal_uInt16 nWhich = rFound.nWhichId;
274
0
                const SfxPoolItem *pItem = nullptr;
275
0
                SfxItemState eState = pSet->GetItemState(nWhich, true, &pItem);
276
0
                if ( eState == SfxItemState::DEFAULT && SfxItemPool::IsWhich(nWhich) )
277
0
                    pItem = &pSet->Get(nWhich);
278
0
                UpdateControllers_Impl( rFound, pItem, eState );
279
0
            }
280
0
            bUpdated = true;
281
0
        }
282
283
0
        pSet.reset();
284
0
    }
285
286
0
    if (!bUpdated)
287
0
    {
288
0
        SfxFoundCache_Impl aFoundCache(0, pRealSlot, rCache);
289
0
        UpdateControllers_Impl( aFoundCache, nullptr, SfxItemState::DISABLED);
290
0
    }
291
0
}
292
293
void SfxBindings::InvalidateSlotsInMap_Impl()
294
0
{
295
0
    for (auto const& slot : pImpl->m_aInvalidateSlots)
296
0
        Invalidate( slot.first );
297
298
0
    pImpl->m_aInvalidateSlots.clear();
299
0
}
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
0
{
313
0
    if ( pDispatcher )
314
0
        pDispatcher->Flush();
315
316
0
    if ( pImpl->pSubBindings )
317
0
        pImpl->pSubBindings->Update( nId );
318
319
0
    SfxStateCache* pCache = GetStateCache( nId );
320
0
    if ( !pCache )
321
0
        return;
322
323
0
    pImpl->bInUpdate = true;
324
0
    if ( pImpl->bMsgDirty )
325
0
    {
326
0
        UpdateSlotServer_Impl();
327
0
        pCache = GetStateCache( nId );
328
0
    }
329
330
0
    if (pCache)
331
0
    {
332
0
        bool bInternalUpdate = true;
333
0
        if( pCache->GetDispatch().is() && pCache->GetItemLink() )
334
0
        {
335
0
            pCache->SetCachedState(true);
336
0
            bInternalUpdate = ( pCache->GetInternalController() != nullptr );
337
0
        }
338
339
0
        if ( bInternalUpdate )
340
0
        {
341
            // Query Status
342
0
            const SfxSlotServer* pMsgServer = pDispatcher ? pCache->GetSlotServer(*pDispatcher, pImpl->xProv) : nullptr;
343
0
            if ( !pCache->IsControllerDirty() )
344
0
            {
345
0
                pImpl->bInUpdate = false;
346
0
                InvalidateSlotsInMap_Impl();
347
0
                return;
348
0
            }
349
0
            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
0
            Update_Impl(*pCache);
358
0
        }
359
360
0
        pImpl->bAllDirty = false;
361
0
    }
362
363
0
    pImpl->bInUpdate = false;
364
0
    InvalidateSlotsInMap_Impl();
365
0
}
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
116
{
472
116
    return GetStateCache(nId, nullptr);
473
116
}
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
116
{
484
    // is the specified function bound?
485
116
    const std::size_t nStart = ( pPos ? *pPos : 0 );
486
116
    const std::size_t nPos = GetSlotPos( nId, nStart );
487
488
116
    if ( nPos < pImpl->pCaches.size() &&
489
116
         pImpl->pCaches[nPos]->GetId() == nId )
490
0
    {
491
0
        if ( pPos )
492
0
            *pPos = nPos;
493
0
        return pImpl->pCaches[nPos].get();
494
0
    }
495
116
    return nullptr;
496
116
}
497
498
499
void SfxBindings::InvalidateAll
500
(
501
    bool  bWithMsg  /* true   Mark Slot Server as invalid
502
                       false  Slot Server remains valid */
503
)
504
68.3k
{
505
68.3k
    DBG_ASSERT( !pImpl->bInUpdate, "SfxBindings::Invalidate while in update" );
506
507
68.3k
    if ( pImpl->pSubBindings )
508
0
        pImpl->pSubBindings->InvalidateAll( bWithMsg );
509
510
    // everything is already set dirty or downing => nothing to do
511
68.3k
    if ( !pDispatcher ||
512
60.1k
         ( pImpl->bAllDirty && ( !bWithMsg || pImpl->bAllMsgDirty ) ) ||
513
0
         SfxGetpApp()->IsDowning() )
514
68.3k
    {
515
68.3k
        return;
516
68.3k
    }
517
518
0
    pImpl->bAllMsgDirty = pImpl->bAllMsgDirty || bWithMsg;
519
0
    pImpl->bMsgDirty = pImpl->bMsgDirty || pImpl->bAllMsgDirty || bWithMsg;
520
0
    pImpl->bAllDirty = true;
521
522
0
    for (std::unique_ptr<SfxStateCache>& pCache : pImpl->pCaches)
523
0
        pCache->Invalidate(bWithMsg);
524
525
0
    pImpl->nMsgPos = 0;
526
0
    if ( !nRegLevel )
527
0
    {
528
0
        pImpl->aAutoTimer.Stop();
529
0
        pImpl->aAutoTimer.SetTimeout(TIMEOUT_FIRST);
530
0
        pImpl->aAutoTimer.Start();
531
0
    }
532
0
}
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
8.49k
{
541
8.49k
    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
8.49k
    if ( pImpl->pSubBindings )
553
0
        pImpl->pSubBindings->Invalidate( pIds );
554
555
    // everything is already set dirty or downing => nothing to do
556
8.49k
    if ( !pDispatcher || pImpl->bAllDirty || SfxGetpApp()->IsDowning() )
557
8.49k
        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
117k
{
645
117k
    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
117k
    if ( pImpl->pSubBindings )
654
0
        pImpl->pSubBindings->Invalidate( nId );
655
656
117k
    if ( !pDispatcher || pImpl->bAllDirty || SfxGetpApp()->IsDowning() )
657
117k
        return;
658
659
0
    SfxStateCache* pCache = GetStateCache(nId);
660
0
    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
0
}
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
163k
{
712
    // answer immediately if a function-seek comes repeated
713
163k
    if ( pImpl->nCachedFunc1 < pImpl->pCaches.size() &&
714
159k
         pImpl->pCaches[pImpl->nCachedFunc1]->GetId() == nId )
715
0
    {
716
0
        return pImpl->nCachedFunc1;
717
0
    }
718
163k
    if ( pImpl->nCachedFunc2 < pImpl->pCaches.size() &&
719
159k
         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
163k
    if ( pImpl->pCaches.size() <= nStartSearchAt )
728
4.08k
    {
729
4.08k
        return 0;
730
4.08k
    }
731
159k
    if ( pImpl->pCaches.size() == (nStartSearchAt+1) )
732
4.08k
    {
733
4.08k
        return pImpl->pCaches[nStartSearchAt]->GetId() >= nId ? 0 : 1;
734
4.08k
    }
735
155k
    std::size_t nLow = nStartSearchAt;
736
155k
    std::size_t nMid = 0;
737
155k
    std::size_t nHigh = 0;
738
155k
    bool bFound = false;
739
155k
    nHigh = pImpl->pCaches.size() - 1;
740
616k
    while ( !bFound && nLow <= nHigh )
741
469k
    {
742
469k
        nMid = (nLow + nHigh) >> 1;
743
469k
        DBG_ASSERT( nMid < pImpl->pCaches.size(), "bsearch is buggy" );
744
469k
        int nDiff = static_cast<int>(nId) - static_cast<int>( (pImpl->pCaches[nMid])->GetId() );
745
469k
        if ( nDiff < 0)
746
163k
        {   if ( nMid == 0 )
747
8.16k
                break;
748
155k
            nHigh = nMid - 1;
749
155k
        }
750
306k
        else if ( nDiff > 0 )
751
204k
        {   nLow = nMid + 1;
752
204k
            if ( nLow == 0 )
753
0
                break;
754
204k
        }
755
102k
        else
756
102k
            bFound = true;
757
469k
    }
758
155k
    std::size_t nPos = bFound ? nMid : nLow;
759
155k
    DBG_ASSERT( nPos <= pImpl->pCaches.size(), "" );
760
155k
    DBG_ASSERT( nPos == pImpl->pCaches.size() ||
761
155k
                nId <= pImpl->pCaches[nPos]->GetId(), "" );
762
155k
    DBG_ASSERT( nPos == nStartSearchAt ||
763
155k
                nId > pImpl->pCaches[nPos-1]->GetId(), "" );
764
155k
    DBG_ASSERT( ( (nPos+1) >= pImpl->pCaches.size() ) ||
765
155k
                nId < pImpl->pCaches[nPos+1]->GetId(), "" );
766
155k
    pImpl->nCachedFunc2 = pImpl->nCachedFunc1;
767
155k
    pImpl->nCachedFunc1 = nPos;
768
155k
    return nPos;
769
159k
}
770
771
void SfxBindings::RegisterInternal_Impl( SfxControllerItem& rItem )
772
0
{
773
0
    Register_Impl( rItem, true );
774
775
0
}
776
777
void SfxBindings::Register( SfxControllerItem& rItem )
778
81.6k
{
779
81.6k
    Register_Impl( rItem, false );
780
81.6k
}
781
782
void SfxBindings::Register_Impl( SfxControllerItem& rItem, bool bInternal )
783
81.6k
{
784
//    DBG_ASSERT( nRegLevel > 0, "registration without EnterRegistrations" );
785
81.6k
    DBG_ASSERT( !pImpl->bInNextJob, "SfxBindings::Register while status-updating" );
786
787
    // insert new cache if it does not already exist
788
81.6k
    sal_uInt16 nId = rItem.GetId();
789
81.6k
    std::size_t nPos = GetSlotPos(nId);
790
81.6k
    if ( nPos >= pImpl->pCaches.size() ||
791
65.3k
         pImpl->pCaches[nPos]->GetId() != nId )
792
61.2k
    {
793
61.2k
        pImpl->pCaches.insert( pImpl->pCaches.begin() + nPos, std::make_unique<SfxStateCache>(nId) );
794
61.2k
        DBG_ASSERT( nPos == 0 ||
795
61.2k
                    pImpl->pCaches[nPos]->GetId() >
796
61.2k
                        pImpl->pCaches[nPos-1]->GetId(), "" );
797
61.2k
        DBG_ASSERT( (nPos == pImpl->pCaches.size()-1) ||
798
61.2k
                    pImpl->pCaches[nPos]->GetId() <
799
61.2k
                        pImpl->pCaches[nPos+1]->GetId(), "" );
800
61.2k
        pImpl->bMsgDirty = true;
801
61.2k
    }
802
803
    // enqueue the new binding
804
81.6k
    if ( bInternal )
805
0
    {
806
0
        pImpl->pCaches[nPos]->SetInternalController( &rItem );
807
0
    }
808
81.6k
    else
809
81.6k
    {
810
81.6k
        SfxControllerItem *pOldItem = pImpl->pCaches[nPos]->ChangeItemLink(&rItem);
811
81.6k
        rItem.ChangeItemLink(pOldItem);
812
81.6k
    }
813
81.6k
}
814
815
816
void SfxBindings::Release( SfxControllerItem& rItem )
817
81.6k
{
818
81.6k
    DBG_ASSERT( !pImpl->bInNextJob, "SfxBindings::Release while status-updating" );
819
81.6k
    ENTERREGISTRATIONS();
820
821
    // find the bound function
822
81.6k
    sal_uInt16 nId = rItem.GetId();
823
81.6k
    std::size_t nPos = GetSlotPos(nId);
824
81.6k
    SfxStateCache* pCache = (nPos < pImpl->pCaches.size()) ? pImpl->pCaches[nPos].get() : nullptr;
825
81.6k
    if ( pCache && pCache->GetId() == nId )
826
81.6k
    {
827
81.6k
        if ( pCache->GetInternalController() == &rItem )
828
0
        {
829
0
            pCache->ReleaseInternalController();
830
0
        }
831
81.6k
        else
832
81.6k
        {
833
            // is this the first binding in the list?
834
81.6k
            SfxControllerItem* pItem = pCache->GetItemLink();
835
81.6k
            if ( pItem == &rItem )
836
61.2k
                pCache->ChangeItemLink( rItem.GetItemLink() );
837
20.4k
            else
838
20.4k
            {
839
                // search the binding in the list
840
20.4k
                while ( pItem && pItem->GetItemLink() != &rItem )
841
0
                    pItem = pItem->GetItemLink();
842
843
                // unlink it if it was found
844
20.4k
                if ( pItem )
845
20.4k
                    pItem->ChangeItemLink( rItem.GetItemLink() );
846
20.4k
            }
847
81.6k
        }
848
849
        // was this the last controller?
850
81.6k
        if ( pCache->GetItemLink() == nullptr && !pCache->GetInternalController() )
851
61.2k
        {
852
61.2k
            pImpl->bCtrlReleased = true;
853
61.2k
        }
854
81.6k
    }
855
856
81.6k
    LEAVEREGISTRATIONS();
857
81.6k
}
858
859
860
SfxPoolItemHolder SfxBindings::ExecuteSynchron( sal_uInt16 nId, const SfxPoolItem** ppItems )
861
0
{
862
0
    return Execute(nId, ppItems, SfxCallMode::SYNCHRON);
863
0
}
864
865
SfxPoolItemHolder SfxBindings::Execute( sal_uInt16 nId, const SfxPoolItem** ppItems, SfxCallMode nCallMode )
866
0
{
867
0
    if( !nId || !pDispatcher )
868
0
        return SfxPoolItemHolder();
869
870
0
    return Execute_Impl(nId, ppItems, nCallMode);
871
0
}
872
873
SfxPoolItemHolder SfxBindings::Execute_Impl( sal_uInt16 nId, const SfxPoolItem** ppItems, SfxCallMode nCallMode )
874
0
{
875
0
    SfxStateCache *pCache = GetStateCache( nId );
876
0
    if ( !pCache )
877
0
    {
878
0
        SfxBindings *pBind = pImpl->pSubBindings;
879
0
        while ( pBind )
880
0
        {
881
0
            if ( pBind->GetStateCache( nId ) )
882
0
                return pBind->Execute_Impl(nId, ppItems, nCallMode);
883
0
            pBind = pBind->pImpl->pSubBindings;
884
0
        }
885
0
    }
886
887
0
    SfxDispatcher &rDispatcher = *pDispatcher;
888
0
    rDispatcher.Flush();
889
890
    // get SlotServer (Slot+ShellLevel) and Shell from cache
891
0
    std::unique_ptr<SfxStateCache> xCache;
892
0
    if ( !pCache )
893
0
    {
894
        // Execution of non cached slots (Accelerators don't use Controllers)
895
        // slot is uncached, use SlotCache to handle external dispatch providers
896
0
        xCache.reset(new SfxStateCache(nId));
897
0
        pCache = xCache.get();
898
0
    }
899
900
0
    pCache->GetSlotServer( rDispatcher, pImpl->xProv ); // make pCache->GetDispatch() up to date
901
0
    if ( pCache->GetDispatch().is() )
902
0
    {
903
0
        SfxItemPool &rPool = GetDispatcher()->GetFrame()->GetObjectShell()->GetPool();
904
0
        SfxRequest aReq( nId, nCallMode, rPool );
905
0
        if( ppItems )
906
0
            while( *ppItems )
907
0
                aReq.AppendItem( **ppItems++ );
908
909
        // cache binds to an external dispatch provider
910
0
        sal_Int16 eRet = pCache->Dispatch( aReq.GetArgs(), nCallMode == SfxCallMode::SYNCHRON );
911
0
        SfxPoolItem* pPoolItem(nullptr);
912
0
        if ( eRet == css::frame::DispatchResultState::DONTKNOW )
913
0
            pPoolItem = new SfxVoidItem( nId );
914
0
        else
915
0
            pPoolItem = new SfxBoolItem( nId, eRet == css::frame::DispatchResultState::SUCCESS);
916
917
0
        return SfxPoolItemHolder(rPool, pPoolItem, true);
918
0
    }
919
920
    // slot is handled internally by SfxDispatcher
921
0
    if ( pImpl->bMsgDirty )
922
0
        UpdateSlotServer_Impl();
923
924
0
    SfxShell *pShell=nullptr;
925
0
    const SfxSlot *pSlot=nullptr;
926
927
0
    const SfxSlotServer* pServer = pCache->GetSlotServer( rDispatcher, pImpl->xProv );
928
0
    if ( !pServer )
929
0
    {
930
0
        return SfxPoolItemHolder();
931
0
    }
932
0
    else
933
0
    {
934
0
        pShell = rDispatcher.GetShell( pServer->GetShellLevel() );
935
0
        pSlot = pServer->GetSlot();
936
0
    }
937
938
0
    if (!pShell)
939
0
        return SfxPoolItemHolder();
940
941
0
    SfxItemPool &rPool = pShell->GetPool();
942
0
    SfxRequest aReq( nId, nCallMode, rPool );
943
0
    if( ppItems )
944
0
        while( *ppItems )
945
0
            aReq.AppendItem( **ppItems++ );
946
947
0
    Execute_Impl( aReq, pSlot, pShell );
948
949
0
    const SfxPoolItemHolder& rRetval(aReq.GetReturnValue());
950
951
0
    if (!rRetval)
952
0
        return SfxPoolItemHolder(rPool, new SfxVoidItem( nId ), true);
953
954
0
    return rRetval;
955
0
}
956
957
void SfxBindings::Execute_Impl( SfxRequest& aReq, const SfxSlot* pSlot, SfxShell* pShell )
958
0
{
959
0
    SfxItemPool &rPool = pShell->GetPool();
960
961
0
    if ( SfxSlotKind::Attribute == pSlot->GetKind() )
962
0
    {
963
        // Which value has to be mapped for Attribute slots
964
0
        const sal_uInt16 nSlotId = pSlot->GetSlotId();
965
0
        aReq.SetSlot( nSlotId );
966
0
        if ( pSlot->IsMode(SfxSlotMode::TOGGLE) )
967
0
        {
968
            // The value is attached to a toggleable attribute (Bools)
969
0
            sal_uInt16 nWhich = pSlot->GetWhich(rPool);
970
0
            SfxItemSet aSet(rPool, nWhich, nWhich);
971
0
            SfxStateFunc pFunc = pSlot->GetStateFnc();
972
0
            (*pFunc)(pShell, aSet);
973
0
            const SfxPoolItem *pOldItem;
974
0
            SfxItemState eState = aSet.GetItemState(nWhich, true, &pOldItem);
975
0
            if ( eState == SfxItemState::DISABLED )
976
0
                return;
977
978
0
            if ( SfxItemState::DEFAULT == eState && SfxItemPool::IsWhich(nWhich) )
979
0
                pOldItem = &aSet.Get(nWhich);
980
981
0
            if ( SfxItemState::SET == eState ||
982
0
                 ( SfxItemState::DEFAULT == eState &&
983
0
                   SfxItemPool::IsWhich(nWhich) &&
984
0
                   pOldItem ) )
985
0
            {
986
0
                if ( auto pOldBoolItem = dynamic_cast< const SfxBoolItem *>( pOldItem ) )
987
0
                {
988
                    // we can toggle Bools
989
0
                    bool bOldValue = pOldBoolItem->GetValue();
990
0
                    std::unique_ptr<SfxBoolItem> pNewItem(static_cast<SfxBoolItem*>(pOldItem->Clone()));
991
0
                    pNewItem->SetValue( !bOldValue );
992
0
                    aReq.AppendItem( *pNewItem );
993
0
                }
994
0
                else if ( auto pOldEnumItem = dynamic_cast< const SfxEnumItemInterface *>( pOldItem ) )
995
0
                {
996
0
                    if (pOldEnumItem->HasBoolValue())
997
0
                    {
998
                        // and Enums with Bool-Interface
999
0
                        std::unique_ptr<SfxEnumItemInterface> pNewItem(
1000
0
                            static_cast<SfxEnumItemInterface*>(pOldEnumItem->Clone()));
1001
0
                        pNewItem->SetBoolValue(!pOldEnumItem->GetBoolValue());
1002
0
                        aReq.AppendItem( *pNewItem );
1003
0
                    }
1004
0
                }
1005
0
                else {
1006
0
                    OSL_FAIL( "Toggle only for Enums and Bools allowed" );
1007
0
                }
1008
0
            }
1009
0
            else if ( SfxItemState::INVALID == eState )
1010
0
            {
1011
                // Create one Status-Item for each Factory
1012
0
                std::unique_ptr<SfxPoolItem> pNewItem = pSlot->GetType()->CreateItem();
1013
0
                DBG_ASSERT( pNewItem, "Toggle to slot without ItemFactory" );
1014
0
                pNewItem->SetWhich( nWhich );
1015
1016
0
                if ( auto pNewBoolItem = dynamic_cast<SfxBoolItem *>( pNewItem.get() ) )
1017
0
                {
1018
                  // we can toggle Bools
1019
0
                    pNewBoolItem->SetValue( true );
1020
0
                    aReq.AppendItem( *pNewItem );
1021
0
                }
1022
0
                else if ( auto pEnumItem = dynamic_cast<SfxEnumItemInterface *>( pNewItem.get() ) )
1023
0
                {
1024
0
                    if (pEnumItem->HasBoolValue())
1025
0
                    {
1026
                        // and Enums with Bool-Interface
1027
0
                        pEnumItem->SetBoolValue(true);
1028
0
                        aReq.AppendItem( *pNewItem );
1029
0
                    }
1030
0
                }
1031
0
                else {
1032
0
                    OSL_FAIL( "Toggle only for Enums and Bools allowed" );
1033
0
                }
1034
0
            }
1035
0
            else {
1036
0
                OSL_FAIL( "suspicious Toggle-Slot" );
1037
0
            }
1038
0
        }
1039
1040
0
        pDispatcher->Execute_( *pShell, *pSlot, aReq, aReq.GetCallMode() | SfxCallMode::RECORD );
1041
0
    }
1042
0
    else
1043
0
        pDispatcher->Execute_( *pShell, *pSlot, aReq, aReq.GetCallMode() | SfxCallMode::RECORD );
1044
0
}
1045
1046
1047
void SfxBindings::UpdateSlotServer_Impl()
1048
0
{
1049
    // synchronize
1050
0
    pDispatcher->Flush();
1051
1052
0
    if ( pImpl->bAllMsgDirty )
1053
0
    {
1054
0
        if ( !nRegLevel )
1055
0
        {
1056
0
            pImpl->bContextChanged = false;
1057
0
        }
1058
0
        else
1059
0
            pImpl->bContextChanged = true;
1060
0
    }
1061
1062
0
    for (size_t i = 0; i < pImpl->pCaches.size(); ++i)
1063
0
    {
1064
        //GetSlotServer can modify pImpl->pCaches
1065
0
        pImpl->pCaches[i]->GetSlotServer(*pDispatcher, pImpl->xProv);
1066
0
    }
1067
0
    pImpl->bMsgDirty = pImpl->bAllMsgDirty = false;
1068
1069
0
    Broadcast( SfxHint(SfxHintId::DocChanged) );
1070
0
}
1071
1072
1073
std::optional<SfxItemSet> SfxBindings::CreateSet_Impl
1074
(
1075
    SfxStateCache&          rCache,     // in: Status-Cache from nId
1076
    const SfxSlot*&         pRealSlot,  // out: RealSlot to nId
1077
    const SfxSlotServer**   pMsgServer, // out: Slot-Server to nId
1078
    SfxFoundCacheArr_Impl&  rFound      // out: List of Caches for Siblings
1079
)
1080
0
{
1081
0
    DBG_ASSERT( !pImpl->bMsgDirty, "CreateSet_Impl with dirty MessageServer" );
1082
0
    assert(pDispatcher);
1083
1084
0
    const SfxSlotServer* pMsgSvr = rCache.GetSlotServer(*pDispatcher, pImpl->xProv);
1085
0
    if (!pMsgSvr)
1086
0
        return {};
1087
1088
0
    pRealSlot = nullptr;
1089
0
    *pMsgServer = pMsgSvr;
1090
1091
0
    sal_uInt16 nShellLevel = pMsgSvr->GetShellLevel();
1092
0
    SfxShell *pShell = pDispatcher->GetShell( nShellLevel );
1093
0
    if ( !pShell ) // rare GPF when browsing through update from Inet-Notify
1094
0
        return {};
1095
1096
0
    SfxItemPool &rPool = pShell->GetPool();
1097
1098
    // get the status method, which is served by the rCache
1099
0
    SfxStateFunc pFnc = nullptr;
1100
0
    pRealSlot = pMsgSvr->GetSlot();
1101
1102
0
    pFnc = pRealSlot->GetStateFnc();
1103
1104
    // the RealSlot is always on
1105
0
    SfxFoundCache_Impl aFound(pRealSlot->GetWhich(rPool), pRealSlot, rCache);
1106
0
    rFound.push_back( aFound );
1107
1108
    // Search through the bindings for slots served by the same function. This ,    // will only affect slots which are present in the found interface.
1109
1110
    // The position of the  Statecaches in StateCache-Array
1111
0
    std::size_t nCachePos = pImpl->nMsgPos;
1112
0
    const SfxSlot *pSibling = pRealSlot->GetNextSlot();
1113
1114
    // the Slots ODF and interfaces are linked in a circle
1115
0
    while ( pSibling > pRealSlot )
1116
0
    {
1117
0
        SfxStateFunc pSiblingFnc=nullptr;
1118
0
        SfxStateCache *pSiblingCache =
1119
0
                GetStateCache( pSibling->GetSlotId(), &nCachePos );
1120
1121
        // Is the slot cached ?
1122
0
        if ( pSiblingCache )
1123
0
        {
1124
0
            const SfxSlotServer *pServ = pSiblingCache->GetSlotServer(*pDispatcher, pImpl->xProv);
1125
0
            if ( pServ && pServ->GetShellLevel() == nShellLevel )
1126
0
                pSiblingFnc = pServ->GetSlot()->GetStateFnc();
1127
0
        }
1128
1129
        // Does the slot have to be updated at all?
1130
0
        bool bInsert = pSiblingCache && pSiblingCache->IsControllerDirty();
1131
1132
        // It is not enough to ask for the same shell!!
1133
0
        bool bSameMethod = pSiblingCache && pFnc == pSiblingFnc;
1134
1135
0
        if ( bInsert && bSameMethod )
1136
0
        {
1137
0
            SfxFoundCache_Impl aFoundCache(
1138
0
                pSibling->GetWhich(rPool),
1139
0
                pSibling, *pSiblingCache);
1140
1141
0
            rFound.push_back( aFoundCache );
1142
0
        }
1143
1144
0
        pSibling = pSibling->GetNextSlot();
1145
0
    }
1146
1147
    // Create a Set from the ranges
1148
0
    WhichRangesContainer ranges;
1149
0
    size_t i = 0;
1150
0
    while ( i < rFound.size() )
1151
0
    {
1152
0
        const sal_uInt16 nWhich1 = rFound[i].nWhichId;
1153
            // consecutive numbers
1154
0
        for ( ; i < rFound.size()-1; ++i )
1155
0
            if ( rFound[i].nWhichId+1 != rFound[i+1].nWhichId )
1156
0
                break;
1157
0
        const sal_uInt16 nWhich2 = rFound[i++].nWhichId;
1158
0
        ranges = ranges.MergeRange(nWhich1, nWhich2);
1159
0
    }
1160
0
    SfxItemSet aSet(rPool, std::move(ranges));
1161
0
    return aSet;
1162
0
}
1163
1164
1165
void SfxBindings::UpdateControllers_Impl
1166
(
1167
    const SfxFoundCache_Impl&   rFound, // Cache, Slot, Which etc.
1168
    const SfxPoolItem*          pItem,  // item to send to controller
1169
    SfxItemState                eState  // state of item
1170
)
1171
0
{
1172
0
    SfxStateCache& rCache = rFound.rCache;
1173
0
    const SfxSlot* pSlot = rFound.pSlot;
1174
0
    DBG_ASSERT( !pSlot || rCache.GetId() == pSlot->GetSlotId(), "SID mismatch" );
1175
1176
    // bound until now, the Controller to update the Slot.
1177
0
    if (!rCache.IsControllerDirty())
1178
0
        return;
1179
1180
0
    if ( SfxItemState::INVALID == eState )
1181
0
    {
1182
        // ambiguous
1183
0
        rCache.SetState( SfxItemState::INVALID, INVALID_POOL_ITEM );
1184
0
    }
1185
0
    else if ( SfxItemState::DEFAULT == eState &&
1186
0
              SfxItemPool::IsSlot(rFound.nWhichId) )
1187
0
    {
1188
        // no Status or Default but without Pool
1189
        // tdf#162666 note that use DISABLED_POOL_ITEM needs to be
1190
        // handled correctly in the cache, see comments there
1191
0
        rCache.SetState( SfxItemState::UNKNOWN, DISABLED_POOL_ITEM );
1192
0
    }
1193
0
    else if ( SfxItemState::DISABLED == eState )
1194
0
        rCache.SetState(SfxItemState::DISABLED, nullptr);
1195
0
    else
1196
0
        rCache.SetState(SfxItemState::DEFAULT, pItem);
1197
0
}
1198
1199
IMPL_LINK( SfxBindings, NextJob, Timer *, pTimer, void )
1200
0
{
1201
0
    SfxViewFrame* pFrame = pDispatcher ? pDispatcher->GetFrame() : nullptr;
1202
0
    SfxLokLanguageGuard aGuard(pFrame ? pFrame->GetViewShell() : nullptr);
1203
1204
0
    NextJob_Impl(pTimer);
1205
0
}
1206
1207
bool SfxBindings::NextJob_Impl(Timer const * pTimer)
1208
0
{
1209
0
    const unsigned MAX_INPUT_DELAY = 200;
1210
1211
0
    if ( Application::GetLastInputInterval() < MAX_INPUT_DELAY && pTimer )
1212
0
    {
1213
0
        pImpl->aAutoTimer.SetTimeout(TIMEOUT_UPDATING);
1214
0
        return true;
1215
0
    }
1216
1217
0
    SfxApplication *pSfxApp = SfxGetpApp();
1218
1219
0
    if( pDispatcher )
1220
0
        pDispatcher->Update_Impl();
1221
1222
    // modifying the SfxObjectInterface-stack without SfxBindings => nothing to do
1223
0
    SfxViewFrame* pFrame = pDispatcher ? pDispatcher->GetFrame() : nullptr;
1224
0
    if ( (pFrame && !pFrame->GetObjectShell()->AcceptStateUpdate()) || pSfxApp->IsDowning() || pImpl->pCaches.empty() )
1225
0
    {
1226
0
        return true;
1227
0
    }
1228
0
    if ( !pDispatcher || !pDispatcher->IsFlushed() )
1229
0
    {
1230
0
        return true;
1231
0
    }
1232
1233
    // if possible Update all server / happens in its own time slice
1234
0
    if ( pImpl->bMsgDirty )
1235
0
    {
1236
0
        UpdateSlotServer_Impl();
1237
0
        return false;
1238
0
    }
1239
1240
0
    pImpl->bAllDirty = false;
1241
0
    pImpl->aAutoTimer.SetTimeout(TIMEOUT_UPDATING);
1242
1243
    // at least 10 loops and further if more jobs are available but no input
1244
0
    bool bPreEmptive = pTimer;
1245
0
    sal_uInt16 nLoops = 10;
1246
0
    pImpl->bInNextJob = true;
1247
0
    const std::size_t nCount = pImpl->pCaches.size();
1248
0
    while ( pImpl->nMsgPos < nCount )
1249
0
    {
1250
        // iterate through the bound functions
1251
0
        bool bJobDone = false;
1252
0
        while ( !bJobDone )
1253
0
        {
1254
0
            SfxStateCache* pCache = pImpl->pCaches[pImpl->nMsgPos].get();
1255
0
            assert(pCache && "invalid SfxStateCache-position in job queue");
1256
0
            bool bWasDirty = pCache->IsControllerDirty();
1257
0
            if ( bWasDirty )
1258
0
            {
1259
0
                Update_Impl(*pCache);
1260
0
                DBG_ASSERT(nCount == pImpl->pCaches.size(), "Reschedule in StateChanged => buff");
1261
0
            }
1262
1263
            // skip to next function binding
1264
0
            ++pImpl->nMsgPos;
1265
1266
            // keep job if it is not completed, but any input is available
1267
0
            bJobDone = pImpl->nMsgPos >= nCount;
1268
0
            if ( bJobDone && pImpl->bFirstRound )
1269
0
            {
1270
1271
                // Update of the  preferred shell has been done, now may
1272
                // also the others shells be updated
1273
0
                bJobDone = false;
1274
0
                pImpl->bFirstRound = false;
1275
0
                pImpl->nMsgPos = 0;
1276
0
            }
1277
1278
0
            if ( bWasDirty && !bJobDone && bPreEmptive && (--nLoops == 0) )
1279
0
            {
1280
0
                pImpl->bInNextJob = false;
1281
0
                return false;
1282
0
            }
1283
0
        }
1284
0
    }
1285
1286
0
    pImpl->nMsgPos = 0;
1287
1288
0
    pImpl->aAutoTimer.Stop();
1289
1290
    // Update round is finished
1291
0
    pImpl->bInNextJob = false;
1292
0
    Broadcast(SfxHint(SfxHintId::UpdateDone));
1293
0
    return true;
1294
0
}
1295
1296
1297
sal_uInt16 SfxBindings::EnterRegistrations(std::string_view pFile, int nLine)
1298
159k
{
1299
159k
    SAL_INFO(
1300
159k
        "sfx.control",
1301
159k
        std::setw(std::min(nRegLevel, sal_uInt16(8))) << ' ' << "this = " << this
1302
159k
            << " Level = " << nRegLevel << " SfxBindings::EnterRegistrations "
1303
159k
            << (!pFile.empty()
1304
159k
                ? SAL_STREAM("File: " << pFile << " Line: " << nLine) : ""));
1305
1306
    // When bindings are locked, also lock sub bindings.
1307
159k
    if ( pImpl->pSubBindings )
1308
0
    {
1309
0
        pImpl->pSubBindings->ENTERREGISTRATIONS();
1310
1311
        // These EnterRegistrations are not "real" for the SubBindings
1312
0
        pImpl->pSubBindings->pImpl->nOwnRegLevel--;
1313
1314
        // Synchronize Bindings
1315
0
        pImpl->pSubBindings->nRegLevel = nRegLevel + pImpl->pSubBindings->pImpl->nOwnRegLevel + 1;
1316
0
    }
1317
1318
159k
    pImpl->nOwnRegLevel++;
1319
1320
    // check if this is the outer most level
1321
159k
    if ( ++nRegLevel == 1 )
1322
32.6k
    {
1323
        // stop background-processing
1324
32.6k
        pImpl->aAutoTimer.Stop();
1325
1326
        // flush the cache
1327
32.6k
        pImpl->nCachedFunc1 = 0;
1328
32.6k
        pImpl->nCachedFunc2 = 0;
1329
1330
        // Mark if the all of the Caches have disappeared.
1331
32.6k
        pImpl->bCtrlReleased = false;
1332
32.6k
    }
1333
1334
159k
    return nRegLevel;
1335
159k
}
1336
1337
1338
void SfxBindings::LeaveRegistrations(  std::string_view pFile, int nLine )
1339
151k
{
1340
151k
    DBG_ASSERT( nRegLevel, "Leave without Enter" );
1341
1342
    // Only when the SubBindings are still locked by the Superbindings,
1343
    // remove this lock (i.e. if there are more locks than "real" ones)
1344
151k
    if ( pImpl->pSubBindings && pImpl->pSubBindings->nRegLevel > pImpl->pSubBindings->pImpl->nOwnRegLevel )
1345
0
    {
1346
        // Synchronize Bindings
1347
0
        pImpl->pSubBindings->nRegLevel = nRegLevel + pImpl->pSubBindings->pImpl->nOwnRegLevel;
1348
1349
        // This LeaveRegistrations is not "real" for SubBindings
1350
0
        pImpl->pSubBindings->pImpl->nOwnRegLevel++;
1351
0
        pImpl->pSubBindings->LEAVEREGISTRATIONS();
1352
0
    }
1353
1354
151k
    pImpl->nOwnRegLevel--;
1355
1356
    // check if this is the outer most level
1357
151k
    if ( --nRegLevel == 0 && SfxGetpApp() && !SfxGetpApp()->IsDowning() )
1358
32.6k
    {
1359
32.6k
        if ( pImpl->bContextChanged )
1360
0
        {
1361
0
            pImpl->bContextChanged = false;
1362
0
        }
1363
1364
32.6k
        SfxViewFrame* pFrame = pDispatcher->GetFrame();
1365
1366
        // If possible remove unused Caches, for example prepare PlugInInfo
1367
32.6k
        if ( pImpl->bCtrlReleased )
1368
0
        {
1369
0
            for ( sal_uInt16 nCache = pImpl->pCaches.size(); nCache > 0; --nCache )
1370
0
            {
1371
                // Get Cache via css::sdbcx::Index
1372
0
                SfxStateCache *pCache = pImpl->pCaches[nCache-1].get();
1373
1374
                // No interested Controller present
1375
0
                if ( pCache->GetItemLink() == nullptr && !pCache->GetInternalController() )
1376
0
                {
1377
                    // Remove Cache. Safety: first remove and then delete
1378
0
                    pImpl->pCaches.erase(pImpl->pCaches.begin() + nCache - 1);
1379
0
                }
1380
0
            }
1381
0
        }
1382
1383
        // restart background-processing
1384
32.6k
        pImpl->nMsgPos = 0;
1385
32.6k
        if ( !pFrame || !pFrame->GetObjectShell() )
1386
4.08k
            return;
1387
28.5k
        if ( !pImpl->pCaches.empty() )
1388
24.4k
        {
1389
24.4k
            pImpl->aAutoTimer.Stop();
1390
24.4k
            pImpl->aAutoTimer.SetTimeout(TIMEOUT_FIRST);
1391
24.4k
            pImpl->aAutoTimer.Start();
1392
24.4k
        }
1393
28.5k
    }
1394
1395
146k
    SAL_INFO(
1396
146k
        "sfx.control",
1397
146k
        std::setw(std::min(nRegLevel, sal_uInt16(8))) << ' ' << "this = " << this
1398
146k
            << " Level = " << nRegLevel << " SfxBindings::LeaveRegistrations "
1399
146k
            << (!pFile.empty()
1400
146k
                ? SAL_STREAM("File: " << pFile << " Line: " << nLine) : ""));
1401
146k
}
1402
1403
1404
void SfxBindings::SetDispatcher( SfxDispatcher *pDisp )
1405
12.2k
{
1406
12.2k
    SfxDispatcher *pOldDispat = pDispatcher;
1407
12.2k
    if ( pDisp == pDispatcher )
1408
4.08k
        return;
1409
1410
8.16k
    if ( pOldDispat )
1411
4.08k
    {
1412
4.08k
        SfxBindings* pBind = pOldDispat->GetBindings();
1413
8.16k
        while ( pBind )
1414
4.08k
        {
1415
4.08k
            if ( pBind->pImpl->pSubBindings == this && pBind->pDispatcher != pDisp )
1416
0
                pBind->SetSubBindings_Impl( nullptr );
1417
4.08k
            pBind = pBind->pImpl->pSubBindings;
1418
4.08k
        }
1419
4.08k
    }
1420
1421
8.16k
    pDispatcher = pDisp;
1422
1423
8.16k
    css::uno::Reference < css::frame::XDispatchProvider > xProv;
1424
8.16k
    if ( pDisp )
1425
4.08k
        xProv.set( pDisp->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
1426
1427
8.16k
    SetDispatchProvider_Impl( xProv );
1428
8.16k
    InvalidateAll( true );
1429
1430
8.16k
    if ( pDispatcher && !pOldDispat )
1431
4.08k
    {
1432
4.08k
        if ( pImpl->pSubBindings && pImpl->pSubBindings->pDispatcher != pOldDispat )
1433
0
        {
1434
0
            OSL_FAIL( "SubBindings already set before activating!" );
1435
0
            pImpl->pSubBindings->ENTERREGISTRATIONS();
1436
0
        }
1437
4.08k
        LEAVEREGISTRATIONS();
1438
4.08k
    }
1439
4.08k
    else if( !pDispatcher )
1440
4.08k
    {
1441
4.08k
        ENTERREGISTRATIONS();
1442
4.08k
        if ( pImpl->pSubBindings && pImpl->pSubBindings->pDispatcher != pOldDispat )
1443
0
        {
1444
0
            OSL_FAIL( "SubBindings still set even when deactivating!" );
1445
0
            pImpl->pSubBindings->LEAVEREGISTRATIONS();
1446
0
        }
1447
4.08k
    }
1448
1449
8.16k
    Broadcast( SfxHint( SfxHintId::DataChanged ) );
1450
1451
8.16k
    if ( !pDisp )
1452
4.08k
        return;
1453
1454
4.08k
    SfxBindings* pBind = pDisp->GetBindings();
1455
4.08k
    while ( pBind && pBind != this )
1456
0
    {
1457
0
        if ( !pBind->pImpl->pSubBindings )
1458
0
        {
1459
0
            pBind->SetSubBindings_Impl( this );
1460
0
            break;
1461
0
        }
1462
1463
0
        pBind = pBind->pImpl->pSubBindings;
1464
0
    }
1465
4.08k
}
1466
1467
1468
void SfxBindings::ClearCache_Impl( sal_uInt16 nSlotId )
1469
0
{
1470
0
    SfxStateCache* pCache = GetStateCache(nSlotId);
1471
0
    if (!pCache)
1472
0
        return;
1473
0
    pCache->ClearCache();
1474
0
}
1475
1476
1477
void SfxBindings::StartUpdate_Impl( bool bComplete )
1478
0
{
1479
0
    if ( pImpl->pSubBindings )
1480
0
        pImpl->pSubBindings->StartUpdate_Impl( bComplete );
1481
1482
0
    if ( !bComplete )
1483
        // Update may be interrupted
1484
0
        NextJob_Impl(&pImpl->aAutoTimer);
1485
0
    else
1486
        // Update all slots in a row
1487
0
        NextJob_Impl(nullptr);
1488
0
}
1489
1490
1491
SfxItemState SfxBindings::QueryState( sal_uInt16 nSlot, std::unique_ptr<SfxPoolItem> &rpState )
1492
0
{
1493
0
    css::uno::Reference< css::frame::XDispatch >  xDisp;
1494
0
    SfxStateCache *pCache = GetStateCache( nSlot );
1495
0
    if ( pCache )
1496
0
        xDisp = pCache->GetDispatch();
1497
0
    if ( xDisp.is() || !pCache )
1498
0
    {
1499
0
        const SfxSlot* pSlot = SfxSlotPool::GetSlotPool( pDispatcher->GetFrame() ).GetSlot( nSlot );
1500
0
        if ( !pSlot || pSlot->aUnoName.isEmpty() )
1501
0
            return SfxItemState::DISABLED;
1502
1503
0
        css::util::URL aURL;
1504
0
        OUString aCmd( u".uno:"_ustr );
1505
0
        aURL.Protocol = aCmd;
1506
0
        aURL.Path = pSlot->GetUnoName();
1507
0
        aCmd += aURL.Path;
1508
0
        aURL.Complete = aCmd;
1509
0
        aURL.Main = aCmd;
1510
1511
0
        if ( !xDisp.is() )
1512
0
            xDisp = pImpl->xProv->queryDispatch( aURL, OUString(), 0 );
1513
1514
0
        if ( xDisp.is() )
1515
0
        {
1516
0
            if (!dynamic_cast<SfxOfficeDispatch*>(xDisp.get()))
1517
0
            {
1518
0
                bool bDeleteCache = false;
1519
0
                if ( !pCache )
1520
0
                {
1521
0
                    pCache = new SfxStateCache( nSlot );
1522
0
                    pCache->GetSlotServer( *GetDispatcher_Impl(), pImpl->xProv );
1523
0
                    bDeleteCache = true;
1524
0
                }
1525
1526
0
                SfxItemState eState = SfxItemState::SET;
1527
0
                rtl::Reference<BindDispatch_Impl> xBind(new BindDispatch_Impl( xDisp, aURL, pCache, pSlot ));
1528
0
                xDisp->addStatusListener( xBind, aURL );
1529
0
                if ( !xBind->GetStatus().IsEnabled )
1530
0
                {
1531
0
                    eState = SfxItemState::DISABLED;
1532
0
                }
1533
0
                else
1534
0
                {
1535
0
                    css::uno::Any aAny = xBind->GetStatus().State;
1536
0
                    const css::uno::Type& aType = aAny.getValueType();
1537
1538
0
                    if ( aType == cppu::UnoType<bool>::get() )
1539
0
                    {
1540
0
                        bool bTemp = false;
1541
0
                        aAny >>= bTemp ;
1542
0
                        rpState.reset(new SfxBoolItem( nSlot, bTemp ));
1543
0
                    }
1544
0
                    else if ( aType == ::cppu::UnoType< ::cppu::UnoUnsignedShortType >::get() )
1545
0
                    {
1546
0
                        sal_uInt16 nTemp = 0;
1547
0
                        aAny >>= nTemp ;
1548
0
                        rpState.reset(new SfxUInt16Item( nSlot, nTemp ));
1549
0
                    }
1550
0
                    else if ( aType == cppu::UnoType<sal_uInt32>::get() )
1551
0
                    {
1552
0
                        sal_uInt32 nTemp = 0;
1553
0
                        aAny >>= nTemp ;
1554
0
                        rpState.reset(new SfxUInt32Item( nSlot, nTemp ));
1555
0
                    }
1556
0
                    else if ( aType == cppu::UnoType<OUString>::get() )
1557
0
                    {
1558
0
                        OUString sTemp ;
1559
0
                        aAny >>= sTemp ;
1560
0
                        rpState.reset(new SfxStringItem( nSlot, sTemp ));
1561
0
                    }
1562
0
                    else
1563
0
                        rpState.reset(new SfxVoidItem( nSlot ));
1564
0
                }
1565
1566
0
                xDisp->removeStatusListener( xBind, aURL );
1567
0
                xBind->Release();
1568
0
                xBind.clear();
1569
0
                if ( bDeleteCache )
1570
0
                {
1571
0
                    delete pCache;
1572
0
                    pCache = nullptr;
1573
0
                }
1574
0
                return eState;
1575
0
            }
1576
0
        }
1577
0
    }
1578
1579
    // Then test at the dispatcher to check if the returned items from
1580
    // there are always DELETE_ON_IDLE, a copy of it has to be made in
1581
    // order to allow for transition of ownership.
1582
0
    SfxPoolItemHolder aResult;
1583
0
    const SfxItemState eState(pDispatcher->QueryState(nSlot, aResult));
1584
1585
0
    if (SfxItemState::SET == eState)
1586
0
    {
1587
0
        DBG_ASSERT( aResult.getItem(), "SfxItemState::SET but no item!" );
1588
0
        if (aResult)
1589
0
            rpState.reset(aResult.getItem()->Clone());
1590
0
    }
1591
0
    else if (SfxItemState::DEFAULT == eState && aResult)
1592
0
    {
1593
0
        rpState.reset(aResult.getItem()->Clone());
1594
0
    }
1595
1596
0
    return eState;
1597
0
}
1598
1599
void SfxBindings::QueryControlState( sal_uInt16 nSlot, boost::property_tree::ptree& rState )
1600
0
{
1601
0
    if ( SfxGetpApp()->IsDowning() )
1602
0
        return;
1603
1604
0
    if ( pDispatcher )
1605
0
        pDispatcher->Flush();
1606
1607
0
    if ( pImpl->pSubBindings )
1608
0
        pImpl->pSubBindings->QueryControlState( nSlot, rState );
1609
1610
0
    SfxStateCache* pCache = GetStateCache( nSlot );
1611
0
    if ( !pCache )
1612
0
        return;
1613
1614
0
    if ( pImpl->bMsgDirty )
1615
0
    {
1616
0
        UpdateSlotServer_Impl();
1617
0
        pCache = GetStateCache( nSlot );
1618
0
    }
1619
1620
0
    if (pCache && pCache->GetItemLink() )
1621
0
    {
1622
0
        pCache->GetState(rState);
1623
0
    }
1624
0
}
1625
1626
sal_uInt16 SfxBindings::QuerySlotId( const util::URL& aURL )
1627
0
{
1628
0
    if (!pImpl)
1629
0
        return 0;
1630
1631
0
    css::uno::Reference<css::frame::XDispatch> xDispatch =
1632
0
        pImpl->xProv->queryDispatch(aURL, OUString(), 0);
1633
0
    if (!xDispatch.is())
1634
0
        return 0;
1635
1636
0
    SfxOfficeDispatch* pDispatch = dynamic_cast<SfxOfficeDispatch*>(xDispatch.get());
1637
0
    if (!pDispatch)
1638
0
        return 0;
1639
1640
0
    return pDispatch->GetId();
1641
0
}
1642
1643
void SfxBindings::SetSubBindings_Impl( SfxBindings *pSub )
1644
0
{
1645
0
    if ( pImpl->pSubBindings )
1646
0
    {
1647
0
        pImpl->pSubBindings->SetDispatchProvider_Impl( css::uno::Reference< css::frame::XDispatchProvider > () );
1648
0
    }
1649
1650
0
    pImpl->pSubBindings = pSub;
1651
1652
0
    if ( pSub )
1653
0
    {
1654
0
        pImpl->pSubBindings->SetDispatchProvider_Impl( pImpl->xProv );
1655
0
    }
1656
0
}
1657
1658
SfxBindings* SfxBindings::GetSubBindings_Impl() const
1659
4.08k
{
1660
4.08k
    return pImpl->pSubBindings;
1661
4.08k
}
1662
1663
void SfxBindings::SetWorkWindow_Impl( std::unique_ptr<SfxWorkWindow> xWork )
1664
4.08k
{
1665
4.08k
    pImpl->mxWorkWin = std::move(xWork);
1666
4.08k
}
1667
1668
SfxWorkWindow* SfxBindings::GetWorkWindow_Impl() const
1669
0
{
1670
0
    return pImpl->mxWorkWin.get();
1671
0
}
1672
1673
bool SfxBindings::IsInUpdate() const
1674
10.8k
{
1675
10.8k
    bool bInUpdate = pImpl->bInUpdate;
1676
10.8k
    if ( !bInUpdate && pImpl->pSubBindings )
1677
0
        bInUpdate = pImpl->pSubBindings->IsInUpdate();
1678
10.8k
    return bInUpdate;
1679
10.8k
}
1680
1681
void SfxBindings::SetVisibleState( sal_uInt16 nId, bool bShow )
1682
0
{
1683
0
    SfxStateCache *pCache = GetStateCache( nId );
1684
0
    if ( pCache )
1685
0
        pCache->SetVisibleState( bShow );
1686
0
}
1687
1688
void SfxBindings::SetActiveFrame( const css::uno::Reference< css::frame::XFrame > & rFrame )
1689
8.16k
{
1690
8.16k
    if ( rFrame.is() || !pDispatcher )
1691
4.08k
        SetDispatchProvider_Impl( css::uno::Reference< css::frame::XDispatchProvider > ( rFrame, css::uno::UNO_QUERY ) );
1692
4.08k
    else
1693
4.08k
        SetDispatchProvider_Impl( css::uno::Reference< css::frame::XDispatchProvider > (
1694
4.08k
            pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), css::uno::UNO_QUERY ) );
1695
8.16k
}
1696
1697
css::uno::Reference< css::frame::XFrame > SfxBindings::GetActiveFrame() const
1698
8.16k
{
1699
8.16k
    const css::uno::Reference< css::frame::XFrame > xFrame( pImpl->xProv, css::uno::UNO_QUERY );
1700
8.16k
    if ( xFrame.is() || !pDispatcher )
1701
8.16k
        return xFrame;
1702
0
    else
1703
0
        return pDispatcher->GetFrame()->GetFrame().GetFrameInterface();
1704
8.16k
}
1705
1706
void SfxBindings::SetDispatchProvider_Impl( const css::uno::Reference< css::frame::XDispatchProvider > & rProv )
1707
16.3k
{
1708
16.3k
    bool bInvalidate = ( rProv != pImpl->xProv );
1709
16.3k
    if ( bInvalidate )
1710
8.16k
    {
1711
8.16k
        pImpl->xProv = rProv;
1712
8.16k
        InvalidateAll( true );
1713
8.16k
    }
1714
1715
16.3k
    if ( pImpl->pSubBindings )
1716
0
        pImpl->pSubBindings->SetDispatchProvider_Impl( pImpl->xProv );
1717
16.3k
}
1718
1719
const css::uno::Reference< css::frame::XDispatchRecorder >& SfxBindings::GetRecorder() const
1720
0
{
1721
0
    return pImpl->xRecorder;
1722
0
}
1723
1724
void SfxBindings::SetRecorder_Impl( css::uno::Reference< css::frame::XDispatchRecorder > const & rRecorder )
1725
4.08k
{
1726
4.08k
    pImpl->xRecorder = rRecorder;
1727
4.08k
}
1728
1729
void SfxBindings::ContextChanged_Impl()
1730
0
{
1731
0
    if ( !pImpl->bInUpdate && ( !pImpl->bContextChanged || !pImpl->bAllMsgDirty ) )
1732
0
    {
1733
0
        InvalidateAll( true );
1734
0
    }
1735
0
}
1736
1737
uno::Reference < frame::XDispatch > SfxBindings::GetDispatch( const SfxSlot* pSlot, const util::URL& aURL, bool bMasterCommand )
1738
0
{
1739
0
    uno::Reference < frame::XDispatch > xRet;
1740
0
    SfxStateCache* pCache = GetStateCache( pSlot->nSlotId );
1741
0
    if ( pCache && !bMasterCommand )
1742
0
        xRet = pCache->GetInternalDispatch();
1743
0
    if ( !xRet.is() )
1744
0
    {
1745
        // dispatches for slaves are unbound, they don't have a state
1746
0
        SfxOfficeDispatch* pDispatch = bMasterCommand ?
1747
0
            new SfxOfficeDispatch( pDispatcher, pSlot, aURL ) :
1748
0
            new SfxOfficeDispatch( *this, pDispatcher, pSlot, aURL );
1749
1750
0
        pDispatch->SetMasterUnoCommand( bMasterCommand );
1751
0
        xRet.set( pDispatch );
1752
0
        if ( !pCache )
1753
0
            pCache = GetStateCache( pSlot->nSlotId );
1754
1755
0
        DBG_ASSERT( bMasterCommand || pCache, "No cache for OfficeDispatch!" );
1756
0
        if ( pCache && !bMasterCommand )
1757
0
            pCache->SetInternalDispatch( xRet );
1758
0
    }
1759
1760
0
    return xRet;
1761
0
}
1762
1763
Timer& SfxBindings::GetTimer()
1764
0
{
1765
0
    return pImpl->aAutoTimer;
1766
0
}
1767
1768
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */