summaryrefslogtreecommitdiffstats
path: root/sfx2/source/control/shell.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sfx2/source/control/shell.cxx743
1 files changed, 743 insertions, 0 deletions
diff --git a/sfx2/source/control/shell.cxx b/sfx2/source/control/shell.cxx
new file mode 100644
index 000000000..ab3f7e869
--- /dev/null
+++ b/sfx2/source/control/shell.cxx
@@ -0,0 +1,743 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/embed/VerbDescriptor.hpp>
+#include <com/sun/star/embed/VerbAttributes.hpp>
+#include <officecfg/Office/Common.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <svl/itempool.hxx>
+#include <svl/setitem.hxx>
+#include <svl/undo.hxx>
+#include <itemdel.hxx>
+#include <svtools/asynclink.hxx>
+#include <unotools/configmgr.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/shell.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <statcach.hxx>
+#include <sidebar/ContextChangeBroadcaster.hxx>
+#include <com/sun/star/ui/dialogs/XSLTFilterDialog.hpp>
+#include <tools/debug.hxx>
+
+#include <memory>
+#include <vector>
+#include <map>
+
+#include <desktop/crashreport.hxx>
+
+using namespace com::sun::star;
+
+struct SfxShell_Impl: public SfxBroadcaster
+{
+ OUString aObjectName; // Name of Sbx-Objects
+ // Maps the Which() field to a pointer to a SfxPoolItem
+ std::map<sal_uInt16, std::unique_ptr<SfxPoolItem>>
+ m_Items; // Data exchange on Item level
+ SfxViewShell* pViewSh; // SfxViewShell if Shell is
+ // ViewFrame/ViewShell/SubShell list
+ SfxViewFrame* pFrame; // Frame, if <UI-active>
+ SfxRepeatTarget* pRepeatTarget; // SbxObjectRef xParent;
+ bool bActive;
+ SfxDisableFlags nDisableFlags;
+ std::unique_ptr<svtools::AsynchronLink> pExecuter;
+ std::unique_ptr<svtools::AsynchronLink> pUpdater;
+ std::vector<std::unique_ptr<SfxSlot> > aSlotArr;
+
+ css::uno::Sequence < css::embed::VerbDescriptor > aVerbList;
+ ::sfx2::sidebar::ContextChangeBroadcaster maContextChangeBroadcaster;
+
+ SfxShell_Impl()
+ : pViewSh(nullptr)
+ , pFrame(nullptr)
+ , pRepeatTarget(nullptr)
+ , bActive(false)
+ , nDisableFlags(SfxDisableFlags::NONE)
+ {
+ }
+
+ virtual ~SfxShell_Impl() override { pExecuter.reset(); pUpdater.reset();}
+};
+
+
+void SfxShell::EmptyExecStub(SfxShell *, SfxRequest &)
+{
+}
+
+void SfxShell::EmptyStateStub(SfxShell *, SfxItemSet &)
+{
+}
+
+SfxShell::SfxShell()
+: pImpl(new SfxShell_Impl),
+ pPool(nullptr),
+ pUndoMgr(nullptr)
+{
+}
+
+SfxShell::SfxShell( SfxViewShell *pViewSh )
+: pImpl(new SfxShell_Impl),
+ pPool(nullptr),
+ pUndoMgr(nullptr)
+{
+ pImpl->pViewSh = pViewSh;
+}
+
+SfxShell::~SfxShell()
+{
+}
+
+void SfxShell::SetName( const OUString &rName )
+{
+ pImpl->aObjectName = rName;
+}
+
+const OUString& SfxShell::GetName() const
+{
+ return pImpl->aObjectName;
+}
+
+SfxDispatcher* SfxShell::GetDispatcher() const
+{
+ return pImpl->pFrame ? pImpl->pFrame->GetDispatcher() : nullptr;
+}
+
+SfxViewShell* SfxShell::GetViewShell() const
+{
+ return pImpl->pViewSh;
+}
+
+SfxViewFrame* SfxShell::GetFrame() const
+{
+ if ( pImpl->pFrame )
+ return pImpl->pFrame;
+ if ( pImpl->pViewSh )
+ return pImpl->pViewSh->GetViewFrame();
+ return nullptr;
+}
+
+const SfxPoolItem* SfxShell::GetItem
+(
+ sal_uInt16 nSlotId // Slot-Id of the querying <SfxPoolItem>s
+) const
+{
+ auto const it = pImpl->m_Items.find( nSlotId );
+ if (it != pImpl->m_Items.end())
+ return it->second.get();
+ return nullptr;
+}
+
+void SfxShell::PutItem
+(
+ const SfxPoolItem& rItem /* Instance, of which a copy is created,
+ which is stored in the SfxShell in a list. */
+)
+{
+ DBG_ASSERT( dynamic_cast< const SfxSetItem* >( &rItem) == nullptr, "SetItems aren't allowed here" );
+ DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
+ "items with Which-Ids aren't allowed here" );
+
+ // MSC made a mess here of WNT/W95, beware of changes
+ SfxPoolItem *pItem = rItem.Clone();
+ SfxPoolItemHint aItemHint( pItem );
+ sal_uInt16 nWhich = rItem.Which();
+
+ auto const it = pImpl->m_Items.find(nWhich);
+ if (it != pImpl->m_Items.end())
+ {
+ // Replace Item
+ pImpl->m_Items.erase( it );
+ pImpl->m_Items.insert(std::make_pair(nWhich, std::unique_ptr<SfxPoolItem>(pItem)));
+
+ // if active, notify Bindings
+ SfxDispatcher *pDispat = GetDispatcher();
+ if ( pDispat )
+ {
+ SfxBindings* pBindings = pDispat->GetBindings();
+ pBindings->Broadcast( aItemHint );
+ sal_uInt16 nSlotId = nWhich; //pItem->GetSlotId();
+ SfxStateCache* pCache = pBindings->GetStateCache( nSlotId );
+ if ( pCache )
+ {
+ pCache->SetState( SfxItemState::DEFAULT, pItem, true );
+ pCache->SetCachedState( true );
+ }
+ }
+ return;
+ }
+ else
+ {
+ Broadcast( aItemHint );
+ pImpl->m_Items.insert(std::make_pair(nWhich, std::unique_ptr<SfxPoolItem>(pItem)));
+ }
+}
+
+SfxInterface* SfxShell::GetInterface() const
+{
+ return GetStaticInterface();
+}
+
+SfxUndoManager* SfxShell::GetUndoManager()
+{
+ return pUndoMgr;
+}
+
+void SfxShell::SetUndoManager( SfxUndoManager *pNewUndoMgr )
+{
+ OSL_ENSURE( ( pUndoMgr == nullptr ) || ( pNewUndoMgr == nullptr ) || ( pUndoMgr == pNewUndoMgr ),
+ "SfxShell::SetUndoManager: exchanging one non-NULL manager with another non-NULL manager? Suspicious!" );
+ // there's at least one client of our UndoManager - the DocumentUndoManager at the SfxBaseModel - which
+ // caches the UndoManager, and registers itself as listener. If exchanging non-NULL UndoManagers is really
+ // a supported scenario (/me thinks it is not), then we would need to notify all such clients instances.
+
+ pUndoMgr = pNewUndoMgr;
+ if (pUndoMgr && !utl::ConfigManager::IsFuzzing())
+ {
+ pUndoMgr->SetMaxUndoActionCount(
+ officecfg::Office::Common::Undo::Steps::get());
+ }
+}
+
+SfxRepeatTarget* SfxShell::GetRepeatTarget() const
+{
+ return pImpl->pRepeatTarget;
+}
+
+void SfxShell::SetRepeatTarget( SfxRepeatTarget *pTarget )
+{
+ pImpl->pRepeatTarget = pTarget;
+}
+
+void SfxShell::Invalidate
+(
+ sal_uInt16 nId /* Invalidated Slot-Id or Which-Id.
+ If these are 0 (default), then all
+ by this Shell currently handled Slot-Ids are
+ invalidated. */
+)
+{
+ if ( !GetViewShell() )
+ {
+ OSL_FAIL( "wrong Invalidate method called!" );
+ return;
+ }
+
+ Invalidate_Impl( GetViewShell()->GetViewFrame()->GetBindings(), nId );
+}
+
+void SfxShell::Invalidate_Impl( SfxBindings& rBindings, sal_uInt16 nId )
+{
+ if ( nId == 0 )
+ {
+ rBindings.InvalidateShell( *this );
+ }
+ else
+ {
+ const SfxInterface *pIF = GetInterface();
+ do
+ {
+ const SfxSlot *pSlot = pIF->GetSlot(nId);
+ if ( pSlot )
+ {
+ // Invalidate the Slot itself
+ rBindings.Invalidate( pSlot->GetSlotId() );
+ return;
+ }
+
+ pIF = pIF->GetGenoType();
+ }
+
+ while ( pIF );
+
+ SAL_INFO( "sfx.control", "W3: invalidating slot-id unknown in shell" );
+ }
+}
+
+void SfxShell::HandleOpenXmlFilterSettings(SfxRequest & rReq)
+{
+ try
+ {
+ uno::Reference < ui::dialogs::XExecutableDialog > xDialog = ui::dialogs::XSLTFilterDialog::create( ::comphelper::getProcessComponentContext() );
+ xDialog->execute();
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ rReq.Ignore ();
+}
+
+void SfxShell::DoActivate_Impl( SfxViewFrame *pFrame, bool bMDI )
+{
+ SfxObjectShell* pObjectShell = GetObjectShell();
+ if ( pObjectShell )
+ {
+ const OUString sActiveDocName = pObjectShell->GetTitle();
+ if( !pImpl->aObjectName.startsWith(sActiveDocName) )
+ {
+ CrashReporter::setActiveSfxObjectName(pImpl->aObjectName);
+ }
+ }
+ else
+ {
+ CrashReporter::setActiveSfxObjectName(pImpl->aObjectName);
+ }
+
+#ifdef DBG_UTIL
+ const SfxInterface *p_IF = GetInterface();
+ if ( !p_IF )
+ return;
+#endif
+ SAL_INFO(
+ "sfx.control",
+ "SfxShell::DoActivate() " << this << " " << GetInterface()->GetClassName()
+ << " bMDI " << (bMDI ? "MDI" : ""));
+
+ if ( bMDI )
+ {
+ // Remember Frame, in which it was activated
+ pImpl->pFrame = pFrame;
+ pImpl->bActive = true;
+ }
+
+ // Notify Subclass
+ Activate(bMDI);
+}
+
+void SfxShell::DoDeactivate_Impl( SfxViewFrame const *pFrame, bool bMDI )
+{
+#ifdef DBG_UTIL
+ const SfxInterface *p_IF = GetInterface();
+ if ( !p_IF )
+ return;
+#endif
+ SAL_INFO(
+ "sfx.control",
+ "SfxShell::DoDeactivate()" << this << " " << GetInterface()->GetClassName()
+ << " bMDI " << (bMDI ? "MDI" : ""));
+
+ // Only when it comes from a Frame
+ // (not when for instance by popping BASIC-IDE from AppDisp)
+ if ( bMDI && pImpl->pFrame == pFrame )
+ {
+ // deliver
+ pImpl->pFrame = nullptr;
+ pImpl->bActive = false;
+ }
+
+ // Notify Subclass
+ Deactivate(bMDI);
+}
+
+bool SfxShell::IsActive() const
+{
+ return pImpl->bActive;
+}
+
+void SfxShell::Activate
+(
+ bool /*bMDI*/ /* TRUE
+ the <SfxDispatcher>, on which the SfxShell is
+ located, is activated or the SfxShell instance
+ was pushed on an active SfxDispatcher.
+ (compare with SystemWindow::IsMDIActivate())
+
+ FALSE
+ the <SfxViewFrame>, on which SfxDispatcher
+ the SfxShell instance is located, was
+ activated. (for example by a closing dialog) */
+)
+{
+ BroadcastContextForActivation(true);
+}
+
+void SfxShell::Deactivate
+(
+ bool /*bMDI*/ /* TRUE
+ the <SfxDispatcher>, on which the SfxShell is
+ located, is inactivated or the SfxShell instance
+ was popped on an active SfxDispatcher.
+ (compare with SystemWindow::IsMDIActivate())
+
+ FALSE
+ the <SfxViewFrame>, on which SfxDispatcher
+ the SfxShell instance is located, was
+ deactivated. (for example by a dialog) */
+)
+{
+ BroadcastContextForActivation(false);
+}
+
+bool SfxShell::CanExecuteSlot_Impl( const SfxSlot &rSlot )
+{
+ // Get Slot status
+ SfxItemPool &rPool = GetPool();
+ const sal_uInt16 nId = rSlot.GetWhich( rPool );
+ SfxItemSet aSet(rPool, nId, nId);
+ SfxStateFunc pFunc = rSlot.GetStateFnc();
+ (*pFunc)( this, aSet );
+ return aSet.GetItemState(nId) != SfxItemState::DISABLED;
+}
+
+bool SfxShell::IsConditionalFastCall( const SfxRequest &rReq )
+{
+ sal_uInt16 nId = rReq.GetSlot();
+ bool bRet = false;
+
+ if (nId == SID_UNDO || nId == SID_REDO)
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if (pArgs && pArgs->HasItem(SID_REPAIRPACKAGE))
+ bRet = true;
+ }
+ return bRet;
+}
+
+
+static void ShellCall_Impl( void* pObj, void* pArg )
+{
+ static_cast<SfxShell*>(pObj)->ExecuteSlot( *static_cast<SfxRequest*>(pArg) );
+}
+
+void SfxShell::ExecuteSlot( SfxRequest& rReq, bool bAsync )
+{
+ if( !bAsync )
+ ExecuteSlot( rReq );
+ else
+ {
+ if( !pImpl->pExecuter )
+ pImpl->pExecuter.reset( new svtools::AsynchronLink(
+ Link<void*,void>( this, ShellCall_Impl ) ) );
+ pImpl->pExecuter->Call( new SfxRequest( rReq ) );
+ }
+}
+
+const SfxPoolItem* SfxShell::ExecuteSlot
+(
+ SfxRequest &rReq, // the relayed <SfxRequest>
+ const SfxInterface* pIF // default = 0 means get virtually
+)
+{
+ if ( !pIF )
+ pIF = GetInterface();
+
+ sal_uInt16 nSlot = rReq.GetSlot();
+ const SfxSlot* pSlot = nullptr;
+ if ( nSlot >= SID_VERB_START && nSlot <= SID_VERB_END )
+ pSlot = GetVerbSlot_Impl(nSlot);
+ if ( !pSlot )
+ pSlot = pIF->GetSlot(nSlot);
+ DBG_ASSERT( pSlot, "slot not supported" );
+
+ SfxExecFunc pFunc = pSlot->GetExecFnc();
+ if ( pFunc )
+ (*pFunc)( this, rReq );
+
+ return rReq.GetReturnValue();
+}
+
+const SfxPoolItem* SfxShell::GetSlotState
+(
+ sal_uInt16 nSlotId, // Slot-Id to the Slots in question
+ const SfxInterface* pIF, // default = 0 means get virtually
+ SfxItemSet* pStateSet // SfxItemSet of the Slot-State method
+)
+{
+ // Get Slot on the given Interface
+ if ( !pIF )
+ pIF = GetInterface();
+ SfxItemState eState(SfxItemState::DEFAULT);
+ bool bItemStateSet(false);
+ SfxItemPool &rPool = GetPool();
+
+ const SfxSlot* pSlot = nullptr;
+ if ( nSlotId >= SID_VERB_START && nSlotId <= SID_VERB_END )
+ pSlot = GetVerbSlot_Impl(nSlotId);
+ if ( !pSlot )
+ pSlot = pIF->GetSlot(nSlotId);
+ if ( pSlot )
+ // Map on Which-Id if possible
+ nSlotId = pSlot->GetWhich( rPool );
+
+ // Get Item and Item status
+ const SfxPoolItem *pItem = nullptr;
+ SfxItemSet aSet( rPool, nSlotId, nSlotId ); // else pItem dies too soon
+ if ( nullptr != pSlot )
+ {
+ // Call Status method
+ SfxStateFunc pFunc = pSlot->GetStateFnc();
+ if ( pFunc )
+ (*pFunc)( this, aSet );
+ eState = aSet.GetItemState( nSlotId, true, &pItem );
+ bItemStateSet = true;
+
+ // get default Item if possible
+ if ( eState == SfxItemState::DEFAULT )
+ {
+ if ( SfxItemPool::IsWhich(nSlotId) )
+ pItem = &rPool.GetDefaultItem(nSlotId);
+ else
+ eState = SfxItemState::DONTCARE;
+ }
+ }
+
+ // Evaluate Item and item status and possibly maintain them in pStateSet
+ std::unique_ptr<SfxPoolItem> pRetItem;
+ if ( !bItemStateSet || eState <= SfxItemState::DISABLED )
+ {
+ if ( pStateSet )
+ pStateSet->DisableItem(nSlotId);
+ return nullptr;
+ }
+ else if ( bItemStateSet && eState == SfxItemState::DONTCARE )
+ {
+ if ( pStateSet )
+ pStateSet->ClearItem(nSlotId);
+ pRetItem.reset( new SfxVoidItem(0) );
+ }
+ else // bItemStateSet && eState >= SfxItemState::DEFAULT
+ {
+ if ( pStateSet && pStateSet->Put( *pItem ) )
+ return &pStateSet->Get( pItem->Which() );
+ pRetItem.reset(pItem->Clone());
+ }
+ auto pTemp = pRetItem.get();
+ DeleteItemOnIdle(std::move(pRetItem));
+
+ return pTemp;
+}
+
+static SFX_EXEC_STUB(SfxShell, VerbExec)
+static void SfxStubSfxShellVerbState(SfxShell *, SfxItemSet& rSet)
+{
+ SfxShell::VerbState( rSet );
+}
+
+void SfxShell::SetVerbs(const css::uno::Sequence < css::embed::VerbDescriptor >& aVerbs)
+{
+ SfxViewShell *pViewSh = dynamic_cast<SfxViewShell*>( this );
+
+ DBG_ASSERT(pViewSh, "Only call SetVerbs at the ViewShell!");
+ if ( !pViewSh )
+ return;
+
+ // First make all Statecaches dirty, so that no-one no longer tries to use
+ // the Slots
+ {
+ SfxBindings *pBindings =
+ pViewSh->GetViewFrame()->GetDispatcher()->GetBindings();
+ sal_uInt16 nCount = pImpl->aSlotArr.size();
+ for (sal_uInt16 n1=0; n1<nCount ; n1++)
+ {
+ sal_uInt16 nId = SID_VERB_START + n1;
+ pBindings->Invalidate(nId, false, true);
+ }
+ }
+
+ sal_uInt16 nr=0;
+ for (sal_Int32 n=0; n<aVerbs.getLength(); n++)
+ {
+ sal_uInt16 nSlotId = SID_VERB_START + nr++;
+ DBG_ASSERT(nSlotId <= SID_VERB_END, "Too many Verbs!");
+ if (nSlotId > SID_VERB_END)
+ break;
+
+ SfxSlot *pNewSlot = new SfxSlot;
+ pNewSlot->nSlotId = nSlotId;
+ pNewSlot->nGroupId = SfxGroupId::NONE;
+
+ // Verb slots must be executed asynchronously, so that they can be
+ // destroyed while executing.
+ pNewSlot->nFlags = SfxSlotMode::ASYNCHRON | SfxSlotMode::CONTAINER;
+ pNewSlot->nMasterSlotId = 0;
+ pNewSlot->nValue = 0;
+ pNewSlot->fnExec = SFX_STUB_PTR(SfxShell,VerbExec);
+ pNewSlot->fnState = SFX_STUB_PTR(SfxShell,VerbState);
+ pNewSlot->pType = nullptr; // HACK(SFX_TYPE(SfxVoidItem)) ???
+ pNewSlot->nArgDefCount = 0;
+ pNewSlot->pFirstArgDef = nullptr;
+ pNewSlot->pUnoName = nullptr;
+
+ if (!pImpl->aSlotArr.empty())
+ {
+ SfxSlot& rSlot = *pImpl->aSlotArr[0];
+ pNewSlot->pNextSlot = rSlot.pNextSlot;
+ rSlot.pNextSlot = pNewSlot;
+ }
+ else
+ pNewSlot->pNextSlot = pNewSlot;
+
+ pImpl->aSlotArr.insert(pImpl->aSlotArr.begin() + static_cast<sal_uInt16>(n), std::unique_ptr<SfxSlot>(pNewSlot));
+ }
+
+ pImpl->aVerbList = aVerbs;
+
+ // The status of SID_OBJECT is collected in the controller directly on
+ // the Shell, it is thus enough to encourage a new status update
+ SfxBindings* pBindings = pViewSh->GetViewFrame()->GetDispatcher()->GetBindings();
+ pBindings->Invalidate(SID_OBJECT, true, true);
+}
+
+const css::uno::Sequence < css::embed::VerbDescriptor >& SfxShell::GetVerbs() const
+{
+ return pImpl->aVerbList;
+}
+
+void SfxShell::VerbExec(SfxRequest& rReq)
+{
+ sal_uInt16 nId = rReq.GetSlot();
+ SfxViewShell *pViewShell = GetViewShell();
+ if ( !pViewShell )
+ return;
+
+ bool bReadOnly = pViewShell->GetObjectShell()->IsReadOnly();
+ const css::uno::Sequence < css::embed::VerbDescriptor > aList = pViewShell->GetVerbs();
+ sal_Int32 nVerb = 0;
+ for (const auto& rVerb : aList)
+ {
+ // check for ReadOnly verbs
+ if ( bReadOnly && !(rVerb.VerbAttributes & embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES) )
+ continue;
+
+ // check for verbs that shouldn't appear in the menu
+ if ( !(rVerb.VerbAttributes & embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU) )
+ continue;
+
+ if (nId == SID_VERB_START + nVerb++)
+ {
+ pViewShell->DoVerb(rVerb.VerbID);
+ rReq.Done();
+ return;
+ }
+ }
+}
+
+void SfxShell::VerbState(SfxItemSet& )
+{
+}
+
+const SfxSlot* SfxShell::GetVerbSlot_Impl(sal_uInt16 nId) const
+{
+ css::uno::Sequence < css::embed::VerbDescriptor > rList = pImpl->aVerbList;
+
+ DBG_ASSERT(nId >= SID_VERB_START && nId <= SID_VERB_END,"Wrong VerbId!");
+ sal_uInt16 nIndex = nId - SID_VERB_START;
+ DBG_ASSERT(nIndex < rList.getLength(),"Wrong VerbId!");
+
+ if (nIndex < rList.getLength())
+ return pImpl->aSlotArr[nIndex].get();
+ else
+ return nullptr;
+}
+
+SfxObjectShell* SfxShell::GetObjectShell()
+{
+ if ( GetViewShell() )
+ return GetViewShell()->GetViewFrame()->GetObjectShell();
+ else
+ return nullptr;
+}
+
+bool SfxShell::HasUIFeature(SfxShellFeature) const
+{
+ return false;
+}
+
+static void DispatcherUpdate_Impl( void*, void* pArg )
+{
+ static_cast<SfxDispatcher*>(pArg)->Update_Impl( true );
+ static_cast<SfxDispatcher*>(pArg)->GetBindings()->InvalidateAll(false);
+}
+
+void SfxShell::UIFeatureChanged()
+{
+ SfxViewFrame *pFrame = GetFrame();
+ if ( pFrame && pFrame->IsVisible() )
+ {
+ // Also force an update, if dispatcher is already updated otherwise
+ // something my get stuck in the bunkered tools. Asynchronous call to
+ // prevent recursion.
+ if ( !pImpl->pUpdater )
+ pImpl->pUpdater.reset( new svtools::AsynchronLink( Link<void*,void>( this, DispatcherUpdate_Impl ) ) );
+
+ // Multiple views allowed
+ pImpl->pUpdater->Call( pFrame->GetDispatcher(), true );
+ }
+}
+
+void SfxShell::SetDisableFlags( SfxDisableFlags nFlags )
+{
+ pImpl->nDisableFlags = nFlags;
+}
+
+SfxDisableFlags SfxShell::GetDisableFlags() const
+{
+ return pImpl->nDisableFlags;
+}
+
+std::optional<SfxItemSet> SfxShell::CreateItemSet( sal_uInt16 )
+{
+ return {};
+}
+
+void SfxShell::ApplyItemSet( sal_uInt16, const SfxItemSet& )
+{
+}
+
+void SfxShell::SetContextName (const OUString& rsContextName)
+{
+ pImpl->maContextChangeBroadcaster.Initialize(rsContextName);
+}
+
+void SfxShell::SetViewShell_Impl( SfxViewShell* pView )
+{
+ pImpl->pViewSh = pView;
+}
+
+void SfxShell::BroadcastContextForActivation (const bool bIsActivated)
+{
+ // Avoids activation and de-activation (can be seen on switching view) from causing
+ // the sidebar to re-build. Such switching can happen as we change view to render
+ // using LOK for example, and is un-necessary for Online.
+ if (comphelper::LibreOfficeKit::isDialogPainting())
+ return;
+
+ SfxViewFrame* pViewFrame = GetFrame();
+ if (pViewFrame != nullptr)
+ {
+ if (bIsActivated)
+ pImpl->maContextChangeBroadcaster.Activate(pViewFrame->GetFrame().GetFrameInterface());
+ else
+ pImpl->maContextChangeBroadcaster.Deactivate(pViewFrame->GetFrame().GetFrameInterface());
+ }
+}
+
+bool SfxShell::SetContextBroadcasterEnabled (const bool bIsEnabled)
+{
+ return pImpl->maContextChangeBroadcaster.SetBroadcasterEnabled(bIsEnabled);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */