1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/embed/VerbDescriptor.hpp>
21 #include <com/sun/star/embed/VerbAttributes.hpp>
22 #include <basic/sbstar.hxx>
23 #include <officecfg/Office/Common.hxx>
24 #include <rtl/ustring.hxx>
25 #include <sal/log.hxx>
26 #include <svl/itempool.hxx>
27 #include <svl/undo.hxx>
28 #include "itemdel.hxx"
29 #include <svtools/asynclink.hxx>
30 #include <basic/sbx.hxx>
32 #include <sfx2/app.hxx>
33 #include <sfx2/shell.hxx>
34 #include <sfx2/bindings.hxx>
35 #include <sfx2/dispatch.hxx>
36 #include <sfx2/viewfrm.hxx>
37 #include <sfx2/objface.hxx>
38 #include <sfx2/objsh.hxx>
39 #include <sfx2/viewsh.hxx>
40 #include "sfxtypes.hxx"
41 #include <sfx2/request.hxx>
42 #include <sfx2/mnumgr.hxx>
43 #include "statcach.hxx"
44 #include <sfx2/msgpool.hxx>
45 #include <sidebar/ContextChangeBroadcaster.hxx>
46 #include <com/sun/star/ui/dialogs/XSLTFilterDialog.hpp>
48 #include <boost/ptr_container/ptr_map.hpp>
49 #include <boost/ptr_container/ptr_vector.hpp>
51 // Maps the Which() field to a pointer to a SfxPoolItem
52 typedef boost::ptr_map
<sal_uInt16
, SfxPoolItem
> SfxItemPtrMap
;
56 typedef boost::ptr_vector
<SfxSlot
> SfxVerbSlotArr_Impl
;
58 using namespace com::sun::star
;
60 struct SfxShell_Impl
: public SfxBroadcaster
62 OUString aObjectName
; // Name of Sbx-Objects
63 SfxItemPtrMap aItems
; // Data exchange on Item level
64 SfxViewShell
* pViewSh
; // SfxViewShell if Shell is
65 // ViewFrame/ViewShell/SubShell list
66 SfxViewFrame
* pFrame
; // Frame, if <UI-active>
67 SfxRepeatTarget
* pRepeatTarget
; // SbxObjectRef xParent;
69 sal_uIntPtr nDisableFlags
;
71 svtools::AsynchronLink
* pExecuter
;
72 svtools::AsynchronLink
* pUpdater
;
73 SfxVerbSlotArr_Impl aSlotArr
;
75 com::sun::star::uno::Sequence
< com::sun::star::embed::VerbDescriptor
> aVerbList
;
76 ::sfx2::sidebar::ContextChangeBroadcaster maContextChangeBroadcaster
;
90 virtual ~SfxShell_Impl() { delete pExecuter
; delete pUpdater
;}
94 void SfxShell::EmptyExecStub(SfxShell
*, SfxRequest
&)
98 void SfxShell::EmptyStateStub(SfxShell
*, SfxItemSet
&)
107 pImp
= new SfxShell_Impl
;
110 SfxShell::SfxShell( SfxViewShell
*pViewSh
)
115 pImp
= new SfxShell_Impl
;
116 pImp
->pViewSh
= pViewSh
;
119 SfxShell::~SfxShell()
124 void SfxShell::SetName( const OUString
&rName
)
126 pImp
->aObjectName
= rName
;
129 const OUString
& SfxShell::GetName() const
131 return pImp
->aObjectName
;
134 SfxDispatcher
* SfxShell::GetDispatcher() const
136 return pImp
->pFrame
? pImp
->pFrame
->GetDispatcher() : 0;
139 SfxViewShell
* SfxShell::GetViewShell() const
141 return pImp
->pViewSh
;
144 SfxViewFrame
* SfxShell::GetFrame() const
149 return pImp
->pViewSh
->GetViewFrame();
153 const SfxPoolItem
* SfxShell::GetItem
155 sal_uInt16 nSlotId
// Slot-Id of the querying <SfxPoolItem>s
158 SfxItemPtrMap::const_iterator it
= pImp
->aItems
.find( nSlotId
);
159 if( it
!= pImp
->aItems
.end() )
164 void SfxShell::PutItem
166 const SfxPoolItem
& rItem
/* Instance, of which a copy is created,
167 which is stored in the SfxShell in a list. */
170 DBG_ASSERT( !rItem
.ISA(SfxSetItem
), "SetItems aren't allowed here" );
171 DBG_ASSERT( SfxItemPool::IsSlot( rItem
.Which() ),
172 "items with Which-Ids aren't allowed here" );
174 // MSC made a mess here of WNT/W95, beware of changes
175 SfxPoolItem
*pItem
= rItem
.Clone();
176 SfxPoolItemHint
aItemHint( pItem
);
177 sal_uInt16 nWhich
= rItem
.Which();
179 SfxItemPtrMap::iterator it
= pImp
->aItems
.find( nWhich
);
180 if( it
!= pImp
->aItems
.end() )
183 pImp
->aItems
.erase( it
);
184 pImp
->aItems
.insert( nWhich
, pItem
);
186 // if active, notify Bindings
187 SfxDispatcher
*pDispat
= GetDispatcher();
190 SfxBindings
* pBindings
= pDispat
->GetBindings();
191 pBindings
->Broadcast( aItemHint
);
192 sal_uInt16 nSlotId
= nWhich
; //pItem->GetSlotId();
193 SfxStateCache
* pCache
= pBindings
->GetStateCache( nSlotId
);
196 pCache
->SetState( SfxItemState::DEFAULT
, pItem
, true );
197 pCache
->SetCachedState( true );
204 Broadcast( aItemHint
);
205 pImp
->aItems
.insert( nWhich
, pItem
);
209 SfxInterface
* SfxShell::GetInterface() const
211 return GetStaticInterface();
214 ::svl::IUndoManager
* SfxShell::GetUndoManager()
219 void SfxShell::SetUndoManager( ::svl::IUndoManager
*pNewUndoMgr
)
221 OSL_ENSURE( ( pUndoMgr
== NULL
) || ( pNewUndoMgr
== NULL
) || ( pUndoMgr
== pNewUndoMgr
),
222 "SfxShell::SetUndoManager: exchanging one non-NULL manager with another non-NULL manager? Suspicious!" );
223 // there's at least one client of our UndoManager - the DocumentUndoManager at the SfxBaseModel - which
224 // caches the UndoManager, and registers itself as listener. If exchanging non-NULL UndoManagers is really
225 // a supported scenario (/me thinks it is not), then we would need to notify all such clients instances.
227 pUndoMgr
= pNewUndoMgr
;
229 pUndoMgr
->SetMaxUndoActionCount(
230 officecfg::Office::Common::Undo::Steps::get());
233 SfxRepeatTarget
* SfxShell::GetRepeatTarget() const
235 return pImp
->pRepeatTarget
;
238 void SfxShell::SetRepeatTarget( SfxRepeatTarget
*pTarget
)
240 pImp
->pRepeatTarget
= pTarget
;
243 void SfxShell::Invalidate
245 sal_uInt16 nId
/* Invalidated Slot-Id or Which-Id.
246 If these are 0 (default), then all
247 by this Shell currently handled Slot-Ids are
251 if ( !GetViewShell() )
253 OSL_FAIL( "wrong Invalidate method called!" );
257 Invalidate_Impl( GetViewShell()->GetViewFrame()->GetBindings(), nId
);
260 void SfxShell::Invalidate_Impl( SfxBindings
& rBindings
, sal_uInt16 nId
)
264 rBindings
.InvalidateShell( *this, false );
268 const SfxInterface
*pIF
= GetInterface();
271 const SfxSlot
*pSlot
= pIF
->GetSlot(nId
);
274 // At Enum-Slots invalidate the Master-Slot
275 if ( SFX_KIND_ENUM
== pSlot
->GetKind() )
276 pSlot
= pSlot
->GetLinkedSlot();
278 // Invalidate the Slot itself and possible also all Slave-Slots
279 rBindings
.Invalidate( pSlot
->GetSlotId() );
280 for ( const SfxSlot
*pSlave
= pSlot
->GetLinkedSlot();
281 pSlave
&& pIF
->ContainsSlot_Impl( pSlave
) &&
282 pSlave
->GetLinkedSlot() == pSlot
;
284 rBindings
.Invalidate( pSlave
->GetSlotId() );
289 pIF
= pIF
->GetGenoType();
294 DBG_WARNING( "W3: invalidating slot-id unknown in shell" );
298 void SfxShell::HandleOpenXmlFilterSettings(SfxRequest
& rReq
)
302 uno::Reference
< ui::dialogs::XExecutableDialog
> xDialog
= ui::dialogs::XSLTFilterDialog::create( ::comphelper::getProcessComponentContext() );
305 catch (const uno::Exception
&)
311 void SfxShell::DoActivate_Impl( SfxViewFrame
*pFrame
, bool bMDI
)
314 const SfxInterface
*p_IF
= GetInterface();
320 "SfxShell::DoActivate() " << this << " " << GetInterface()->GetClassName()
321 << " bMDI " << (bMDI
? "MDI" : ""));
325 // Remember Frame, in which it was activated
326 pImp
->pFrame
= pFrame
;
327 pImp
->bActive
= true;
334 void SfxShell::DoDeactivate_Impl( SfxViewFrame
*pFrame
, bool bMDI
)
337 const SfxInterface
*p_IF
= GetInterface();
343 "SfxShell::DoDeactivate()" << this << " " << GetInterface()->GetClassName()
344 << " bMDI " << (bMDI
? "MDI" : ""));
346 // Only when it comes from a Frame
347 // (not when for instance by poping BASIC-IDE from AppDisp)
348 if ( bMDI
&& pImp
->pFrame
== pFrame
)
352 pImp
->bActive
= false;
359 bool SfxShell::IsActive() const
361 return pImp
->bActive
;
364 void SfxShell::Activate
366 bool /*bMDI*/ /* TRUE
367 the <SfxDispatcher>, on which the SfxShell is
368 located, is activated or the SfxShell instance
369 was pushed on an active SfxDispatcher.
370 (compare with SystemWindow::IsMDIActivate())
373 the <SfxViewFrame>, on which SfxDispatcher
374 the SfxShell instance is located, was
375 activated. (for example by a closing dialoge) */
378 BroadcastContextForActivation(true);
381 void SfxShell::Deactivate
383 bool /*bMDI*/ /* TRUE
384 the <SfxDispatcher>, on which the SfxShell is
385 located, is inactivated or the SfxShell instance
386 was popped on an active SfxDispatcher.
387 (compare with SystemWindow::IsMDIActivate())
390 the <SfxViewFrame>, on which SfxDispatcher
391 the SfxShell instance is located, was
392 deactivated. (for example by a dialoge) */
395 BroadcastContextForActivation(false);
398 bool SfxShell::CanExecuteSlot_Impl( const SfxSlot
&rSlot
)
401 SfxItemPool
&rPool
= GetPool();
402 const sal_uInt16 nId
= rSlot
.GetWhich( rPool
);
403 SfxItemSet
aSet(rPool
, nId
, nId
);
404 SfxStateFunc pFunc
= rSlot
.GetStateFnc();
405 CallState( pFunc
, aSet
);
406 return aSet
.GetItemState(nId
) != SfxItemState::DISABLED
;
409 sal_IntPtr
ShellCall_Impl( void* pObj
, void* pArg
)
411 static_cast<SfxShell
*>(pObj
)->ExecuteSlot( *static_cast<SfxRequest
*>(pArg
), (SfxInterface
*)0L );
415 const SfxPoolItem
* SfxShell::ExecuteSlot( SfxRequest
& rReq
, bool bAsync
)
418 return ExecuteSlot( rReq
, (SfxInterface
*)0L );
421 if( !pImp
->pExecuter
)
422 pImp
->pExecuter
= new svtools::AsynchronLink(
423 Link
<>( this, ShellCall_Impl
) );
424 pImp
->pExecuter
->Call( new SfxRequest( rReq
) );
429 const SfxPoolItem
* SfxShell::ExecuteSlot
431 SfxRequest
&rReq
, // the relayed <SfxRequest>
432 const SfxInterface
* pIF
// default = 0 means get virtually
436 pIF
= GetInterface();
438 sal_uInt16 nSlot
= rReq
.GetSlot();
439 const SfxSlot
* pSlot
= NULL
;
440 if ( nSlot
>= SID_VERB_START
&& nSlot
<= SID_VERB_END
)
441 pSlot
= GetVerbSlot_Impl(nSlot
);
443 pSlot
= pIF
->GetSlot(nSlot
);
444 DBG_ASSERT( pSlot
, "slot not supported" );
446 SfxExecFunc pFunc
= pSlot
->GetExecFnc();
448 CallExec( pFunc
, rReq
);
450 return rReq
.GetReturnValue();
453 const SfxPoolItem
* SfxShell::GetSlotState
455 sal_uInt16 nSlotId
, // Slot-Id to the Slots in question
456 const SfxInterface
* pIF
, // default = 0 means get virtually
457 SfxItemSet
* pStateSet
// SfxItemSet of the Slot-State method
460 // Get Slot on the given Interface
462 pIF
= GetInterface();
463 SfxItemState eState
= SfxItemState::UNKNOWN
;
464 SfxItemPool
&rPool
= GetPool();
466 const SfxSlot
* pSlot
= NULL
;
467 if ( nSlotId
>= SID_VERB_START
&& nSlotId
<= SID_VERB_END
)
468 pSlot
= GetVerbSlot_Impl(nSlotId
);
470 pSlot
= pIF
->GetSlot(nSlotId
);
472 // Map on Which-Id if possible
473 nSlotId
= pSlot
->GetWhich( rPool
);
475 // Get Item and Item status
476 const SfxPoolItem
*pItem
= NULL
;
477 SfxItemSet
aSet( rPool
, nSlotId
, nSlotId
); // else pItem dies too soon
480 // Call Status method
481 SfxStateFunc pFunc
= pSlot
->GetStateFnc();
483 CallState( pFunc
, aSet
);
484 eState
= aSet
.GetItemState( nSlotId
, true, &pItem
);
486 // get default Item if possible
487 if ( eState
== SfxItemState::DEFAULT
)
489 if ( SfxItemPool::IsWhich(nSlotId
) )
490 pItem
= &rPool
.GetDefaultItem(nSlotId
);
492 eState
= SfxItemState::DONTCARE
;
496 eState
= SfxItemState::UNKNOWN
;
498 // Evaluate Item and item status and possibly maintain them in pStateSet
499 SfxPoolItem
*pRetItem
= 0;
500 if ( eState
<= SfxItemState::DISABLED
)
503 pStateSet
->DisableItem(nSlotId
);
506 else if ( eState
== SfxItemState::DONTCARE
)
509 pStateSet
->ClearItem(nSlotId
);
510 pRetItem
= new SfxVoidItem(0);
514 if ( pStateSet
&& pStateSet
->Put( *pItem
) )
515 return &pStateSet
->Get( pItem
->Which() );
516 pRetItem
= pItem
->Clone();
518 DeleteItemOnIdle(pRetItem
);
523 SFX_EXEC_STUB(SfxShell
, VerbExec
)
524 void SfxStubSfxShellVerbState(SfxShell
*, SfxItemSet
& rSet
)
526 SfxShell::VerbState( rSet
);
529 void SfxShell::SetVerbs(const com::sun::star::uno::Sequence
< com::sun::star::embed::VerbDescriptor
>& aVerbs
)
531 SfxViewShell
*pViewSh
= PTR_CAST ( SfxViewShell
, this);
533 DBG_ASSERT(pViewSh
, "Only call SetVerbs at the ViewShell!");
537 // First make all Statecaches dirty, so that no-one no longer tries to use
540 SfxBindings
*pBindings
=
541 pViewSh
->GetViewFrame()->GetDispatcher()->GetBindings();
542 sal_uInt16 nCount
= pImp
->aSlotArr
.size();
543 for (sal_uInt16 n1
=0; n1
<nCount
; n1
++)
545 sal_uInt16 nId
= SID_VERB_START
+ n1
;
546 pBindings
->Invalidate(nId
, false, true);
551 for (sal_Int32 n
=0; n
<aVerbs
.getLength(); n
++)
553 sal_uInt16 nSlotId
= SID_VERB_START
+ nr
++;
554 DBG_ASSERT(nSlotId
<= SID_VERB_END
, "To many Verbs!");
555 if (nSlotId
> SID_VERB_END
)
558 SfxSlot
*pNewSlot
= new SfxSlot
;
559 pNewSlot
->nSlotId
= nSlotId
;
560 pNewSlot
->nGroupId
= 0;
562 // Verb slots must be executed asynchronously, so that they can be
563 // destroyed while executing.
564 pNewSlot
->nFlags
= SfxSlotMode::ASYNCHRON
| SfxSlotMode::CONTAINER
;
565 pNewSlot
->nMasterSlotId
= 0;
566 pNewSlot
->nValue
= 0;
567 pNewSlot
->fnExec
= SFX_STUB_PTR(SfxShell
,VerbExec
);
568 pNewSlot
->fnState
= SFX_STUB_PTR(SfxShell
,VerbState
);
569 pNewSlot
->pType
= 0; // HACK(SFX_TYPE(SfxVoidItem)) ???
570 pNewSlot
->pLinkedSlot
= 0;
571 pNewSlot
->nArgDefCount
= 0;
572 pNewSlot
->pFirstArgDef
= 0;
573 pNewSlot
->pUnoName
= 0;
575 if (!pImp
->aSlotArr
.empty())
577 SfxSlot
& rSlot
= pImp
->aSlotArr
[0];
578 pNewSlot
->pNextSlot
= rSlot
.pNextSlot
;
579 rSlot
.pNextSlot
= pNewSlot
;
582 pNewSlot
->pNextSlot
= pNewSlot
;
584 pImp
->aSlotArr
.insert(pImp
->aSlotArr
.begin() + (sal_uInt16
) n
, pNewSlot
);
587 pImp
->aVerbList
= aVerbs
;
591 // The status of SID_OBJECT is collected in the controller directly on
592 // the Shell, it is thus enough to encourage a new status update
593 SfxBindings
*pBindings
= pViewSh
->GetViewFrame()->GetDispatcher()->
595 pBindings
->Invalidate( SID_OBJECT
, true, true );
599 const com::sun::star::uno::Sequence
< com::sun::star::embed::VerbDescriptor
>& SfxShell::GetVerbs() const
601 return pImp
->aVerbList
;
604 void SfxShell::VerbExec(SfxRequest
& rReq
)
606 sal_uInt16 nId
= rReq
.GetSlot();
607 SfxViewShell
*pViewShell
= GetViewShell();
610 bool bReadOnly
= pViewShell
->GetObjectShell()->IsReadOnly();
611 com::sun::star::uno::Sequence
< com::sun::star::embed::VerbDescriptor
> aList
= pViewShell
->GetVerbs();
612 for (sal_Int32 n
=0, nVerb
=0; n
<aList
.getLength(); n
++)
614 // check for ReadOnly verbs
615 if ( bReadOnly
&& !(aList
[n
].VerbAttributes
& embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES
) )
618 // check for verbs that shouldn't appear in the menu
619 if ( !(aList
[n
].VerbAttributes
& embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU
) )
622 if (nId
== SID_VERB_START
+ nVerb
++)
624 pViewShell
->DoVerb(aList
[n
].VerbID
);
632 void SfxShell::VerbState(SfxItemSet
& )
636 const SfxSlot
* SfxShell::GetVerbSlot_Impl(sal_uInt16 nId
) const
638 com::sun::star::uno::Sequence
< com::sun::star::embed::VerbDescriptor
> rList
= pImp
->aVerbList
;
640 DBG_ASSERT(nId
>= SID_VERB_START
&& nId
<= SID_VERB_END
,"Wrong VerbId!");
641 sal_uInt16 nIndex
= nId
- SID_VERB_START
;
642 DBG_ASSERT(nIndex
< rList
.getLength(),"Wrong VerbId!");
644 if (nIndex
< rList
.getLength())
645 return &pImp
->aSlotArr
[nIndex
];
650 void SfxShell::SetHelpId(sal_uIntPtr nId
)
655 sal_uIntPtr
SfxShell::GetHelpId() const
657 return pImp
->nHelpId
;
660 SfxObjectShell
* SfxShell::GetObjectShell()
662 if ( GetViewShell() )
663 return GetViewShell()->GetViewFrame()->GetObjectShell();
668 bool SfxShell::HasUIFeature( sal_uInt32
)
673 sal_IntPtr
DispatcherUpdate_Impl( void*, void* pArg
)
675 static_cast<SfxDispatcher
*>(pArg
)->Update_Impl( true );
676 static_cast<SfxDispatcher
*>(pArg
)->GetBindings()->InvalidateAll(false);
680 void SfxShell::UIFeatureChanged()
682 SfxViewFrame
*pFrame
= GetFrame();
683 if ( pFrame
&& pFrame
->IsVisible() )
685 // Also force an update, if dispatcher is already updated otherwise
686 // something my get stuck in the bunkered tools. Asynchronous call to
687 // prevent recursion.
688 if ( !pImp
->pUpdater
)
689 pImp
->pUpdater
= new svtools::AsynchronLink( Link
<>( this, DispatcherUpdate_Impl
) );
691 // Multiple views allowed
692 pImp
->pUpdater
->Call( pFrame
->GetDispatcher(), true );
696 void SfxShell::SetDisableFlags( sal_uIntPtr nFlags
)
698 pImp
->nDisableFlags
= nFlags
;
701 sal_uIntPtr
SfxShell::GetDisableFlags() const
703 return pImp
->nDisableFlags
;
706 SfxItemSet
* SfxShell::CreateItemSet( sal_uInt16
)
711 void SfxShell::ApplyItemSet( sal_uInt16
, const SfxItemSet
& )
715 void SfxShell::SetContextName (const ::rtl::OUString
& rsContextName
)
717 pImp
->maContextChangeBroadcaster
.Initialize(rsContextName
);
720 void SfxShell::SetViewShell_Impl( SfxViewShell
* pView
)
722 pImp
->pViewSh
= pView
;
725 void SfxShell::BroadcastContextForActivation (const bool bIsActivated
)
727 SfxViewFrame
* pViewFrame
= GetFrame();
728 if (pViewFrame
!= NULL
)
731 pImp
->maContextChangeBroadcaster
.Activate(pViewFrame
->GetFrame().GetFrameInterface());
733 pImp
->maContextChangeBroadcaster
.Deactivate(pViewFrame
->GetFrame().GetFrameInterface());
737 bool SfxShell::SetContextBroadcasterEnabled (const bool bIsEnabled
)
739 return pImp
->maContextChangeBroadcaster
.SetBroadcasterEnabled(bIsEnabled
);
742 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */