blob: 05c01aea0a2f019bcc71bca6463479f5e860d0d3 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sfx2.hxx"
#include <hash_map>
#include <svl/itempool.hxx>
#include <svl/itemiter.hxx>
#include <svl/eitem.hxx>
#include <svl/aeitem.hxx>
#include <svl/intitem.hxx>
#include <svl/stritem.hxx>
#include <svl/visitem.hxx>
#include <com/sun/star/util/XURLTransformer.hpp>
#include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
#include <com/sun/star/frame/XDispatch.hpp>
#include <com/sun/star/frame/XDispatchProvider.hpp>
#include <com/sun/star/frame/XStatusListener.hpp>
#include <com/sun/star/frame/FrameSearchFlag.hpp>
#include <com/sun/star/frame/XDispatchProviderInterception.hpp>
#include <com/sun/star/frame/FeatureStateEvent.hpp>
#include <com/sun/star/frame/DispatchDescriptor.hpp>
#include <com/sun/star/frame/XController.hpp>
#include <comphelper/processfactory.hxx>
#include <svtools/itemdel.hxx>
#ifndef GCC
#endif
// wg. nInReschedule
#include "appdata.hxx"
#include <sfx2/bindings.hxx>
#include <sfx2/msg.hxx>
#include "statcach.hxx"
#include <sfx2/ctrlitem.hxx>
#include <sfx2/app.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/request.hxx>
#include <sfx2/objface.hxx>
#include "sfxtypes.hxx"
#include "workwin.hxx"
#include <sfx2/unoctitm.hxx>
#include <sfx2/sfx.hrc>
#include <sfx2/sfxuno.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/msgpool.hxx>
#include <comphelper/uieventslogger.hxx>
#include <com/sun/star/frame/XModuleManager.hpp>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;
DBG_NAME(SfxBindingsMsgPos)
DBG_NAME(SfxBindingsUpdateServers)
DBG_NAME(SfxBindingsCreateSet)
DBG_NAME(SfxBindingsUpdateCtrl1)
DBG_NAME(SfxBindingsUpdateCtrl2)
DBG_NAME(SfxBindingsNextJob_Impl0)
DBG_NAME(SfxBindingsNextJob_Impl)
DBG_NAME(SfxBindingsUpdate_Impl)
DBG_NAME(SfxBindingsInvalidateAll)
//====================================================================
static sal_uInt16 nTimeOut = 300;
#define TIMEOUT_FIRST nTimeOut
#define TIMEOUT_UPDATING 20
#define TIMEOUT_IDLE 2500
static sal_uInt32 nCache1 = 0;
static sal_uInt32 nCache2 = 0;
typedef std::hash_map< sal_uInt16, bool > InvalidateSlotMap;
//====================================================================
DECL_PTRARRAY(SfxStateCacheArr_Impl, SfxStateCache*, 32, 16)
//====================================================================
class SfxAsyncExec_Impl
{
::com::sun::star::util::URL aCommand;
::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
Timer aTimer;
public:
SfxAsyncExec_Impl( const ::com::sun::star::util::URL& rCmd, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch >& rDisp )
: aCommand( rCmd )
, xDisp( rDisp )
{
aTimer.SetTimeoutHdl( LINK(this, SfxAsyncExec_Impl, TimerHdl) );
aTimer.SetTimeout( 0 );
aTimer.Start();
}
DECL_LINK( TimerHdl, Timer*);
};
IMPL_LINK(SfxAsyncExec_Impl, TimerHdl, Timer*, pTimer)
{
(void)pTimer; // unused
aTimer.Stop();
Sequence<beans::PropertyValue> aSeq;
xDisp->dispatch( aCommand, aSeq );
delete this;
return 0L;
}
class SfxBindings_Impl
{
public:
::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchRecorder > xRecorder;
::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv;
SfxUnoControllerArr_Impl*
pUnoCtrlArr;
SfxWorkWindow* pWorkWin;
SfxBindings* pSubBindings;
SfxBindings* pSuperBindings;
SfxStateCacheArr_Impl* pCaches; // je ein cache fuer jede gebundene
sal_uInt16 nCachedFunc1; // index der zuletzt gerufenen
sal_uInt16 nCachedFunc2; // index der vorletzt gerufenen
sal_uInt16 nMsgPos; // Message-Position, ab der zu aktualisieren ist
SfxPopupAction ePopupAction; // in DeleteFloatinWindow() abgefragt
sal_Bool bContextChanged;
sal_Bool bMsgDirty; // wurde ein MessageServer invalidiert?
sal_Bool bAllMsgDirty; // wurden die MessageServer invalidiert?
sal_Bool bAllDirty; // nach InvalidateAll
sal_Bool bCtrlReleased; // waehrend EnterRegistrations
AutoTimer aTimer; // fuer volatile Slots
sal_Bool bInUpdate; // fuer Assertions
sal_Bool bInNextJob; // fuer Assertions
sal_Bool bFirstRound; // Erste Runde im Update
sal_uInt16 nFirstShell; // Shell, die in erster Runde bevorzugt wird
sal_uInt16 nOwnRegLevel; // z"ahlt die echten Locks, ohne die der SuperBindings
InvalidateSlotMap m_aInvalidateSlots; // store slots which are invalidated while in update
};
//--------------------------------------------------------------------
struct SfxFoundCache_Impl
{
sal_uInt16 nSlotId; // die Slot-Id
sal_uInt16 nWhichId; // falls verf"ugbar die Which-Id, sonst nSlotId
const SfxSlot* pSlot; // Pointer auf den <Master-Slot>
SfxStateCache* pCache; // Pointer auf den StatusCache, ggf. 0
SfxFoundCache_Impl():
nSlotId(0),
nWhichId(0),
pSlot(0),
pCache(0)
{}
SfxFoundCache_Impl(SfxFoundCache_Impl&r):
nSlotId(r.nSlotId),
nWhichId(r.nWhichId),
pSlot(r.pSlot),
pCache(r.pCache)
{}
SfxFoundCache_Impl(sal_uInt16 nS, sal_uInt16 nW, const SfxSlot *pS, SfxStateCache *pC ):
nSlotId(nS),
nWhichId(nW),
pSlot(pS),
pCache(pC)
{}
int operator<( const SfxFoundCache_Impl &r ) const
{ return nWhichId < r.nWhichId; }
int operator==( const SfxFoundCache_Impl &r ) const
{ return nWhichId== r.nWhichId; }
};
//--------------------------------------------------------------------------
SV_DECL_PTRARR_SORT_DEL(SfxFoundCacheArr_Impl, SfxFoundCache_Impl*, 16, 16 )
SV_IMPL_OP_PTRARR_SORT(SfxFoundCacheArr_Impl, SfxFoundCache_Impl*);
//==========================================================================
SfxBindings::SfxBindings()
: pImp(new SfxBindings_Impl),
pDispatcher(0),
nRegLevel(1) // geht erst auf 0, wenn Dispatcher gesetzt
{
pImp->nMsgPos = 0;
pImp->bAllMsgDirty = sal_True;
pImp->bContextChanged = sal_False;
pImp->bMsgDirty = sal_True;
pImp->bAllDirty = sal_True;
pImp->ePopupAction = SFX_POPUP_DELETE;
pImp->nCachedFunc1 = 0;
pImp->nCachedFunc2 = 0;
pImp->bCtrlReleased = sal_False;
pImp->bFirstRound = sal_False;
pImp->bInNextJob = sal_False;
pImp->bInUpdate = sal_False;
pImp->pSubBindings = NULL;
pImp->pSuperBindings = NULL;
pImp->pWorkWin = NULL;
pImp->pUnoCtrlArr = NULL;
pImp->nOwnRegLevel = nRegLevel;
// all caches are valid (no pending invalidate-job)
// create the list of caches
pImp->pCaches = new SfxStateCacheArr_Impl;
pImp->aTimer.SetTimeoutHdl( LINK(this, SfxBindings, NextJob_Impl) );
}
//====================================================================
SfxBindings::~SfxBindings()
/* [Beschreibung]
Destruktor der Klasse SfxBindings. Die eine, f"ur jede <SfxApplication>
existierende Instanz wird von der <SfxApplication> nach Ausf"urhung
von <SfxApplication::Exit()> automatisch zerst"ort.
Noch existierende <SfxControllerItem> Instanzen, die bei dieser
SfxBindings Instanz angemeldet sind, werden im Destruktor
automatisch zerst"ort. Dies sind i.d.R. Floating-Toolboxen, Value-Sets
etc. Arrays von SfxControllerItems d"urfen zu diesem Zeitpunkt nicht
mehr exisitieren.
*/
{
// Die SubBindings sollen ja nicht gelocked werden !
pImp->pSubBindings = NULL;
ENTERREGISTRATIONS();
pImp->aTimer.Stop();
DeleteControllers_Impl();
// Caches selbst l"oschen
sal_uInt16 nCount = pImp->pCaches->Count();
for ( sal_uInt16 nCache = 0; nCache < nCount; ++nCache )
delete pImp->pCaches->GetObject(nCache);
DELETEZ( pImp->pWorkWin );
delete pImp->pCaches;
delete pImp;
}
//--------------------------------------------------------------------
void SfxBindings::DeleteControllers_Impl()
{
// in der ersten Runde den SfxPopupWindows l"oschen
sal_uInt16 nCount = pImp->pCaches->Count();
sal_uInt16 nCache;
for ( nCache = 0; nCache < nCount; ++nCache )
{
// merken wo man ist
SfxStateCache *pCache = pImp->pCaches->GetObject(nCache);
sal_uInt16 nSlotId = pCache->GetId();
// SfxPopupWindow l"oschen lassen
pCache->DeleteFloatingWindows();
// da der Cache verkleinert worden sein kann, wiederaufsetzen
sal_uInt16 nNewCount = pImp->pCaches->Count();
if ( nNewCount < nCount )
{
nCache = GetSlotPos(nSlotId);
if ( nCache >= nNewCount ||
nSlotId != pImp->pCaches->GetObject(nCache)->GetId() )
--nCache;
nCount = nNewCount;
}
}
// alle Caches l"oschen
for ( nCache = pImp->pCaches->Count(); nCache > 0; --nCache )
{
// Cache via ::com::sun::star::sdbcx::Index besorgen
SfxStateCache *pCache = pImp->pCaches->GetObject(nCache-1);
// alle Controller in dem Cache unbinden
SfxControllerItem *pNext;
for ( SfxControllerItem *pCtrl = pCache->GetItemLink();
pCtrl; pCtrl = pNext )
{
pNext = pCtrl->GetItemLink();
pCtrl->UnBind();
}
if ( pCache->GetInternalController() )
pCache->GetInternalController()->UnBind();
// Cache l"oschen
if( nCache-1 < pImp->pCaches->Count() )
delete (*pImp->pCaches)[nCache-1];
pImp->pCaches->Remove(nCache-1, 1);
}
if( pImp->pUnoCtrlArr )
{
sal_uInt16 nCtrlCount = pImp->pUnoCtrlArr->Count();
for ( sal_uInt16 n=nCtrlCount; n>0; n-- )
{
SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1];
pCtrl->ReleaseBindings();
}
DBG_ASSERT( !pImp->pUnoCtrlArr->Count(), "UnoControllerItems nicht entfernt!" );
DELETEZ( pImp->pUnoCtrlArr );
}
}
//--------------------------------------------------------------------
SfxPopupAction SfxBindings::GetPopupAction_Impl() const
{
return pImp->ePopupAction;
}
//--------------------------------------------------------------------
void SfxBindings::HidePopups( bool bHide )
{
// SfxPopupWindows hiden
HidePopupCtrls_Impl( bHide );
SfxBindings *pSub = pImp->pSubBindings;
while ( pSub )
{
pImp->pSubBindings->HidePopupCtrls_Impl( bHide );
pSub = pSub->pImp->pSubBindings;
}
// SfxChildWindows hiden
DBG_ASSERT( pDispatcher, "HidePopups not allowed without dispatcher" );
if ( pImp->pWorkWin )
pImp->pWorkWin->HidePopups_Impl( bHide, sal_True );
}
void SfxBindings::HidePopupCtrls_Impl( FASTBOOL bHide )
{
if ( bHide )
{
// SfxPopupWindows hiden
pImp->ePopupAction = SFX_POPUP_HIDE;
}
else
{
// SfxPopupWindows showen
pImp->ePopupAction = SFX_POPUP_SHOW;
}
for ( sal_uInt16 nCache = 0; nCache < pImp->pCaches->Count(); ++nCache )
pImp->pCaches->GetObject(nCache)->DeleteFloatingWindows();
pImp->ePopupAction = SFX_POPUP_DELETE;
}
//--------------------------------------------------------------------
void SfxBindings::Update_Impl
(
SfxStateCache* pCache // der upzudatende SfxStatusCache
)
{
if( pCache->GetDispatch().is() && pCache->GetItemLink() )
{
pCache->SetCachedState(sal_True);
if ( !pCache->GetInternalController() )
return;
}
if ( !pDispatcher )
return;
DBG_PROFSTART(SfxBindingsUpdate_Impl);
// alle mit derselben Statusmethode zusammensammeln, die dirty sind
SfxDispatcher &rDispat = *pDispatcher;
const SfxSlot *pRealSlot = 0;
const SfxSlotServer* pMsgServer = 0;
SfxFoundCacheArr_Impl aFound;
SfxItemSet *pSet = CreateSet_Impl( pCache, pRealSlot, &pMsgServer, aFound );
sal_Bool bUpdated = sal_False;
if ( pSet )
{
// Status erfragen
if ( rDispat._FillState( *pMsgServer, *pSet, pRealSlot ) )
{
// Status posten
const SfxInterface *pInterface =
rDispat.GetShell(pMsgServer->GetShellLevel())->GetInterface();
for ( sal_uInt16 nPos = 0; nPos < aFound.Count(); ++nPos )
{
const SfxFoundCache_Impl *pFound = aFound[nPos];
sal_uInt16 nWhich = pFound->nWhichId;
const SfxPoolItem *pItem = 0;
SfxItemState eState = pSet->GetItemState(nWhich, sal_True, &pItem);
if ( eState == SFX_ITEM_DEFAULT && SfxItemPool::IsWhich(nWhich) )
pItem = &pSet->Get(nWhich);
UpdateControllers_Impl( pInterface, aFound[nPos], pItem, eState );
}
bUpdated = sal_True;
}
delete pSet;
}
if ( !bUpdated && pCache )
{
// Wenn pCache == NULL und kein SlotServer ( z.B. weil Dispatcher gelockt! ),
// darf nat"urlich kein Update versucht werden
SfxFoundCache_Impl aFoundCache(
pCache->GetId(), 0,
pRealSlot, pCache );
UpdateControllers_Impl( 0, &aFoundCache, 0, SFX_ITEM_DISABLED);
}
DBG_PROFSTOP(SfxBindingsUpdate_Impl);
}
//--------------------------------------------------------------------
void SfxBindings::InvalidateSlotsInMap_Impl()
{
InvalidateSlotMap::const_iterator pIter = pImp->m_aInvalidateSlots.begin();
while ( pIter != pImp->m_aInvalidateSlots.end() )
{
Invalidate( pIter->first );
++pIter;
}
pImp->m_aInvalidateSlots.clear();
}
//--------------------------------------------------------------------
void SfxBindings::AddSlotToInvalidateSlotsMap_Impl( sal_uInt16 nId )
{
pImp->m_aInvalidateSlots[nId] = sal_True;
}
//--------------------------------------------------------------------
void SfxBindings::Update
(
sal_uInt16 nId // die gebundene und upzudatende Slot-Id
)
{
DBG_MEMTEST();
DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
//!!TLX: Fuehrte zu Vorlagenkatalogstillstand
// if ( nRegLevel )
// return;
if ( pDispatcher )
pDispatcher->Flush();
if ( pImp->pSubBindings )
pImp->pSubBindings->Update( nId );
SfxStateCache* pCache = GetStateCache( nId );
if ( pCache )
{
pImp->bInUpdate = sal_True;
if ( pImp->bMsgDirty )
{
UpdateSlotServer_Impl();
pCache = GetStateCache( nId );
}
if (pCache)
{
sal_Bool bInternalUpdate = sal_True;
if( pCache->GetDispatch().is() && pCache->GetItemLink() )
{
pCache->SetCachedState(sal_True);
bInternalUpdate = ( pCache->GetInternalController() != 0 );
}
if ( bInternalUpdate )
{
// Status erfragen
const SfxSlotServer* pMsgServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
if ( !pCache->IsControllerDirty() &&
( !pMsgServer ||
!pMsgServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) ) )
{
pImp->bInUpdate = sal_False;
InvalidateSlotsInMap_Impl();
return;
}
if (!pMsgServer)
{
pCache->SetState(SFX_ITEM_DISABLED, 0);
pImp->bInUpdate = sal_False;
InvalidateSlotsInMap_Impl();
return;
}
Update_Impl(pCache);
}
pImp->bAllDirty = sal_False;
}
pImp->bInUpdate = sal_False;
InvalidateSlotsInMap_Impl();
}
}
//--------------------------------------------------------------------
void SfxBindings::Update()
{
DBG_MEMTEST();
DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
if ( pImp->pSubBindings )
pImp->pSubBindings->Update();
if ( pDispatcher )
{
if ( nRegLevel )
return;
pImp->bInUpdate = sal_True;
pDispatcher->Flush();
pDispatcher->Update_Impl();
while ( !NextJob_Impl(0) )
; // loop
pImp->bInUpdate = sal_False;
InvalidateSlotsInMap_Impl();
}
}
//--------------------------------------------------------------------
void SfxBindings::SetState
(
const SfxItemSet& rSet // zu setzende Status-Werte
)
{
// wenn gelockt, dann nur invalidieren
if ( nRegLevel )
{
SfxItemIter aIter(rSet);
for ( const SfxPoolItem *pItem = aIter.FirstItem();
pItem;
pItem = aIter.NextItem() )
Invalidate( pItem->Which() );
}
else
{
// Status d"urfen nur angenommen werden, wenn alle Slot-Pointer gesetzt sind
if ( pImp->bMsgDirty )
UpdateSlotServer_Impl();
// "uber das ItemSet iterieren, falls Slot gebunden, updaten
//! Bug: WhichIter verwenden und ggf. VoidItems hochschicken
SfxItemIter aIter(rSet);
for ( const SfxPoolItem *pItem = aIter.FirstItem();
pItem;
pItem = aIter.NextItem() )
{
SfxStateCache* pCache =
GetStateCache( rSet.GetPool()->GetSlotId(pItem->Which()) );
if ( pCache )
{
// Status updaten
if ( !pCache->IsControllerDirty() )
pCache->Invalidate(sal_False);
pCache->SetState( SFX_ITEM_AVAILABLE, pItem );
//! nicht implementiert: Updates von EnumSlots via MasterSlots
}
}
}
}
//--------------------------------------------------------------------
void SfxBindings::SetState
(
const SfxPoolItem& rItem // zu setzender Status-Wert
)
{
if ( nRegLevel )
{
Invalidate( rItem.Which() );
}
else
{
// Status d"urfen nur angenommen werden, wenn alle Slot-Pointer gesetzt sind
if ( pImp->bMsgDirty )
UpdateSlotServer_Impl();
// falls der Slot gebunden ist, updaten
DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
"cannot set items with which-id" );
SfxStateCache* pCache = GetStateCache( rItem.Which() );
if ( pCache )
{
// Status updaten
if ( !pCache->IsControllerDirty() )
pCache->Invalidate(sal_False);
pCache->SetState( SFX_ITEM_AVAILABLE, &rItem );
//! nicht implementiert: Updates von EnumSlots via MasterSlots
}
}
}
//--------------------------------------------------------------------
SfxStateCache* SfxBindings::GetAnyStateCache_Impl( sal_uInt16 nId )
{
SfxStateCache* pCache = GetStateCache( nId );
if ( !pCache && pImp->pSubBindings )
return pImp->pSubBindings->GetAnyStateCache_Impl( nId );
return pCache;
}
SfxStateCache* SfxBindings::GetStateCache
(
sal_uInt16 nId /* Slot-Id, deren SfxStatusCache gefunden
werden soll */,
sal_uInt16* pPos /* 0 bzw. Position, ab der die Bindings
bin"ar durchsucht werden sollen. Liefert
die Position zur"uck, an der nId gefunden
wurde, bzw. an der es einfef"ugt werden
w"urde. */
)
{
DBG_MEMTEST();
DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
// is the specified function bound?
const sal_uInt16 nStart = ( pPos ? *pPos : 0 );
const sal_uInt16 nPos = GetSlotPos( nId, nStart );
if ( nPos < pImp->pCaches->Count() &&
(*pImp->pCaches)[nPos]->GetId() == nId )
{
if ( pPos )
*pPos = nPos;
return (*pImp->pCaches)[nPos];
}
return 0;
}
//--------------------------------------------------------------------
void SfxBindings::InvalidateAll
(
sal_Bool bWithMsg /* sal_True
Slot-Server als ung"ultig markieren
sal_False
Slot-Server bleiben g"ultig */
)
{
DBG_PROFSTART(SfxBindingsInvalidateAll);
DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
DBG_MEMTEST();
if ( pImp->pSubBindings )
pImp->pSubBindings->InvalidateAll( bWithMsg );
// ist schon alles dirty gesetzt oder downing => nicht zu tun
if ( !pDispatcher ||
( pImp->bAllDirty && ( !bWithMsg || pImp->bAllMsgDirty ) ) ||
SFX_APP()->IsDowning() )
{
DBG_PROFSTOP(SfxBindingsInvalidateAll);
return;
}
pImp->bAllMsgDirty = pImp->bAllMsgDirty || bWithMsg;
pImp->bMsgDirty = pImp->bMsgDirty || pImp->bAllMsgDirty || bWithMsg;
pImp->bAllDirty = sal_True;
for ( sal_uInt16 n = 0; n < pImp->pCaches->Count(); ++n )
pImp->pCaches->GetObject(n)->Invalidate(bWithMsg);
/*
::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
( pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
if ( bWithMsg && xFrame.is() )
xFrame->contextChanged();
*/
pImp->nMsgPos = 0;
if ( !nRegLevel )
{
pImp->aTimer.Stop();
pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
pImp->aTimer.Start();
// pImp->bFirstRound = sal_True;
// pImp->nFirstShell = 0;
}
DBG_PROFSTOP(SfxBindingsInvalidateAll);
}
//--------------------------------------------------------------------
void SfxBindings::Invalidate
(
const sal_uInt16* pIds /* numerisch sortiertes 0-terminiertes Array
von Slot-Ids (einzel, nicht als Paare!) */
)
{
DBG_PROFSTART(SfxBindingsInvalidateAll);
// DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
DBG_MEMTEST();
if ( pImp->bInUpdate )
{
sal_Int32 i = 0;
while ( pIds[i] != 0 )
AddSlotToInvalidateSlotsMap_Impl( pIds[i++] );
if ( pImp->pSubBindings )
pImp->pSubBindings->Invalidate( pIds );
return;
}
if ( pImp->pSubBindings )
pImp->pSubBindings->Invalidate( pIds );
// ist schon alles dirty gesetzt oder downing => nicht zu tun
if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
return;
// in immer kleiner werdenden Berichen bin"ar suchen
for ( sal_uInt16 n = GetSlotPos(*pIds);
*pIds && n < pImp->pCaches->Count();
n = GetSlotPos(*pIds, n) )
{
// falls SID "uberhaupt gebunden ist, den Cache invalidieren
SfxStateCache *pCache = pImp->pCaches->GetObject(n);
if ( pCache->GetId() == *pIds )
pCache->Invalidate(sal_False);
// n"achste SID
if ( !*++pIds )
break;
DBG_ASSERT( *pIds > *(pIds-1), "pIds unsorted" );
}
// falls nicht gelockt, Update-Timer starten
pImp->nMsgPos = 0;
if ( !nRegLevel )
{
pImp->aTimer.Stop();
pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
pImp->aTimer.Start();
// pImp->bFirstRound = sal_True;
// pImp->nFirstShell = 0;
}
DBG_PROFSTOP(SfxBindingsInvalidateAll);
}
//--------------------------------------------------------------------
void SfxBindings::InvalidateShell
(
const SfxShell& rSh /* Die <SfxShell>, deren Slot-Ids
invalidiert werden sollen. */,
sal_Bool bDeep /* sal_True
auch die, von der SfxShell
ererbten Slot-Ids werden invalidert
sal_False
die ererbten und nicht "uberladenen
Slot-Ids werden invalidiert */
//! MI: z. Zt. immer bDeep
)
{
DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
if ( pImp->pSubBindings )
pImp->pSubBindings->InvalidateShell( rSh, bDeep );
if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
return;
DBG_PROFSTART(SfxBindingsInvalidateAll);
DBG_MEMTEST();
// Jetzt schon flushen, wird in GetShellLevel(rSh) sowieso gemacht; wichtig,
// damit pImp->bAll(Msg)Dirty korrekt gesetzt ist
pDispatcher->Flush();
if ( !pDispatcher ||
( pImp->bAllDirty && pImp->bAllMsgDirty ) ||
SFX_APP()->IsDowning() )
{
// Wenn sowieso demn"achst alle Server geholt werden
return;
}
// Level finden
sal_uInt16 nLevel = pDispatcher->GetShellLevel(rSh);
if ( nLevel != USHRT_MAX )
{
for ( sal_uInt16 n = 0; n < pImp->pCaches->Count(); ++n )
{
SfxStateCache *pCache = pImp->pCaches->GetObject(n);
const SfxSlotServer *pMsgServer =
pCache->GetSlotServer(*pDispatcher, pImp->xProv);
if ( pMsgServer && pMsgServer->GetShellLevel() == nLevel )
pCache->Invalidate(sal_False);
}
pImp->nMsgPos = 0;
if ( !nRegLevel )
{
pImp->aTimer.Stop();
pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
pImp->aTimer.Start();
pImp->bFirstRound = sal_True;
pImp->nFirstShell = nLevel;
}
}
DBG_PROFSTOP(SfxBindingsInvalidateAll);
}
//--------------------------------------------------------------------
void SfxBindings::Invalidate
(
sal_uInt16 nId // zu invalidierende Slot-Id
)
{
DBG_MEMTEST();
// DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
if ( pImp->bInUpdate )
{
AddSlotToInvalidateSlotsMap_Impl( nId );
if ( pImp->pSubBindings )
pImp->pSubBindings->Invalidate( nId );
return;
}
if ( pImp->pSubBindings )
pImp->pSubBindings->Invalidate( nId );
if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() )
return;
SfxStateCache* pCache = GetStateCache(nId);
if ( pCache )
{
pCache->Invalidate(sal_False);
pImp->nMsgPos = Min(GetSlotPos(nId), pImp->nMsgPos);
if ( !nRegLevel )
{
pImp->aTimer.Stop();
pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
pImp->aTimer.Start();
}
}
}
//--------------------------------------------------------------------
void SfxBindings::Invalidate
(
sal_uInt16 nId, // zu invalidierende Slot-Id
sal_Bool bWithItem, // StateCache clearen ?
sal_Bool bWithMsg // SlotServer neu holen ?
)
{
DBG_MEMTEST();
DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" );
if ( pImp->pSubBindings )
pImp->pSubBindings->Invalidate( nId, bWithItem, bWithMsg );
if ( SFX_APP()->IsDowning() )
return;
SfxStateCache* pCache = GetStateCache(nId);
if ( pCache )
{
if ( bWithItem )
pCache->ClearCache();
pCache->Invalidate(bWithMsg);
if ( !pDispatcher || pImp->bAllDirty )
return;
pImp->nMsgPos = Min(GetSlotPos(nId), pImp->nMsgPos);
if ( !nRegLevel )
{
pImp->aTimer.Stop();
pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
pImp->aTimer.Start();
}
}
}
//--------------------------------------------------------------------
sal_Bool SfxBindings::IsBound( sal_uInt16 nSlotId, sal_uInt16 nStartSearchAt )
{
DBG_MEMTEST();
DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
return GetStateCache(nSlotId, &nStartSearchAt ) != 0;
}
//--------------------------------------------------------------------
sal_uInt16 SfxBindings::GetSlotPos( sal_uInt16 nId, sal_uInt16 nStartSearchAt )
{
DBG_MEMTEST();
DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
DBG_PROFSTART(SfxBindingsMsgPos);
// answer immediately if a function-seek comes repeated
if ( pImp->nCachedFunc1 < pImp->pCaches->Count() &&
(*pImp->pCaches)[pImp->nCachedFunc1]->GetId() == nId )
{
++nCache1;
DBG_PROFSTOP(SfxBindingsMsgPos);
return pImp->nCachedFunc1;
}
if ( pImp->nCachedFunc2 < pImp->pCaches->Count() &&
(*pImp->pCaches)[pImp->nCachedFunc2]->GetId() == nId )
{
++nCache2;
// swap the caches
sal_uInt16 nTemp = pImp->nCachedFunc1;
pImp->nCachedFunc1 = pImp->nCachedFunc2;
pImp->nCachedFunc2 = nTemp;
DBG_PROFSTOP(SfxBindingsMsgPos);
return pImp->nCachedFunc1;
}
// binary search, if not found, seek to target-position
if ( pImp->pCaches->Count() <= nStartSearchAt )
{
DBG_PROFSTOP(SfxBindingsMsgPos);
return 0;
}
if ( pImp->pCaches->Count() == (nStartSearchAt+1) )
{
DBG_PROFSTOP(SfxBindingsMsgPos);
return (*pImp->pCaches)[nStartSearchAt]->GetId() >= nId ? 0 : 1;
}
sal_uInt16 nLow = nStartSearchAt;
sal_uInt16 nMid = 0;
sal_uInt16 nHigh = 0;
sal_Bool bFound = sal_False;
nHigh = pImp->pCaches->Count() - 1;
while ( !bFound && nLow <= nHigh )
{
nMid = (nLow + nHigh) >> 1;
DBG_ASSERT( nMid < pImp->pCaches->Count(), "bsearch ist buggy" );
int nDiff = (int) nId - (int) ( ((*pImp->pCaches)[nMid])->GetId() );
if ( nDiff < 0)
{ if ( nMid == 0 )
break;
nHigh = nMid - 1;
}
else if ( nDiff > 0 )
{ nLow = nMid + 1;
if ( nLow == 0 )
break;
}
else
bFound = sal_True;
}
sal_uInt16 nPos = bFound ? nMid : nLow;
DBG_ASSERT( nPos <= pImp->pCaches->Count(), "" );
DBG_ASSERT( nPos == pImp->pCaches->Count() ||
nId <= (*pImp->pCaches)[nPos]->GetId(), "" );
DBG_ASSERT( nPos == nStartSearchAt ||
nId > (*pImp->pCaches)[nPos-1]->GetId(), "" );
DBG_ASSERT( ( (nPos+1) >= pImp->pCaches->Count() ) ||
nId < (*pImp->pCaches)[nPos+1]->GetId(), "" );
pImp->nCachedFunc2 = pImp->nCachedFunc1;
pImp->nCachedFunc1 = nPos;
DBG_PROFSTOP(SfxBindingsMsgPos);
return nPos;
}
//--------------------------------------------------------------------
void SfxBindings::RegisterInternal_Impl( SfxControllerItem& rItem )
{
Register_Impl( rItem, sal_True );
}
void SfxBindings::Register( SfxControllerItem& rItem )
{
Register_Impl( rItem, sal_False );
}
void SfxBindings::Register_Impl( SfxControllerItem& rItem, sal_Bool bInternal )
{
DBG_MEMTEST();
// DBG_ASSERT( nRegLevel > 0, "registration without EnterRegistrations" );
DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Register while status-updating" );
// insert new cache if it does not already exist
sal_uInt16 nId = rItem.GetId();
sal_uInt16 nPos = GetSlotPos(nId);
if ( nPos >= pImp->pCaches->Count() ||
(*pImp->pCaches)[nPos]->GetId() != nId )
{
SfxStateCache* pCache = new SfxStateCache(nId);
pImp->pCaches->Insert( nPos, pCache );
DBG_ASSERT( nPos == 0 ||
(*pImp->pCaches)[nPos]->GetId() >
(*pImp->pCaches)[nPos-1]->GetId(), "" );
DBG_ASSERT( (nPos == pImp->pCaches->Count()-1) ||
(*pImp->pCaches)[nPos]->GetId() <
(*pImp->pCaches)[nPos+1]->GetId(), "" );
pImp->bMsgDirty = sal_True;
}
// enqueue the new binding
if ( bInternal )
{
(*pImp->pCaches)[nPos]->SetInternalController( &rItem );
}
else
{
SfxControllerItem *pOldItem = (*pImp->pCaches)[nPos]->ChangeItemLink(&rItem);
rItem.ChangeItemLink(pOldItem);
}
}
//--------------------------------------------------------------------
void SfxBindings::Release( SfxControllerItem& rItem )
{
DBG_MEMTEST();
DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
//! DBG_ASSERT( nRegLevel > 0, "release without EnterRegistrations" );
DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Release while status-updating" );
ENTERREGISTRATIONS();
// find the bound function
sal_uInt16 nId = rItem.GetId();
sal_uInt16 nPos = GetSlotPos(nId);
SfxStateCache* pCache = (*pImp->pCaches)[nPos];
if ( pCache->GetId() == nId )
{
if ( pCache->GetInternalController() == &rItem )
{
pCache->ReleaseInternalController();
}
else
{
// is this the first binding in the list?
SfxControllerItem* pItem = pCache->GetItemLink();
if ( pItem == &rItem )
pCache->ChangeItemLink( rItem.GetItemLink() );
else
{
// search the binding in the list
while ( pItem && pItem->GetItemLink() != &rItem )
pItem = pItem->GetItemLink();
// unlink it if it was found
if ( pItem )
pItem->ChangeItemLink( rItem.GetItemLink() );
}
}
// was this the last controller?
if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
{
#ifdef slow
// remove the BoundFunc
delete (*pImp->pCaches)[nPos];
pImp->pCaches->Remove(nPos, 1);
#endif
pImp->bCtrlReleased = sal_True;
}
}
LEAVEREGISTRATIONS();
}
//--------------------------------------------------------------------
const SfxPoolItem* SfxBindings::ExecuteSynchron( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi,
const SfxPoolItem **ppInternalArgs )
{
DBG_MEMTEST();
DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
if( !nId || !pDispatcher )
return NULL;
return Execute_Impl( nId, ppItems, nModi, SFX_CALLMODE_SYNCHRON, ppInternalArgs );
}
sal_Bool SfxBindings::Execute( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode,
const SfxPoolItem **ppInternalArgs )
{
DBG_MEMTEST();
DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
if( !nId || !pDispatcher )
return sal_False;
const SfxPoolItem* pRet = Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs );
return ( pRet != 0 );
}
void SfxBindings::ExecuteGlobal_Impl( sal_uInt16 nId )
{
if( nId && pDispatcher )
Execute_Impl( nId, NULL, 0, SFX_CALLMODE_ASYNCHRON, NULL, sal_True );
}
const SfxPoolItem* SfxBindings::Execute_Impl( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode,
const SfxPoolItem **ppInternalArgs, sal_Bool bGlobalOnly )
{
SfxStateCache *pCache = GetStateCache( nId );
if ( !pCache )
{
SfxBindings *pBind = pImp->pSubBindings;
while ( pBind )
{
if ( pBind->GetStateCache( nId ) )
return pBind->Execute_Impl( nId, ppItems, nModi, nCallMode, ppInternalArgs, bGlobalOnly );
pBind = pBind->pImp->pSubBindings;
};
}
SfxDispatcher &rDispatcher = *pDispatcher;
rDispatcher.Flush();
rDispatcher.GetFrame(); // -Wall is this required???
// get SlotServer (Slot+ShellLevel) and Shell from cache
sal_Bool bDeleteCache = sal_False;
if ( !pCache )
{
// Execution of non cached slots (Accelerators don't use Controllers)
// slot is uncached, use SlotCache to handle external dispatch providers
pCache = new SfxStateCache( nId );
pCache->GetSlotServer( rDispatcher, pImp->xProv );
bDeleteCache = sal_True;
}
if ( pCache && pCache->GetDispatch().is() )
{
DBG_ASSERT( !ppInternalArgs, "Internal args get lost when dispatched!" );
SfxItemPool &rPool = GetDispatcher()->GetFrame()->GetObjectShell()->GetPool();
SfxRequest aReq( nId, nCallMode, rPool );
aReq.SetModifier( nModi );
if( ppItems )
while( *ppItems )
aReq.AppendItem( **ppItems++ );
// cache binds to an external dispatch provider
pCache->Dispatch( aReq.GetArgs(), nCallMode == SFX_CALLMODE_SYNCHRON );
if ( bDeleteCache )
DELETEZ( pCache );
SfxPoolItem *pVoid = new SfxVoidItem( nId );
DeleteItemOnIdle( pVoid );
return pVoid;
}
// slot is handled internally by SfxDispatcher
if ( pImp->bMsgDirty )
UpdateSlotServer_Impl();
SfxShell *pShell=0;
const SfxSlot *pSlot=0;
// if slot was uncached, we should have created a cache in this method!
DBG_ASSERT( pCache, "This code needs a cache!");
const SfxSlotServer* pServer = pCache ? pCache->GetSlotServer( rDispatcher, pImp->xProv ) : 0;
if ( !pServer )
{
return NULL;
}
else
{
pShell = rDispatcher.GetShell( pServer->GetShellLevel() );
pSlot = pServer->GetSlot();
}
if ( bGlobalOnly )
if ( !pShell->ISA(SfxModule) && !pShell->ISA(SfxApplication) && !pShell->ISA(SfxViewFrame) )
return NULL;
SfxItemPool &rPool = pShell->GetPool();
SfxRequest aReq( nId, nCallMode, rPool );
aReq.SetModifier( nModi );
if( ppItems )
while( *ppItems )
aReq.AppendItem( **ppItems++ );
if ( ppInternalArgs )
{
SfxAllItemSet aSet( rPool );
for ( const SfxPoolItem **pArg = ppInternalArgs; *pArg; ++pArg )
aSet.Put( **pArg );
aReq.SetInternalArgs_Impl( aSet );
}
Execute_Impl( aReq, pSlot, pShell );
const SfxPoolItem* pRet = aReq.GetReturnValue();
if ( !pRet )
{
SfxPoolItem *pVoid = new SfxVoidItem( nId );
DeleteItemOnIdle( pVoid );
pRet = pVoid;
}
if ( bDeleteCache )
delete pCache;
return pRet;
}
void SfxBindings::Execute_Impl( SfxRequest& aReq, const SfxSlot* pSlot, SfxShell* pShell )
{
SfxItemPool &rPool = pShell->GetPool();
if ( SFX_KIND_ENUM == pSlot->GetKind() )
{
// bei Enum-Slots muss der Master mit dem Wert des Enums executet werden
const SfxSlot *pRealSlot = pShell->GetInterface()->GetRealSlot(pSlot);
const sal_uInt16 nSlotId = pRealSlot->GetSlotId();
aReq.SetSlot( nSlotId );
aReq.AppendItem( SfxAllEnumItem( rPool.GetWhich(nSlotId), pSlot->GetValue() ) );
pDispatcher->_Execute( *pShell, *pRealSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
}
else if ( SFX_KIND_ATTR == pSlot->GetKind() )
{
// bei Attr-Slots muss der Which-Wert gemapped werden
const sal_uInt16 nSlotId = pSlot->GetSlotId();
aReq.SetSlot( nSlotId );
if ( pSlot->IsMode(SFX_SLOT_TOGGLE) )
{
// an togglebare-Attribs (Bools) wird der Wert angeheangt
sal_uInt16 nWhich = pSlot->GetWhich(rPool);
SfxItemSet aSet(rPool, nWhich, nWhich, 0);
SfxStateFunc aFunc = pSlot->GetStateFnc();
pShell->CallState( aFunc, aSet );
const SfxPoolItem *pOldItem;
SfxItemState eState = aSet.GetItemState(nWhich, sal_True, &pOldItem);
if ( eState == SFX_ITEM_DISABLED )
return;
if ( SFX_ITEM_AVAILABLE == eState && SfxItemPool::IsWhich(nWhich) )
pOldItem = &aSet.Get(nWhich);
if ( SFX_ITEM_SET == eState ||
( SFX_ITEM_AVAILABLE == eState &&
SfxItemPool::IsWhich(nWhich) &&
pOldItem ) )
{
if ( pOldItem->ISA(SfxBoolItem) )
{
// wir koennen Bools toggeln
sal_Bool bOldValue = ((const SfxBoolItem *)pOldItem)->GetValue();
SfxBoolItem *pNewItem = (SfxBoolItem*) (pOldItem->Clone());
pNewItem->SetValue( !bOldValue );
aReq.AppendItem( *pNewItem );
delete pNewItem;
}
else if ( pOldItem->ISA(SfxEnumItemInterface) &&
((SfxEnumItemInterface *)pOldItem)->HasBoolValue())
{
// und Enums mit Bool-Interface
SfxEnumItemInterface *pNewItem =
(SfxEnumItemInterface*) (pOldItem->Clone());
pNewItem->SetBoolValue(!((SfxEnumItemInterface *)pOldItem)->GetBoolValue());
aReq.AppendItem( *pNewItem );
delete pNewItem;
}
else {
DBG_ERROR( "Toggle only for Enums and Bools allowed" );
}
}
else if ( SFX_ITEM_DONTCARE == eState )
{
// ein Status-Item per Factory erzeugen
SfxPoolItem *pNewItem = pSlot->GetType()->CreateItem();
DBG_ASSERT( pNewItem, "Toggle an Slot ohne ItemFactory" );
pNewItem->SetWhich( nWhich );
if ( pNewItem->ISA(SfxBoolItem) )
{
// wir koennen Bools toggeln
((SfxBoolItem*)pNewItem)->SetValue( sal_True );
aReq.AppendItem( *pNewItem );
}
else if ( pNewItem->ISA(SfxEnumItemInterface) &&
((SfxEnumItemInterface *)pNewItem)->HasBoolValue())
{
// und Enums mit Bool-Interface
((SfxEnumItemInterface*)pNewItem)->SetBoolValue(sal_True);
aReq.AppendItem( *pNewItem );
}
else {
DBG_ERROR( "Toggle only for Enums and Bools allowed" );
}
delete pNewItem;
}
else {
DBG_ERROR( "suspicious Toggle-Slot" );
}
}
pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
}
else
pDispatcher->_Execute( *pShell, *pSlot, aReq, aReq.GetCallMode() | SFX_CALLMODE_RECORD );
}
//--------------------------------------------------------------------
void SfxBindings::UpdateSlotServer_Impl()
{
DBG_PROFSTART(SfxBindingsUpdateServers);
DBG_MEMTEST();
DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
// synchronisieren
pDispatcher->Flush();
// pDispatcher->Update_Impl();
if ( pImp->bAllMsgDirty )
{
if ( !nRegLevel )
{
::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
( pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
//if ( xFrame.is() )
// xFrame->contextChanged();
pImp->bContextChanged = sal_False;
}
else
pImp->bContextChanged = sal_True;
}
const sal_uInt16 nCount = pImp->pCaches->Count();
for(sal_uInt16 i = 0; i < nCount; ++i)
{
SfxStateCache *pCache = pImp->pCaches->GetObject(i);
pCache->GetSlotServer(*pDispatcher, pImp->xProv);
}
pImp->bMsgDirty = pImp->bAllMsgDirty = sal_False;
Broadcast( SfxSimpleHint(SFX_HINT_DOCCHANGED) );
DBG_PROFSTOP(SfxBindingsUpdateServers);
}
//--------------------------------------------------------------------
#ifdef WNT
int __cdecl CmpUS_Impl(const void *p1, const void *p2)
#else
int CmpUS_Impl(const void *p1, const void *p2)
#endif
/* [Beschreibung]
Interne Vergleichsfunktion fuer qsort.
*/
{
return *(sal_uInt16 *)p1 - *(sal_uInt16 *)p2;
}
//--------------------------------------------------------------------
SfxItemSet* SfxBindings::CreateSet_Impl
(
SfxStateCache*& pCache, // in: Status-Cache von nId
const SfxSlot*& pRealSlot, // out: RealSlot zu nId
const SfxSlotServer** pMsgServer, // out: Slot-Server zu nId
SfxFoundCacheArr_Impl& rFound // out: Liste der Caches der Siblings
)
{
DBG_MEMTEST();
DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
DBG_ASSERT( !pImp->bMsgDirty, "CreateSet_Impl mit dirty MessageServer" );
const SfxSlotServer* pMsgSvr = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
if(!pMsgSvr || !pDispatcher)
return 0;
DBG_PROFSTART(SfxBindingsCreateSet);
pRealSlot = 0;
*pMsgServer = pMsgSvr;
sal_uInt16 nShellLevel = pMsgSvr->GetShellLevel();
SfxShell *pShell = pDispatcher->GetShell( nShellLevel );
if ( !pShell ) // seltener GPF beim Browsen durch Update aus Inet-Notify
return 0;
SfxItemPool &rPool = pShell->GetPool();
// hole die Status-Methode, von der pCache bedient wird
SfxStateFunc pFnc = 0;
const SfxInterface *pInterface = pShell->GetInterface();
if ( SFX_KIND_ENUM == pMsgSvr->GetSlot()->GetKind() )
{
pRealSlot = pInterface->GetRealSlot(pMsgSvr->GetSlot());
pCache = GetStateCache( pRealSlot->GetSlotId() );
// DBG_ASSERT( pCache, "Kein Slotcache fuer den Masterslot gefunden!" );
}
else
pRealSlot = pMsgSvr->GetSlot();
//
// Achtung: pCache darf auch NULL sein !!!
//
pFnc = pRealSlot->GetStateFnc();
// der RealSlot ist immer drin
const SfxFoundCache_Impl *pFound = new SfxFoundCache_Impl(
pRealSlot->GetSlotId(), pRealSlot->GetWhich(rPool), pRealSlot, pCache );
rFound.Insert( pFound );
sal_uInt16 nSlot = pRealSlot->GetSlotId();
if ( !(nSlot >= SID_VERB_START && nSlot <= SID_VERB_END) )
{
pInterface = pInterface->GetRealInterfaceForSlot( pRealSlot );
DBG_ASSERT (pInterface,"Slot in angegebener Shell nicht gefunden!");
}
// Durchsuche die Bindings nach den von derselben Funktion bedienten Slots.
// Daf"ur kommen nur Slots in Frage, die es im gefundenen Interface gibt.
// Die Position des Statecaches im StateCache-Array
sal_uInt16 nCachePos = pImp->nMsgPos;
const SfxSlot *pSibling = pRealSlot->GetNextSlot();
// Die Slots eines Interfaces sind im Kreis verkettet
while ( pSibling > pRealSlot )
{
SfxStateFunc pSiblingFnc=0;
SfxStateCache *pSiblingCache =
GetStateCache( pSibling->GetSlotId(), &nCachePos );
// Ist der Slot "uberhaupt gecached ?
if ( pSiblingCache )
{
const SfxSlotServer *pServ = pSiblingCache->GetSlotServer(*pDispatcher, pImp->xProv);
if ( pServ && pServ->GetShellLevel() == nShellLevel )
pSiblingFnc = pServ->GetSlot()->GetStateFnc();
}
// Mu\s der Slot "uberhaupt upgedatet werden ?
bool bInsert = pSiblingCache && pSiblingCache->IsControllerDirty();
// Bugfix #26161#: Es reicht nicht, nach der selben Shell zu fragen !!
bool bSameMethod = pSiblingCache && pFnc == pSiblingFnc;
// Wenn der Slot ein nicht-dirty MasterSlot ist, dann ist vielleicht
// einer seiner Slaves dirty ? Dann wird der Masterslot doch eingef"ugt.
if ( !bInsert && bSameMethod && pSibling->GetLinkedSlot() )
{
// auch Slave-Slots auf Binding pru"fen
const SfxSlot* pFirstSlave = pSibling->GetLinkedSlot();
for ( const SfxSlot *pSlaveSlot = pFirstSlave;
!bInsert;
pSlaveSlot = pSlaveSlot->GetNextSlot())
{
// Die Slaves zeigen auf ihren Master
DBG_ASSERT(pSlaveSlot->GetLinkedSlot() == pSibling,
"Falsche Master/Slave-Beziehung!");
sal_uInt16 nCurMsgPos = pImp->nMsgPos;
const SfxStateCache *pSlaveCache =
GetStateCache( pSlaveSlot->GetSlotId(), &nCurMsgPos );
// Ist der Slave-Slot gecached und dirty ?
bInsert = pSlaveCache && pSlaveCache->IsControllerDirty();
// Slaves sind untereinander im Kreis verkettet
if (pSlaveSlot->GetNextSlot() == pFirstSlave)
break;
}
}
if ( bInsert && bSameMethod )
{
const SfxFoundCache_Impl *pFoundCache = new SfxFoundCache_Impl(
pSibling->GetSlotId(), pSibling->GetWhich(rPool),
pSibling, pSiblingCache );
rFound.Insert( pFoundCache );
}
pSibling = pSibling->GetNextSlot();
}
// aus den Ranges ein Set erzeugen
sal_uInt16 *pRanges = new sal_uInt16[rFound.Count() * 2 + 1];
int j = 0;
sal_uInt16 i = 0;
while ( i < rFound.Count() )
{
pRanges[j++] = rFound[i]->nWhichId;
// aufeinanderfolgende Zahlen
for ( ; i < rFound.Count()-1; ++i )
if ( rFound[i]->nWhichId+1 != rFound[i+1]->nWhichId )
break;
pRanges[j++] = rFound[i++]->nWhichId;
}
pRanges[j] = 0; // terminierende NULL
SfxItemSet *pSet = new SfxItemSet(rPool, pRanges);
delete [] pRanges;
DBG_PROFSTOP(SfxBindingsCreateSet);
return pSet;
}
//--------------------------------------------------------------------
void SfxBindings::UpdateControllers_Impl
(
const SfxInterface* pIF, // das diese Id momentan bedienende Interface
const SfxFoundCache_Impl* pFound, // Cache, Slot, Which etc.
const SfxPoolItem* pItem, // item to send to controller
SfxItemState eState // state of item
)
{
DBG_ASSERT( !pFound->pSlot || SFX_KIND_ENUM != pFound->pSlot->GetKind(),
"direct update of enum slot isn't allowed" );
DBG_PROFSTART(SfxBindingsUpdateCtrl1);
SfxStateCache* pCache = pFound->pCache;
const SfxSlot* pSlot = pFound->pSlot;
DBG_ASSERT( !pCache || !pSlot || pCache->GetId() == pSlot->GetSlotId(), "SID mismatch" );
// insofern gebunden, die Controller f"uer den Slot selbst updaten
if ( pCache && pCache->IsControllerDirty() )
{
if ( SFX_ITEM_DONTCARE == eState )
{
// uneindeuting
pCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 );
}
else if ( SFX_ITEM_DEFAULT == eState &&
pFound->nWhichId > SFX_WHICH_MAX )
{
// kein Status oder Default aber ohne Pool
SfxVoidItem aVoid(0);
pCache->SetState( SFX_ITEM_UNKNOWN, &aVoid );
}
else if ( SFX_ITEM_DISABLED == eState )
pCache->SetState(SFX_ITEM_DISABLED, 0);
else
pCache->SetState(SFX_ITEM_AVAILABLE, pItem);
}
DBG_PROFSTOP(SfxBindingsUpdateCtrl1);
// insofern vorhanden und gebunden, die Controller f"uer Slave-Slots
// (Enum-Werte) des Slots updaten
DBG_PROFSTART(SfxBindingsUpdateCtrl2);
DBG_ASSERT( !pSlot || 0 == pSlot->GetLinkedSlot() || !pItem ||
pItem->ISA(SfxEnumItemInterface),
"master slot with non-enum-type found" );
const SfxSlot *pFirstSlave = pSlot ? pSlot->GetLinkedSlot() : 0;
if ( pIF && pFirstSlave)
{
// Items auf EnumItem casten
const SfxEnumItemInterface *pEnumItem =
PTR_CAST(SfxEnumItemInterface,pItem);
if ( eState == SFX_ITEM_AVAILABLE && !pEnumItem )
eState = SFX_ITEM_DONTCARE;
else
eState = SfxControllerItem::GetItemState( pEnumItem );
// "uber alle Slaves-Slots iterieren
for ( const SfxSlot *pSlave = pFirstSlave; pSlave; pSlave = pSlave->GetNextSlot() )
{
DBG_ASSERT(pSlave, "Falsche SlaveSlot-Verkettung!");
DBG_ASSERT(SFX_KIND_ENUM == pSlave->GetKind(),"non enum slaves aren't allowed");
DBG_ASSERT(pSlave->GetMasterSlotId() == pSlot->GetSlotId(),"falscher MasterSlot!");
// ist die Funktion gebunden?
SfxStateCache *pEnumCache = GetStateCache( pSlave->GetSlotId() );
if ( pEnumCache )
{
pEnumCache->Invalidate(sal_False);
HACK(CONTROL/SELECT Kram)
if ( eState == SFX_ITEM_DONTCARE && pFound->nWhichId == 10144 )
{
SfxVoidItem aVoid(0);
pEnumCache->SetState( SFX_ITEM_UNKNOWN, &aVoid );
if (pSlave->GetNextSlot() == pFirstSlave)
break;
continue;
}
if ( SFX_ITEM_DISABLED == eState || !pEnumItem->IsEnabled( pSlave->GetSlotId()) )
{
// disabled
pEnumCache->SetState(SFX_ITEM_DISABLED, 0);
}
else if ( SFX_ITEM_AVAILABLE == eState )
{
// enum-Wert ermitteln
sal_uInt16 nValue = pEnumItem->GetEnumValue();
SfxBoolItem aBool( pFound->nWhichId, pSlave->GetValue() == nValue );
pEnumCache->SetState(SFX_ITEM_AVAILABLE, &aBool);
}
else
{
// uneindeuting
pEnumCache->SetState( SFX_ITEM_DONTCARE, (SfxPoolItem *)-1 );
}
}
if (pSlave->GetNextSlot() == pFirstSlave)
break;
}
}
DBG_PROFSTOP(SfxBindingsUpdateCtrl2);
}
//--------------------------------------------------------------------
IMPL_LINK( SfxBindings, NextJob_Impl, Timer *, pTimer )
{
#ifdef DBG_UTIL
// on Windows very often C++ Exceptions (GPF etc.) are caught by MSVCRT or another MS library
// try to get them here
try
{
#endif
const unsigned MAX_INPUT_DELAY = 200;
DBG_MEMTEST();
DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
DBG_PROFSTART(SfxBindingsNextJob_Impl0);
if ( Application::GetLastInputInterval() < MAX_INPUT_DELAY && pTimer )
{
pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
return sal_True;
}
SfxApplication *pSfxApp = SFX_APP();
if( pDispatcher )
pDispatcher->Update_Impl();
// modifying the SfxObjectInterface-stack without SfxBindings => nothing to do
SfxViewFrame* pFrame = pDispatcher->GetFrame();
//<!--Modified by PengYunQuan for Validity Cell Range Picker
//if ( (pFrame && pFrame->GetObjectShell()->IsInModalMode()) || pSfxApp->IsDowning() || !pImp->pCaches->Count() )
if ( (pFrame && !pFrame->GetObjectShell()->AcceptStateUpdate()) || pSfxApp->IsDowning() || !pImp->pCaches->Count() )
//-->Modified by PengYunQuan for Validity Cell Range Picker
{
DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
return sal_True;
}
if ( !pDispatcher || !pDispatcher->IsFlushed() )
{
DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
return sal_True;
}
// gfs. alle Server aktualisieren / geschieht in eigener Zeitscheibe
if ( pImp->bMsgDirty )
{
UpdateSlotServer_Impl();
DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
return sal_False;
}
DBG_PROFSTOP(SfxBindingsNextJob_Impl0);
DBG_PROFSTART(SfxBindingsNextJob_Impl);
pImp->bAllDirty = sal_False;
pImp->aTimer.SetTimeout(TIMEOUT_UPDATING);
// at least 10 loops and further if more jobs are available but no input
bool bPreEmptive = pTimer && !pSfxApp->Get_Impl()->nInReschedule;
sal_uInt16 nLoops = 10;
pImp->bInNextJob = sal_True;
const sal_uInt16 nCount = pImp->pCaches->Count();
while ( pImp->nMsgPos < nCount )
{
// iterate through the bound functions
sal_Bool bJobDone = sal_False;
while ( !bJobDone )
{
SfxStateCache* pCache = (*pImp->pCaches)[pImp->nMsgPos];
DBG_ASSERT( pCache, "invalid SfxStateCache-position in job queue" );
sal_Bool bWasDirty = pCache->IsControllerDirty();
if ( bWasDirty )
{
/*
sal_Bool bSkip = sal_False;
if ( pImp->bFirstRound )
{
// Falls beim Update eine Shell vorgezogen werden soll,
// kommt in einer ersten Update-Runde nur diese dran
const SfxSlotServer *pMsgServer =
pCache->GetSlotServer(*pDispatcher, pImp->xProv);
if ( pMsgServer &&
pMsgServer->GetShellLevel() != pImp->nFirstShell )
bSkip = sal_True;
}
if ( !bSkip )
{
*/
Update_Impl( pCache );
DBG_ASSERT( nCount == pImp->pCaches->Count(),
"Reschedule in StateChanged => buff" );
// }
}
// skip to next function binding
++pImp->nMsgPos;
// keep job if it is not completed, but any input is available
bJobDone = pImp->nMsgPos >= nCount;
if ( bJobDone && pImp->bFirstRound )
{
// Update der bevorzugten Shell ist gelaufen, nun d"urfen
// auch die anderen
bJobDone = sal_False;
pImp->bFirstRound = sal_False;
pImp->nMsgPos = 0;
}
if ( bWasDirty && !bJobDone && bPreEmptive && (--nLoops == 0) )
{
DBG_PROFSTOP(SfxBindingsNextJob_Impl);
pImp->bInNextJob = sal_False;
return sal_False;
}
}
}
pImp->nMsgPos = 0;
// check for volatile slots
bool bVolatileSlotsPresent = false;
for ( sal_uInt16 n = 0; n < nCount; ++n )
{
SfxStateCache* pCache = (*pImp->pCaches)[n];
const SfxSlotServer *pSlotServer = pCache->GetSlotServer(*pDispatcher, pImp->xProv);
if ( pSlotServer && pSlotServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) )
{
pCache->Invalidate(sal_False);
bVolatileSlotsPresent = true;
}
}
if (bVolatileSlotsPresent)
pImp->aTimer.SetTimeout(TIMEOUT_IDLE);
else
pImp->aTimer.Stop();
// Update-Runde ist beendet
pImp->bInNextJob = sal_False;
Broadcast(SfxSimpleHint(SFX_HINT_UPDATEDONE));
DBG_PROFSTOP(SfxBindingsNextJob_Impl);
return sal_True;
#ifdef DBG_UTIL
}
catch (...)
{
DBG_ERROR("C++ exception caught!");
pImp->bInNextJob = sal_False;
}
return sal_False;
#endif
}
//--------------------------------------------------------------------
sal_uInt16 SfxBindings::EnterRegistrations(const char *pFile, int nLine)
{
(void)pFile;
(void)nLine;
DBG_MEMTEST();
#ifdef DBG_UTIL
ByteString aMsg;
aMsg.Fill( Min(nRegLevel, sal_uInt16(8) ) );
aMsg += "this = ";
aMsg += ByteString::CreateFromInt32((long)this);
aMsg += " Level = ";
aMsg += ByteString::CreateFromInt32(nRegLevel);
aMsg += " SfxBindings::EnterRegistrations ";
if(pFile) {
aMsg += "File: ";
aMsg += pFile;
aMsg += " Line: ";
aMsg += ByteString::CreateFromInt32(nLine);
}
// FILE* pLog = fopen( "c:\\bindings.log", "a+w" );
// fwrite( aMsg.GetBuffer(), 1, aMsg.Len(), pLog );
// fclose( pLog );
DbgTrace( aMsg.GetBuffer() );
#endif
// Wenn Bindings gelockt werden, auch SubBindings locken
if ( pImp->pSubBindings )
{
pImp->pSubBindings->ENTERREGISTRATIONS();
// Dieses EnterRegistrations ist f"ur die SubBindings kein "echtes"
pImp->pSubBindings->pImp->nOwnRegLevel--;
// Bindings synchronisieren
pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel + 1;
}
pImp->nOwnRegLevel++;
// check if this is the outer most level
if ( ++nRegLevel == 1 )
{
// stop background-processing
pImp->aTimer.Stop();
// flush the cache
pImp->nCachedFunc1 = 0;
pImp->nCachedFunc2 = 0;
// merken, ob ganze Caches verschwunden sind
pImp->bCtrlReleased = sal_False;
}
return nRegLevel;
}
//--------------------------------------------------------------------
void SfxBindings::LeaveRegistrations( sal_uInt16 nLevel, const char *pFile, int nLine )
{
(void)nLevel; // unused variable
(void)pFile;
(void)nLine;
DBG_MEMTEST();
DBG_ASSERT( nRegLevel, "Leave without Enter" );
DBG_ASSERT( nLevel == USHRT_MAX || nLevel == nRegLevel, "wrong Leave" );
// Nur wenn die SubBindings noch von den SuperBindings gelockt sind, diesen Lock entfernen
// ( d.h. wenn es mehr Locks als "echte" Locks dort gibt )
if ( pImp->pSubBindings && pImp->pSubBindings->nRegLevel > pImp->pSubBindings->pImp->nOwnRegLevel )
{
// Bindings synchronisieren
pImp->pSubBindings->nRegLevel = nRegLevel + pImp->pSubBindings->pImp->nOwnRegLevel;
// Dieses LeaveRegistrations ist f"ur die SubBindings kein "echtes"
pImp->pSubBindings->pImp->nOwnRegLevel++;
pImp->pSubBindings->LEAVEREGISTRATIONS();
}
pImp->nOwnRegLevel--;
// check if this is the outer most level
if ( --nRegLevel == 0 && !SFX_APP()->IsDowning() )
{
if ( pImp->bContextChanged )
{
pImp->bContextChanged = sal_False;
/*
::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame
( pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
if ( xFrame.is() )
xFrame->contextChanged();*/
}
#ifndef slow
SfxViewFrame* pFrame = pDispatcher->GetFrame();
// ggf unbenutzte Caches entfernen bzw. PlugInInfo aufbereiten
if ( pImp->bCtrlReleased )
{
for ( sal_uInt16 nCache = pImp->pCaches->Count(); nCache > 0; --nCache )
{
// Cache via ::com::sun::star::sdbcx::Index besorgen
SfxStateCache *pCache = pImp->pCaches->GetObject(nCache-1);
// kein Controller mehr interessiert
if ( pCache->GetItemLink() == 0 && !pCache->GetInternalController() )
{
// Cache entfernen. Safety: first remove and then delete
SfxStateCache* pSfxStateCache = (*pImp->pCaches)[nCache-1];
pImp->pCaches->Remove(nCache-1, 1);
delete pSfxStateCache;
}
else
{
// neue Controller mit den alten Items benachrichtigen
//!pCache->SetCachedState();
}
}
}
#endif
// restart background-processing
pImp->nMsgPos = 0;
if ( !pFrame || !pFrame->GetObjectShell() )
return;
if ( pImp->pCaches && pImp->pCaches->Count() )
{
pImp->aTimer.Stop();
pImp->aTimer.SetTimeout(TIMEOUT_FIRST);
pImp->aTimer.Start();
// pImp->bFirstRound = sal_True;
}
}
#ifdef DBG_UTIL
ByteString aMsg;
aMsg.Fill( Min(nRegLevel, sal_uInt16(8)) );
aMsg += "this = ";
aMsg += ByteString::CreateFromInt32((long)this);
aMsg += " Level = ";
aMsg += ByteString::CreateFromInt32(nRegLevel);
aMsg += " SfxBindings::LeaveRegistrations ";
if(pFile) {
aMsg += "File: ";
aMsg += pFile;
aMsg += " Line: ";
aMsg += ByteString::CreateFromInt32(nLine);
}
// FILE* pLog = fopen( "c:\\bindings.log", "a+w" );
// fwrite( aMsg.GetBuffer(), 1, aMsg.Len(), pLog );
// fclose( pLog );
DbgTrace( aMsg.GetBuffer() );
#endif
}
//--------------------------------------------------------------------
const SfxSlot* SfxBindings::GetSlot(sal_uInt16 nSlotId)
{
DBG_MEMTEST();
DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" );
// syncronisieren
pDispatcher->Flush();
if ( pImp->bMsgDirty )
UpdateSlotServer_Impl();
// get the cache for the specified function; return if not bound
SfxStateCache* pCache = GetStateCache(nSlotId);
return pCache && pCache->GetSlotServer(*pDispatcher, pImp->xProv)?
pCache->GetSlotServer(*pDispatcher, pImp->xProv)->GetSlot(): 0;
}
//--------------------------------------------------------------------
void SfxBindings::SetDispatcher( SfxDispatcher *pDisp )
{
SfxDispatcher *pOldDispat = pDispatcher;
if ( pDisp != pDispatcher )
{
if ( pOldDispat )
{
SfxBindings* pBind = pOldDispat->GetBindings();
while ( pBind )
{
if ( pBind->pImp->pSubBindings == this && pBind->pDispatcher != pDisp )
pBind->SetSubBindings_Impl( NULL );
pBind = pBind->pImp->pSubBindings;
}
}
pDispatcher = pDisp;
::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider > xProv;
if ( pDisp )
xProv = ::com::sun::star::uno::Reference < ::com::sun::star::frame::XDispatchProvider >
( pDisp->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY );
SetDispatchProvider_Impl( xProv );
InvalidateAll( sal_True );
InvalidateUnoControllers_Impl();
if ( pDispatcher && !pOldDispat )
{
if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
{
DBG_ERROR( "SubBindings vor Aktivieren schon gesetzt!" );
pImp->pSubBindings->ENTERREGISTRATIONS();
}
LEAVEREGISTRATIONS();
}
else if( !pDispatcher )
{
ENTERREGISTRATIONS();
if ( pImp->pSubBindings && pImp->pSubBindings->pDispatcher != pOldDispat )
{
DBG_ERROR( "SubBindings im Deaktivieren immer noch gesetzt!" );
pImp->pSubBindings->LEAVEREGISTRATIONS();
}
}
Broadcast( SfxSimpleHint( SFX_HINT_DATACHANGED ) );
if ( pDisp )
{
SfxBindings* pBind = pDisp->GetBindings();
while ( pBind && pBind != this )
{
if ( !pBind->pImp->pSubBindings )
{
pBind->SetSubBindings_Impl( this );
break;
}
pBind = pBind->pImp->pSubBindings;
}
}
}
}
//--------------------------------------------------------------------
void SfxBindings::ClearCache_Impl( sal_uInt16 nSlotId )
{
GetStateCache(nSlotId)->ClearCache();
}
//--------------------------------------------------------------------
void SfxBindings::StartUpdate_Impl( sal_Bool bComplete )
{
if ( pImp->pSubBindings )
pImp->pSubBindings->StartUpdate_Impl( bComplete );
if ( !bComplete )
// Update darf unterbrochen werden
NextJob_Impl(&pImp->aTimer);
else
// alle Slots am St"uck updaten
NextJob_Impl(0);
}
//-------------------------------------------------------------------------
SfxItemState SfxBindings::QueryState( sal_uInt16 nSlot, SfxPoolItem* &rpState )
{
::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
SfxStateCache *pCache = GetStateCache( nSlot );
if ( pCache )
xDisp = pCache->GetDispatch();
if ( xDisp.is() || !pCache )
{
const SfxSlot* pSlot = SfxSlotPool::GetSlotPool( pDispatcher->GetFrame() ).GetSlot( nSlot );
if ( !pSlot || !pSlot->pUnoName )
return SFX_ITEM_DISABLED;
::com::sun::star::util::URL aURL;
::rtl::OUString aCmd( DEFINE_CONST_UNICODE(".uno:"));
aURL.Protocol = aCmd;
aURL.Path = ::rtl::OUString::createFromAscii(pSlot->GetUnoName());
aCmd += aURL.Path;
aURL.Complete = aCmd;
aURL.Main = aCmd;
if ( !xDisp.is() )
xDisp = pImp->xProv->queryDispatch( aURL, ::rtl::OUString(), 0 );
if ( xDisp.is() )
{
::com::sun::star::uno::Reference< ::com::sun::star::lang::XUnoTunnel > xTunnel( xDisp, ::com::sun::star::uno::UNO_QUERY );
SfxOfficeDispatch* pDisp = NULL;
if ( xTunnel.is() )
{
sal_Int64 nImplementation = xTunnel->getSomething(SfxOfficeDispatch::impl_getStaticIdentifier());
pDisp = reinterpret_cast< SfxOfficeDispatch* >( sal::static_int_cast< sal_IntPtr >( nImplementation ));
}
if ( !pDisp )
{
sal_Bool bDeleteCache = sal_False;
if ( !pCache )
{
pCache = new SfxStateCache( nSlot );
pCache->GetSlotServer( *GetDispatcher_Impl(), pImp->xProv );
bDeleteCache = sal_True;
}
SfxItemState eState = SFX_ITEM_SET;
SfxPoolItem *pItem=NULL;
BindDispatch_Impl *pBind = new BindDispatch_Impl( xDisp, aURL, pCache, pSlot );
pBind->acquire();
xDisp->addStatusListener( pBind, aURL );
if ( !pBind->GetStatus().IsEnabled )
{
eState = SFX_ITEM_DISABLED;
}
else
{
::com::sun::star::uno::Any aAny = pBind->GetStatus().State;
::com::sun::star::uno::Type pType = aAny.getValueType();
if ( pType == ::getBooleanCppuType() )
{
sal_Bool bTemp = false;
aAny >>= bTemp ;
pItem = new SfxBoolItem( nSlot, bTemp );
}
else if ( pType == ::getCppuType((const sal_uInt16*)0) )
{
sal_uInt16 nTemp = 0;
aAny >>= nTemp ;
pItem = new SfxUInt16Item( nSlot, nTemp );
}
else if ( pType == ::getCppuType((const sal_uInt32*)0) )
{
sal_uInt32 nTemp = 0;
aAny >>= nTemp ;
pItem = new SfxUInt32Item( nSlot, nTemp );
}
else if ( pType == ::getCppuType((const ::rtl::OUString*)0) )
{
::rtl::OUString sTemp ;
aAny >>= sTemp ;
pItem = new SfxStringItem( nSlot, sTemp );
}
else
pItem = new SfxVoidItem( nSlot );
}
xDisp->removeStatusListener( pBind, aURL );
pBind->Release();
rpState = pItem;
if ( bDeleteCache )
DELETEZ( pCache );
return eState;
}
}
}
// Dann am Dispatcher testen; da die von dort zur"uckgegebenen Items immer
// DELETE_ON_IDLE sind, mu\s eine Kopie davon gezogen werden, um einen
// Eigent"umer"ubergang zu erm"oglichen
const SfxPoolItem *pItem = NULL;
SfxItemState eState = pDispatcher->QueryState( nSlot, pItem );
if ( eState == SFX_ITEM_SET )
{
DBG_ASSERT( pItem, "SFX_ITEM_SET aber kein Item!" );
if ( pItem )
rpState = pItem->Clone();
}
else if ( eState == SFX_ITEM_AVAILABLE && pItem )
{
rpState = pItem->Clone();
}
return eState;
}
void SfxBindings::SetSubBindings_Impl( SfxBindings *pSub )
{
if ( pImp->pSubBindings )
{
pImp->pSubBindings->SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > () );
pImp->pSubBindings->pImp->pSuperBindings = NULL;
}
pImp->pSubBindings = pSub;
if ( pSub )
{
pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
pSub->pImp->pSuperBindings = this;
}
}
SfxBindings* SfxBindings::GetSubBindings_Impl( sal_Bool bTop ) const
{
SfxBindings *pRet = pImp->pSubBindings;
if ( bTop )
{
while ( pRet->pImp->pSubBindings )
pRet = pRet->pImp->pSubBindings;
}
return pRet;
}
void SfxBindings::SetWorkWindow_Impl( SfxWorkWindow* pWork )
{
pImp->pWorkWin = pWork;
}
SfxWorkWindow* SfxBindings::GetWorkWindow_Impl() const
{
return pImp->pWorkWin;
}
void SfxBindings::RegisterUnoController_Impl( SfxUnoControllerItem* pControl )
{
if ( !pImp->pUnoCtrlArr )
pImp->pUnoCtrlArr = new SfxUnoControllerArr_Impl;
pImp->pUnoCtrlArr->Insert( pControl, pImp->pUnoCtrlArr->Count() );
}
void SfxBindings::ReleaseUnoController_Impl( SfxUnoControllerItem* pControl )
{
if ( pImp->pUnoCtrlArr )
{
sal_uInt16 nPos = pImp->pUnoCtrlArr->GetPos( pControl );
if ( nPos != 0xFFFF )
{
pImp->pUnoCtrlArr->Remove( nPos );
return;
}
}
if ( pImp->pSubBindings )
pImp->pSubBindings->ReleaseUnoController_Impl( pControl );
}
void SfxBindings::InvalidateUnoControllers_Impl()
{
if ( pImp->pUnoCtrlArr )
{
sal_uInt16 nCount = pImp->pUnoCtrlArr->Count();
for ( sal_uInt16 n=nCount; n>0; n-- )
{
SfxUnoControllerItem *pCtrl = (*pImp->pUnoCtrlArr)[n-1];
::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > xRef( (::cppu::OWeakObject*)pCtrl, ::com::sun::star::uno::UNO_QUERY );
pCtrl->ReleaseDispatch();
pCtrl->GetNewDispatch();
}
}
if ( pImp->pSubBindings )
pImp->pSubBindings->InvalidateUnoControllers_Impl();
}
sal_Bool SfxBindings::IsInUpdate() const
{
sal_Bool bInUpdate = pImp->bInUpdate;
if ( !bInUpdate && pImp->pSubBindings )
bInUpdate = pImp->pSubBindings->IsInUpdate();
return bInUpdate;
}
void SfxBindings::SetVisibleState( sal_uInt16 nId, sal_Bool bShow )
{
::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp;
SfxStateCache *pCache = GetStateCache( nId );
if ( pCache )
pCache->SetVisibleState( bShow );
}
void SfxBindings::SetActiveFrame( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > & rFrame )
{
if ( rFrame.is() || !pDispatcher )
SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > ( rFrame, ::com::sun::star::uno::UNO_QUERY ) );
else
SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > (
pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), ::com::sun::star::uno::UNO_QUERY ) );
}
const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > SfxBindings::GetActiveFrame() const
{
const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame( pImp->xProv, ::com::sun::star::uno::UNO_QUERY );
if ( xFrame.is() || !pDispatcher )
return xFrame;
else
return pDispatcher->GetFrame()->GetFrame().GetFrameInterface();
}
void SfxBindings::SetDispatchProvider_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & rProv )
{
sal_Bool bInvalidate = ( rProv != pImp->xProv );
if ( bInvalidate )
{
pImp->xProv = rProv;
InvalidateAll( sal_True );
InvalidateUnoControllers_Impl();
}
if ( pImp->pSubBindings )
pImp->pSubBindings->SetDispatchProvider_Impl( pImp->xProv );
}
const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & SfxBindings::GetDispatchProvider_Impl() const
{
return pImp->xProv;
}
SystemWindow* SfxBindings::GetSystemWindow() const
{
SfxViewFrame *pFrame = pDispatcher->GetFrame();
while ( pFrame->GetParentViewFrame_Impl() )
pFrame = pFrame->GetParentViewFrame_Impl();
SfxViewFrame* pTop = pFrame->GetTopViewFrame();
return pTop->GetFrame().GetTopWindow_Impl();
}
sal_Bool SfxBindings::ExecuteCommand_Impl( const String& rCommand )
{
::com::sun::star::util::URL aURL;
aURL.Complete = rCommand;
Reference < XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY );
xTrans->parseStrict( aURL );
::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp = pImp->xProv->queryDispatch( aURL, ::rtl::OUString(), 0 );
if ( xDisp.is() )
{
if(::comphelper::UiEventsLogger::isEnabled()) //#i88653#
{
::rtl::OUString sAppName;
try
{
static ::rtl::OUString our_aModuleManagerName = ::rtl::OUString::createFromAscii("com.sun.star.frame.ModuleManager");
::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceManager =
::comphelper::getProcessServiceFactory();
::com::sun::star::uno::Reference< ::com::sun::star::frame::XModuleManager > xModuleManager(
xServiceManager->createInstance(our_aModuleManagerName)
, ::com::sun::star::uno::UNO_QUERY_THROW);
::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > xFrame(
pDispatcher->GetFrame()->GetFrame().GetFrameInterface(), UNO_QUERY_THROW);
sAppName = xModuleManager->identify(xFrame);
} catch(::com::sun::star::uno::Exception&) {}
Sequence<beans::PropertyValue> source;
::comphelper::UiEventsLogger::appendDispatchOrigin(source, sAppName, ::rtl::OUString::createFromAscii("SfxAsyncExec"));
::comphelper::UiEventsLogger::logDispatch(aURL, source);
}
new SfxAsyncExec_Impl( aURL, xDisp );
return sal_True;
}
return sal_False;
}
com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder > SfxBindings::GetRecorder() const
{
return pImp->xRecorder;
}
void SfxBindings::SetRecorder_Impl( com::sun::star::uno::Reference< com::sun::star::frame::XDispatchRecorder >& rRecorder )
{
pImp->xRecorder = rRecorder;
}
void SfxBindings::ContextChanged_Impl()
{
if ( !pImp->bInUpdate && ( !pImp->bContextChanged || !pImp->bAllMsgDirty ) )
{
InvalidateAll( sal_True );
}
}
uno::Reference < frame::XDispatch > SfxBindings::GetDispatch( const SfxSlot* pSlot, const util::URL& aURL, sal_Bool bMasterCommand )
{
uno::Reference < frame::XDispatch > xRet;
SfxStateCache* pCache = GetStateCache( pSlot->nSlotId );
if ( pCache && !bMasterCommand )
xRet = pCache->GetInternalDispatch();
if ( !xRet.is() )
{
// dispatches for slaves are unbound, they don't have a state
SfxOfficeDispatch* pDispatch = bMasterCommand ?
new SfxOfficeDispatch( pDispatcher, pSlot, aURL ) :
new SfxOfficeDispatch( *this, pDispatcher, pSlot, aURL );
pDispatch->SetMasterUnoCommand( bMasterCommand );
xRet = uno::Reference < frame::XDispatch >( pDispatch );
if ( !pCache )
pCache = GetStateCache( pSlot->nSlotId );
DBG_ASSERT( pCache, "No cache for OfficeDispatch!" );
if ( pCache && !bMasterCommand )
pCache->SetInternalDispatch( xRet );
}
return xRet;
}