forked from amazingfate/loongoffice
I checked if this is used, but it can be replaced using Clear() -> all. This prevents that the whole array of Items in an ItemSet gets set to INVALID_POOL_ITEM. I also checked if INVALID_POOL_ITEM/IsInvalidItem is needed at all representing SfxItemState::DONTCARE but it is and still will need to be set for individual Items. At last checked if SfxItemState::UNKNOWN and ::DISABLED really need to be separate states, but indeed there are some rare cases that need that. To make things more consistent I also renamed SfxItemState::DONTCARE to SfxItemState::INVALID to better match Set/IsInvalid calls at ItemSet. The build showed a missing UT and led to a problem due to the hand-made ItemSet-like SearchAttrItemList. The state 'invalid' seems to be used as 'unused' marker. It should be changed to use SfxPoolItemHolder and not need that. For now, set by using an own loop to set to that state. Change-Id: Ifc51aad60570569a1e37d3084a5e307eed47d06c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165035 Tested-by: Jenkins Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
735 lines
21 KiB
C++
735 lines
21 KiB
C++
/* -*- 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/voiditem.hxx>
|
|
#include <svl/undo.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( !rItem.isSetItem(), "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
|
|
it->second = 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 && !comphelper::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 SfxPoolItemHolder& 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();
|
|
}
|
|
|
|
SfxPoolItemHolder 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.GetUserOrPoolDefaultItem(nSlotId);
|
|
else
|
|
eState = SfxItemState::INVALID;
|
|
}
|
|
}
|
|
|
|
// Evaluate Item and item status and possibly maintain them in pStateSet
|
|
if ( !bItemStateSet || eState <= SfxItemState::DISABLED )
|
|
{
|
|
if ( pStateSet )
|
|
pStateSet->DisableItem(nSlotId);
|
|
return SfxPoolItemHolder();
|
|
}
|
|
|
|
if ( bItemStateSet && eState == SfxItemState::INVALID )
|
|
{
|
|
if ( pStateSet )
|
|
pStateSet->ClearItem(nSlotId);
|
|
return SfxPoolItemHolder(rPool, DISABLED_POOL_ITEM);
|
|
}
|
|
|
|
// bItemStateSet && eState >= SfxItemState::DEFAULT
|
|
if ( pStateSet && pStateSet->Put( *pItem ) )
|
|
{
|
|
return SfxPoolItemHolder(rPool, &pStateSet->Get(pItem->Which()));
|
|
}
|
|
|
|
return SfxPoolItemHolder(rPool, pItem);
|
|
}
|
|
|
|
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(
|
|
nSlotId, SfxGroupId::NONE,
|
|
// Verb slots must be executed asynchronously, so that they can be
|
|
// destroyed while executing.
|
|
SfxSlotMode::ASYNCHRON | SfxSlotMode::CONTAINER,
|
|
0, 0,
|
|
SFX_STUB_PTR(SfxShell, VerbExec), SFX_STUB_PTR(SfxShell, VerbState),
|
|
nullptr, // HACK(SFX_TYPE(SfxVoidItem)) ???
|
|
nullptr, nullptr, 0, SfxDisableFlags::NONE, "");
|
|
|
|
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 may 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: */
|