Coverage Report

Created: 2025-12-08 09:28

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