xref: /core/sfx2/source/control/shell.cxx (revision a3d89265)
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 <com/sun/star/embed/VerbDescriptor.hpp>
21 #include <com/sun/star/embed/VerbAttributes.hpp>
22 #include <officecfg/Office/Common.hxx>
23 #include <rtl/ustring.hxx>
24 #include <sal/log.hxx>
25 #include <osl/diagnose.h>
26 #include <svl/itempool.hxx>
27 #include <svl/undo.hxx>
28 #include <itemdel.hxx>
29 #include <svtools/asynclink.hxx>
30 #include <unotools/configmgr.hxx>
31 #include <comphelper/lok.hxx>
32 #include <sfx2/shell.hxx>
33 #include <sfx2/bindings.hxx>
34 #include <sfx2/dispatch.hxx>
35 #include <sfx2/viewfrm.hxx>
36 #include <sfx2/objface.hxx>
37 #include <sfx2/objsh.hxx>
38 #include <sfx2/viewsh.hxx>
39 #include <sfx2/request.hxx>
40 #include <sfx2/sfxsids.hrc>
41 #include <statcach.hxx>
42 #include <sidebar/ContextChangeBroadcaster.hxx>
43 #include <com/sun/star/ui/dialogs/XSLTFilterDialog.hpp>
44 #include <tools/debug.hxx>
45 
46 #include <memory>
47 #include <vector>
48 #include <map>
49 
50 #include <desktop/crashreport.hxx>
51 
52 using namespace com::sun::star;
53 
54 struct SfxShell_Impl: public SfxBroadcaster
55 {
56     OUString                    aObjectName;   // Name of Sbx-Objects
57     // Maps the Which() field to a pointer to a SfxPoolItem
58     std::map<sal_uInt16, std::unique_ptr<SfxPoolItem>>
59                                 m_Items;       // Data exchange on Item level
60     SfxViewShell*               pViewSh;       // SfxViewShell if Shell is
61                                                // ViewFrame/ViewShell/SubShell list
62     SfxViewFrame*               pFrame;        // Frame, if  <UI-active>
63     SfxRepeatTarget*            pRepeatTarget; // SbxObjectRef xParent;
64     bool                        bActive;
65     SfxDisableFlags             nDisableFlags;
66     std::unique_ptr<svtools::AsynchronLink> pExecuter;
67     std::unique_ptr<svtools::AsynchronLink> pUpdater;
68     std::vector<std::unique_ptr<SfxSlot> >  aSlotArr;
69 
70     css::uno::Sequence < css::embed::VerbDescriptor > aVerbList;
71     ::sfx2::sidebar::ContextChangeBroadcaster maContextChangeBroadcaster;
72 
73     SfxShell_Impl()
74         : pViewSh(nullptr)
75         , pFrame(nullptr)
76         , pRepeatTarget(nullptr)
77         , bActive(false)
78         , nDisableFlags(SfxDisableFlags::NONE)
79     {
80     }
81 
82     virtual ~SfxShell_Impl() override { pExecuter.reset(); pUpdater.reset();}
83 };
84 
85 
86 void SfxShell::EmptyExecStub(SfxShell *, SfxRequest &)
87 {
88 }
89 
90 void SfxShell::EmptyStateStub(SfxShell *, SfxItemSet &)
91 {
92 }
93 
94 SfxShell::SfxShell()
95 :   pImpl(new SfxShell_Impl),
96     pPool(nullptr),
97     pUndoMgr(nullptr)
98 {
99 }
100 
101 SfxShell::SfxShell( SfxViewShell *pViewSh )
102 :   pImpl(new SfxShell_Impl),
103     pPool(nullptr),
104     pUndoMgr(nullptr)
105 {
106     pImpl->pViewSh = pViewSh;
107 }
108 
109 SfxShell::~SfxShell()
110 {
111 }
112 
113 void SfxShell::SetName( const OUString &rName )
114 {
115     pImpl->aObjectName = rName;
116 }
117 
118 const OUString& SfxShell::GetName() const
119 {
120     return pImpl->aObjectName;
121 }
122 
123 SfxDispatcher* SfxShell::GetDispatcher() const
124 {
125     return pImpl->pFrame ? pImpl->pFrame->GetDispatcher() : nullptr;
126 }
127 
128 SfxViewShell* SfxShell::GetViewShell() const
129 {
130     return pImpl->pViewSh;
131 }
132 
133 SfxViewFrame* SfxShell::GetFrame() const
134 {
135     if ( pImpl->pFrame )
136         return pImpl->pFrame;
137     if ( pImpl->pViewSh )
138         return pImpl->pViewSh->GetViewFrame();
139     return nullptr;
140 }
141 
142 const SfxPoolItem* SfxShell::GetItem
143 (
144     sal_uInt16  nSlotId         // Slot-Id of the querying <SfxPoolItem>s
145 )   const
146 {
147     auto const it = pImpl->m_Items.find( nSlotId );
148     if (it != pImpl->m_Items.end())
149         return it->second.get();
150     return nullptr;
151 }
152 
153 void SfxShell::PutItem
154 (
155     const SfxPoolItem&  rItem  /* Instance, of which a copy is created,
156                                   which is stored in the SfxShell in a list. */
157 )
158 {
159     DBG_ASSERT( dynamic_cast< const SfxSetItem* >( &rItem) ==  nullptr, "SetItems aren't allowed here" );
160     DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
161                 "items with Which-Ids aren't allowed here" );
162 
163     // MSC made a mess here of WNT/W95, beware of changes
164     SfxPoolItem *pItem = rItem.Clone();
165     SfxPoolItemHint aItemHint( pItem );
166     sal_uInt16 nWhich = rItem.Which();
167 
168     auto const it = pImpl->m_Items.find(nWhich);
169     if (it != pImpl->m_Items.end())
170     {
171         // Replace Item
172         pImpl->m_Items.erase( it );
173         pImpl->m_Items.insert(std::make_pair(nWhich, std::unique_ptr<SfxPoolItem>(pItem)));
174 
175         // if active, notify Bindings
176         SfxDispatcher *pDispat = GetDispatcher();
177         if ( pDispat )
178         {
179             SfxBindings* pBindings = pDispat->GetBindings();
180             pBindings->Broadcast( aItemHint );
181             sal_uInt16 nSlotId = nWhich; //pItem->GetSlotId();
182             SfxStateCache* pCache = pBindings->GetStateCache( nSlotId );
183             if ( pCache )
184             {
185                 pCache->SetState( SfxItemState::DEFAULT, pItem, true );
186                 pCache->SetCachedState( true );
187             }
188         }
189         return;
190     }
191     else
192     {
193         Broadcast( aItemHint );
194         pImpl->m_Items.insert(std::make_pair(nWhich, std::unique_ptr<SfxPoolItem>(pItem)));
195     }
196 }
197 
198 SfxInterface* SfxShell::GetInterface() const
199 {
200     return GetStaticInterface();
201 }
202 
203 SfxUndoManager* SfxShell::GetUndoManager()
204 {
205     return pUndoMgr;
206 }
207 
208 void SfxShell::SetUndoManager( SfxUndoManager *pNewUndoMgr )
209 {
210     OSL_ENSURE( ( pUndoMgr == nullptr ) || ( pNewUndoMgr == nullptr ) || ( pUndoMgr == pNewUndoMgr ),
211         "SfxShell::SetUndoManager: exchanging one non-NULL manager with another non-NULL manager? Suspicious!" );
212     // there's at least one client of our UndoManager - the DocumentUndoManager at the SfxBaseModel - which
213     // caches the UndoManager, and registers itself as listener. If exchanging non-NULL UndoManagers is really
214     // a supported scenario (/me thinks it is not), then we would need to notify all such clients instances.
215 
216     pUndoMgr = pNewUndoMgr;
217     if (pUndoMgr && !utl::ConfigManager::IsFuzzing())
218     {
219         pUndoMgr->SetMaxUndoActionCount(
220             officecfg::Office::Common::Undo::Steps::get());
221     }
222 }
223 
224 SfxRepeatTarget* SfxShell::GetRepeatTarget() const
225 {
226     return pImpl->pRepeatTarget;
227 }
228 
229 void SfxShell::SetRepeatTarget( SfxRepeatTarget *pTarget )
230 {
231     pImpl->pRepeatTarget = pTarget;
232 }
233 
234 void SfxShell::Invalidate
235 (
236     sal_uInt16          nId     /* Invalidated Slot-Id or Which-Id.
237                                If these are 0 (default), then all
238                                by this Shell currently handled Slot-Ids are
239                                invalidated. */
240 )
241 {
242     if ( !GetViewShell() )
243     {
244         OSL_FAIL( "wrong Invalidate method called!" );
245         return;
246     }
247 
248     Invalidate_Impl( GetViewShell()->GetViewFrame()->GetBindings(), nId );
249 }
250 
251 void SfxShell::Invalidate_Impl( SfxBindings& rBindings, sal_uInt16 nId )
252 {
253     if ( nId == 0 )
254     {
255         rBindings.InvalidateShell( *this );
256     }
257     else
258     {
259         const SfxInterface *pIF = GetInterface();
260         do
261         {
262             const SfxSlot *pSlot = pIF->GetSlot(nId);
263             if ( pSlot )
264             {
265                 // Invalidate the Slot itself
266                 rBindings.Invalidate( pSlot->GetSlotId() );
267                 return;
268             }
269 
270             pIF = pIF->GetGenoType();
271         }
272 
273         while ( pIF );
274 
275         SAL_INFO( "sfx.control", "W3: invalidating slot-id unknown in shell" );
276     }
277 }
278 
279 void SfxShell::HandleOpenXmlFilterSettings(SfxRequest & rReq)
280 {
281     try
282     {
283         uno::Reference < ui::dialogs::XExecutableDialog > xDialog = ui::dialogs::XSLTFilterDialog::create( ::comphelper::getProcessComponentContext() );
284         xDialog->execute();
285     }
286     catch (const uno::Exception&)
287     {
288     }
289     rReq.Ignore ();
290 }
291 
292 void SfxShell::DoActivate_Impl( SfxViewFrame *pFrame, bool bMDI )
293 {
294     SfxObjectShell* pObjectShell = GetObjectShell();
295     if ( pObjectShell )
296     {
297         const OUString sActiveDocName = pObjectShell->GetTitle();
298         if( !pImpl->aObjectName.startsWith(sActiveDocName) )
299         {
300            CrashReporter::setActiveSfxObjectName(pImpl->aObjectName);
301         }
302     }
303     else
304     {
305         CrashReporter::setActiveSfxObjectName(pImpl->aObjectName);
306     }
307 
308 #ifdef DBG_UTIL
309     const SfxInterface *p_IF = GetInterface();
310     if ( !p_IF )
311         return;
312 #endif
313     SAL_INFO(
314         "sfx.control",
315         "SfxShell::DoActivate() " << this << "  " << GetInterface()->GetClassName()
316             << " bMDI " << (bMDI ? "MDI" : ""));
317 
318     if ( bMDI )
319     {
320         // Remember Frame, in which it was activated
321         pImpl->pFrame = pFrame;
322         pImpl->bActive = true;
323     }
324 
325     // Notify Subclass
326     Activate(bMDI);
327 }
328 
329 void SfxShell::DoDeactivate_Impl( SfxViewFrame const *pFrame, bool bMDI )
330 {
331 #ifdef DBG_UTIL
332     const SfxInterface *p_IF = GetInterface();
333     if ( !p_IF )
334         return;
335 #endif
336     SAL_INFO(
337         "sfx.control",
338         "SfxShell::DoDeactivate()" << this << "  " << GetInterface()->GetClassName()
339             << " bMDI " << (bMDI ? "MDI" : ""));
340 
341     // Only when it comes from a Frame
342     // (not when for instance by popping BASIC-IDE from AppDisp)
343     if ( bMDI && pImpl->pFrame == pFrame )
344     {
345         // deliver
346         pImpl->pFrame = nullptr;
347         pImpl->bActive = false;
348     }
349 
350     // Notify Subclass
351     Deactivate(bMDI);
352 }
353 
354 bool SfxShell::IsActive() const
355 {
356     return pImpl->bActive;
357 }
358 
359 void SfxShell::Activate
360 (
361     bool    /*bMDI*/        /*  TRUE
362                             the <SfxDispatcher>, on which the SfxShell is
363                             located, is activated or the SfxShell instance
364                             was pushed on an active SfxDispatcher.
365                             (compare with SystemWindow::IsMDIActivate())
366 
367                             FALSE
368                             the <SfxViewFrame>, on which SfxDispatcher
369                             the SfxShell instance is located, was
370                             activated. (for example by a closing dialog) */
371 )
372 {
373     BroadcastContextForActivation(true);
374 }
375 
376 void SfxShell::Deactivate
377 (
378     bool    /*bMDI*/        /*  TRUE
379                             the <SfxDispatcher>, on which the SfxShell is
380                             located, is inactivated or the SfxShell instance
381                             was popped on an active SfxDispatcher.
382                             (compare with SystemWindow::IsMDIActivate())
383 
384                             FALSE
385                             the <SfxViewFrame>, on which SfxDispatcher
386                             the SfxShell instance is located, was
387                             deactivated. (for example by a dialog) */
388 )
389 {
390     BroadcastContextForActivation(false);
391 }
392 
393 bool SfxShell::CanExecuteSlot_Impl( const SfxSlot &rSlot )
394 {
395     // Get Slot status
396     SfxItemPool &rPool = GetPool();
397     const sal_uInt16 nId = rSlot.GetWhich( rPool );
398     SfxItemSet aSet(rPool, {{nId, nId}});
399     SfxStateFunc pFunc = rSlot.GetStateFnc();
400     (*pFunc)( this, aSet );
401     return aSet.GetItemState(nId) != SfxItemState::DISABLED;
402 }
403 
404 bool SfxShell::IsConditionalFastCall( const SfxRequest &rReq )
405 {
406     sal_uInt16 nId = rReq.GetSlot();
407     bool bRet = false;
408 
409     if (nId == SID_UNDO || nId == SID_REDO)
410     {
411         const SfxItemSet* pArgs = rReq.GetArgs();
412         if (pArgs && pArgs->HasItem(SID_REPAIRPACKAGE))
413             bRet = true;
414     }
415     return bRet;
416 }
417 
418 
419 static void ShellCall_Impl( void* pObj, void* pArg )
420 {
421     static_cast<SfxShell*>(pObj)->ExecuteSlot( *static_cast<SfxRequest*>(pArg) );
422 }
423 
424 void SfxShell::ExecuteSlot( SfxRequest& rReq, bool bAsync )
425 {
426     if( !bAsync )
427         ExecuteSlot( rReq );
428     else
429     {
430         if( !pImpl->pExecuter )
431             pImpl->pExecuter.reset( new svtools::AsynchronLink(
432                 Link<void*,void>( this, ShellCall_Impl ) ) );
433         pImpl->pExecuter->Call( new SfxRequest( rReq ) );
434     }
435 }
436 
437 const SfxPoolItem* SfxShell::ExecuteSlot
438 (
439     SfxRequest          &rReq,  // the relayed <SfxRequest>
440     const SfxInterface* pIF     // default = 0 means get virtually
441 )
442 {
443     if ( !pIF )
444         pIF = GetInterface();
445 
446     sal_uInt16 nSlot = rReq.GetSlot();
447     const SfxSlot* pSlot = nullptr;
448     if ( nSlot >= SID_VERB_START && nSlot <= SID_VERB_END )
449         pSlot = GetVerbSlot_Impl(nSlot);
450     if ( !pSlot )
451         pSlot = pIF->GetSlot(nSlot);
452     DBG_ASSERT( pSlot, "slot not supported" );
453 
454     SfxExecFunc pFunc = pSlot->GetExecFnc();
455     if ( pFunc )
456         (*pFunc)( this, rReq );
457 
458     return rReq.GetReturnValue();
459 }
460 
461 const SfxPoolItem* SfxShell::GetSlotState
462 (
463     sal_uInt16              nSlotId,    // Slot-Id to the Slots in question
464     const SfxInterface* pIF,        // default = 0 means get virtually
465     SfxItemSet*         pStateSet   // SfxItemSet of the Slot-State method
466 )
467 {
468     // Get Slot on the given Interface
469     if ( !pIF )
470         pIF = GetInterface();
471     SfxItemState eState(SfxItemState::DEFAULT);
472     bool bItemStateSet(false);
473     SfxItemPool &rPool = GetPool();
474 
475     const SfxSlot* pSlot = nullptr;
476     if ( nSlotId >= SID_VERB_START && nSlotId <= SID_VERB_END )
477         pSlot = GetVerbSlot_Impl(nSlotId);
478     if ( !pSlot )
479         pSlot = pIF->GetSlot(nSlotId);
480     if ( pSlot )
481         // Map on Which-Id if possible
482         nSlotId = pSlot->GetWhich( rPool );
483 
484     // Get Item and Item status
485     const SfxPoolItem *pItem = nullptr;
486     SfxItemSet aSet( rPool, {{nSlotId, nSlotId}} ); // else pItem dies too soon
487     if ( nullptr != pSlot )
488     {
489         // Call Status method
490         SfxStateFunc pFunc = pSlot->GetStateFnc();
491         if ( pFunc )
492             (*pFunc)( this, aSet );
493         eState = aSet.GetItemState( nSlotId, true, &pItem );
494         bItemStateSet = true;
495 
496         // get default Item if possible
497         if ( eState == SfxItemState::DEFAULT )
498         {
499             if ( SfxItemPool::IsWhich(nSlotId) )
500                 pItem = &rPool.GetDefaultItem(nSlotId);
501             else
502                 eState = SfxItemState::DONTCARE;
503         }
504     }
505 
506     // Evaluate Item and item status and possibly maintain them in pStateSet
507     std::unique_ptr<SfxPoolItem> pRetItem;
508     if ( !bItemStateSet || eState <= SfxItemState::DISABLED )
509     {
510         if ( pStateSet )
511             pStateSet->DisableItem(nSlotId);
512         return nullptr;
513     }
514     else if ( bItemStateSet && eState == SfxItemState::DONTCARE )
515     {
516         if ( pStateSet )
517             pStateSet->ClearItem(nSlotId);
518         pRetItem.reset( new SfxVoidItem(0) );
519     }
520     else // bItemStateSet && eState >= SfxItemState::DEFAULT
521     {
522         if ( pStateSet && pStateSet->Put( *pItem ) )
523             return &pStateSet->Get( pItem->Which() );
524         pRetItem.reset(pItem->Clone());
525     }
526     auto pTemp = pRetItem.get();
527     DeleteItemOnIdle(std::move(pRetItem));
528 
529     return pTemp;
530 }
531 
532 static SFX_EXEC_STUB(SfxShell, VerbExec)
533 static void SfxStubSfxShellVerbState(SfxShell *, SfxItemSet& rSet)
534 {
535     SfxShell::VerbState( rSet );
536 }
537 
538 void SfxShell::SetVerbs(const css::uno::Sequence < css::embed::VerbDescriptor >& aVerbs)
539 {
540     SfxViewShell *pViewSh = dynamic_cast<SfxViewShell*>( this );
541 
542     DBG_ASSERT(pViewSh, "Only call SetVerbs at the ViewShell!");
543     if ( !pViewSh )
544         return;
545 
546     // First make all Statecaches dirty, so that no-one no longer tries to use
547     // the Slots
548     {
549         SfxBindings *pBindings =
550             pViewSh->GetViewFrame()->GetDispatcher()->GetBindings();
551         sal_uInt16 nCount = pImpl->aSlotArr.size();
552         for (sal_uInt16 n1=0; n1<nCount ; n1++)
553         {
554             sal_uInt16 nId = SID_VERB_START + n1;
555             pBindings->Invalidate(nId, false, true);
556         }
557     }
558 
559     sal_uInt16 nr=0;
560     for (sal_Int32 n=0; n<aVerbs.getLength(); n++)
561     {
562         sal_uInt16 nSlotId = SID_VERB_START + nr++;
563         DBG_ASSERT(nSlotId <= SID_VERB_END, "Too many Verbs!");
564         if (nSlotId > SID_VERB_END)
565             break;
566 
567         SfxSlot *pNewSlot = new SfxSlot;
568         pNewSlot->nSlotId = nSlotId;
569         pNewSlot->nGroupId = SfxGroupId::NONE;
570 
571         // Verb slots must be executed asynchronously, so that they can be
572         // destroyed while executing.
573         pNewSlot->nFlags = SfxSlotMode::ASYNCHRON | SfxSlotMode::CONTAINER;
574         pNewSlot->nMasterSlotId = 0;
575         pNewSlot->nValue = 0;
576         pNewSlot->fnExec = SFX_STUB_PTR(SfxShell,VerbExec);
577         pNewSlot->fnState = SFX_STUB_PTR(SfxShell,VerbState);
578         pNewSlot->pType = nullptr; // HACK(SFX_TYPE(SfxVoidItem)) ???
579         pNewSlot->nArgDefCount = 0;
580         pNewSlot->pFirstArgDef = nullptr;
581         pNewSlot->pUnoName = nullptr;
582 
583         if (!pImpl->aSlotArr.empty())
584         {
585             SfxSlot& rSlot = *pImpl->aSlotArr[0];
586             pNewSlot->pNextSlot = rSlot.pNextSlot;
587             rSlot.pNextSlot = pNewSlot;
588         }
589         else
590             pNewSlot->pNextSlot = pNewSlot;
591 
592         pImpl->aSlotArr.insert(pImpl->aSlotArr.begin() + static_cast<sal_uInt16>(n), std::unique_ptr<SfxSlot>(pNewSlot));
593     }
594 
595     pImpl->aVerbList = aVerbs;
596 
597     // The status of SID_OBJECT is collected in the controller directly on
598     // the Shell, it is thus enough to encourage a new status update
599     SfxBindings* pBindings = pViewSh->GetViewFrame()->GetDispatcher()->GetBindings();
600     pBindings->Invalidate(SID_OBJECT, true, true);
601 }
602 
603 const css::uno::Sequence < css::embed::VerbDescriptor >& SfxShell::GetVerbs() const
604 {
605     return pImpl->aVerbList;
606 }
607 
608 void SfxShell::VerbExec(SfxRequest& rReq)
609 {
610     sal_uInt16 nId = rReq.GetSlot();
611     SfxViewShell *pViewShell = GetViewShell();
612     if ( !pViewShell )
613         return;
614 
615     bool bReadOnly = pViewShell->GetObjectShell()->IsReadOnly();
616     const css::uno::Sequence < css::embed::VerbDescriptor > aList = pViewShell->GetVerbs();
617     sal_Int32 nVerb = 0;
618     for (const auto& rVerb : aList)
619     {
620         // check for ReadOnly verbs
621         if ( bReadOnly && !(rVerb.VerbAttributes & embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES) )
622             continue;
623 
624         // check for verbs that shouldn't appear in the menu
625         if ( !(rVerb.VerbAttributes & embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU) )
626             continue;
627 
628         if (nId == SID_VERB_START + nVerb++)
629         {
630             pViewShell->DoVerb(rVerb.VerbID);
631             rReq.Done();
632             return;
633         }
634     }
635 }
636 
637 void SfxShell::VerbState(SfxItemSet& )
638 {
639 }
640 
641 const SfxSlot* SfxShell::GetVerbSlot_Impl(sal_uInt16 nId) const
642 {
643     css::uno::Sequence < css::embed::VerbDescriptor > rList = pImpl->aVerbList;
644 
645     DBG_ASSERT(nId >= SID_VERB_START && nId <= SID_VERB_END,"Wrong VerbId!");
646     sal_uInt16 nIndex = nId - SID_VERB_START;
647     DBG_ASSERT(nIndex < rList.getLength(),"Wrong VerbId!");
648 
649     if (nIndex < rList.getLength())
650         return pImpl->aSlotArr[nIndex].get();
651     else
652         return nullptr;
653 }
654 
655 SfxObjectShell* SfxShell::GetObjectShell()
656 {
657     if ( GetViewShell() )
658         return GetViewShell()->GetViewFrame()->GetObjectShell();
659     else
660         return nullptr;
661 }
662 
663 bool SfxShell::HasUIFeature(SfxShellFeature) const
664 {
665     return false;
666 }
667 
668 static void DispatcherUpdate_Impl( void*, void* pArg )
669 {
670     static_cast<SfxDispatcher*>(pArg)->Update_Impl( true );
671     static_cast<SfxDispatcher*>(pArg)->GetBindings()->InvalidateAll(false);
672 }
673 
674 void SfxShell::UIFeatureChanged()
675 {
676     SfxViewFrame *pFrame = GetFrame();
677     if ( pFrame && pFrame->IsVisible() )
678     {
679         // Also force an update, if dispatcher is already updated otherwise
680         // something my get stuck in the bunkered tools. Asynchronous call to
681         // prevent recursion.
682         if ( !pImpl->pUpdater )
683             pImpl->pUpdater.reset( new svtools::AsynchronLink( Link<void*,void>( this, DispatcherUpdate_Impl ) ) );
684 
685         // Multiple views allowed
686         pImpl->pUpdater->Call( pFrame->GetDispatcher(), true );
687     }
688 }
689 
690 void SfxShell::SetDisableFlags( SfxDisableFlags nFlags )
691 {
692     pImpl->nDisableFlags = nFlags;
693 }
694 
695 SfxDisableFlags SfxShell::GetDisableFlags() const
696 {
697     return pImpl->nDisableFlags;
698 }
699 
700 std::unique_ptr<SfxItemSet> SfxShell::CreateItemSet( sal_uInt16 )
701 {
702     return nullptr;
703 }
704 
705 void SfxShell::ApplyItemSet( sal_uInt16, const SfxItemSet& )
706 {
707 }
708 
709 void SfxShell::SetContextName (const OUString& rsContextName)
710 {
711     pImpl->maContextChangeBroadcaster.Initialize(rsContextName);
712 }
713 
714 void SfxShell::SetViewShell_Impl( SfxViewShell* pView )
715 {
716     pImpl->pViewSh = pView;
717 }
718 
719 void SfxShell::BroadcastContextForActivation (const bool bIsActivated)
720 {
721     // Avoids activation and de-activation (can be seen on switching view) from causing
722     // the sidebar to re-build. Such switching can happen as we change view to render
723     // using LOK for example, and is un-necessary for Online.
724     if (comphelper::LibreOfficeKit::isDialogPainting())
725         return;
726 
727     SfxViewFrame* pViewFrame = GetFrame();
728     if (pViewFrame != nullptr)
729     {
730         if (bIsActivated)
731             pImpl->maContextChangeBroadcaster.Activate(pViewFrame->GetFrame().GetFrameInterface());
732         else
733             pImpl->maContextChangeBroadcaster.Deactivate(pViewFrame->GetFrame().GetFrameInterface());
734    }
735 }
736 
737 bool SfxShell::SetContextBroadcasterEnabled (const bool bIsEnabled)
738 {
739     return pImpl->maContextChangeBroadcaster.SetBroadcasterEnabled(bIsEnabled);
740 }
741 
742 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
743