diff options
author | Jens-Heiner Rechtien <hr@openoffice.org> | 2000-09-18 16:07:07 +0000 |
---|---|---|
committer | Jens-Heiner Rechtien <hr@openoffice.org> | 2000-09-18 16:07:07 +0000 |
commit | fd069bee7e57ad529c3c0974559fd2d84ec3151a (patch) | |
tree | ef2eddeefb786feaf966d6a1c0c291872c0ae420 /sfx2/source/control | |
parent | 04c1c754ab9d0ad07f2c5362d46597d13efe75c2 (diff) |
initial import
Diffstat (limited to 'sfx2/source/control')
-rw-r--r-- | sfx2/source/control/bindings.cxx | 3022 | ||||
-rw-r--r-- | sfx2/source/control/ctrlitem.cxx | 480 | ||||
-rw-r--r-- | sfx2/source/control/dispatch.cxx | 3493 | ||||
-rw-r--r-- | sfx2/source/control/macrconf.cxx | 947 | ||||
-rw-r--r-- | sfx2/source/control/macro.cxx | 858 | ||||
-rw-r--r-- | sfx2/source/control/makefile.mk | 120 | ||||
-rw-r--r-- | sfx2/source/control/minfitem.cxx | 136 | ||||
-rw-r--r-- | sfx2/source/control/msg.cxx | 101 | ||||
-rw-r--r-- | sfx2/source/control/msgpool.cxx | 627 | ||||
-rw-r--r-- | sfx2/source/control/objface.cxx | 1427 | ||||
-rw-r--r-- | sfx2/source/control/request.cxx | 576 | ||||
-rw-r--r-- | sfx2/source/control/shell.cxx | 1524 | ||||
-rw-r--r-- | sfx2/source/control/srchitem.cxx | 306 | ||||
-rw-r--r-- | sfx2/source/control/statcach.cxx | 577 | ||||
-rw-r--r-- | sfx2/source/control/unoctitm.cxx | 560 |
15 files changed, 14754 insertions, 0 deletions
diff --git a/sfx2/source/control/bindings.cxx b/sfx2/source/control/bindings.cxx new file mode 100644 index 000000000000..ea5e1a3f7c67 --- /dev/null +++ b/sfx2/source/control/bindings.cxx @@ -0,0 +1,3022 @@ +/************************************************************************* + * + * $RCSfile: bindings.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SFXITEMPOOL_HXX //autogen +#include <svtools/itempool.hxx> +#endif +#ifndef _SFXITEMITER_HXX //autogen +#include <svtools/itemiter.hxx> +#endif +#ifndef _SFXENUMITEM_HXX //autogen +#include <svtools/eitem.hxx> +#endif +#ifndef _AEITEM_HXX //autogen +#include <svtools/aeitem.hxx> +#endif +#include <svtools/intitem.hxx> +#include <svtools/stritem.hxx> + +#ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_ +#include <com/sun/star/util/XURLTransformer.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XDISPATCHPROVIDERINTERCEPTOR_HPP_ +#include <com/sun/star/frame/XDispatchProviderInterceptor.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XDISPATCH_HPP_ +#include <com/sun/star/frame/XDispatch.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XDISPATCHPROVIDER_HPP_ +#include <com/sun/star/frame/XDispatchProvider.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XSTATUSLISTENER_HPP_ +#include <com/sun/star/frame/XStatusListener.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_FRAMESEARCHFLAG_HPP_ +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XDISPATCHPROVIDERINTERCEPTION_HPP_ +#include <com/sun/star/frame/XDispatchProviderInterception.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_FEATURESTATEEVENT_HPP_ +#include <com/sun/star/frame/FeatureStateEvent.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_DISPATCHDESCRIPTOR_HPP_ +#include <com/sun/star/frame/DispatchDescriptor.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XCONTROLLER_HPP_ +#include <com/sun/star/frame/XController.hpp> +#endif +#include <unotools/processfactory.hxx> + +#pragma hdrstop + +#include "ipfrm.hxx" +#include "ipenv.hxx" +#include "interno.hxx" +#include "bindings.hxx" +#include "msg.hxx" +#include "statcach.hxx" +#include "ctrlitem.hxx" +#include "app.hxx" +#include "appdata.hxx" +#include "dispatch.hxx" +#include "request.hxx" +#include "objface.hxx" +#include "sfxtypes.hxx" +#include "workwin.hxx" +#include "macrconf.hxx" +#include "unoctitm.hxx" +#include "sfx.hrc" +#include "sfxuno.hxx" +#include "topfrm.hxx" + +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); + +//==================================================================== + +#define TIMEOUT_FIRST 20 +#define TIMEOUT_UPDATING 0 +#define TIMEOUT_IDLE 2500 + +static sal_uInt32 nCache1 = 0; +static sal_uInt32 nCache2 = 0; + +//==================================================================== +//TYPEINIT1(SfxSlotInterceptorItem, SfxPoolItem); + +DECL_PTRARRAY(SfxStateCacheArr_Impl, SfxStateCache*, 32, 16); +DECL_PTRARRAY(SfxInterceptorArr_Impl, SfxSlotInterceptor*, 2, 2); + +//==================================================================== + +struct SfxSlotInterceptor_Impl +{ + SfxBindings* _pBindings; + sal_Bool _bIsActive; +}; + +//==================================================================== + +class SfxBindings_Impl + +/* [Beschreibung] + + Diese Implementations-Struktur der Klasse SfxBindings dient + der Entkopplung von "Anderungen vom exportierten Interface sowie + der Verringerung von extern sichtbaren Symbolen. + + Eine Instanz exisitiert pro SfxBindings-Instanz f"ur deren Laufzeit. +*/ + +{ +public: + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv; + SfxUnoControllerArr_Impl* + pUnoCtrlArr; + SfxWorkWindow* pWorkWin; + SfxBindings* pSubBindings; + SfxBindings* pSuperBindings; + SfxInterceptorArr_Impl* pInterceptors; // Slots vor dem Dispatcher abfangen + 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 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_Bool bInExecute; // zum Test auf synchrone Executes + sal_uInt16 nOwnRegLevel; // z"ahlt die echten Locks, ohne die der SuperBindings + + void InsertSlotInterceptor( SfxSlotInterceptor* ); + void RemoveSlotInterceptor( SfxSlotInterceptor* ); +}; + +void SfxBindings_Impl::InsertSlotInterceptor( SfxSlotInterceptor* pInter ) +{ + // ggf. Interceptor-Liste on-demand erzeugen + if ( !pInterceptors ) + pInterceptors = new SfxInterceptorArr_Impl; + pInterceptors->Insert( 0, pInter ); + + if ( pSubBindings ) + pSubBindings->pImp->InsertSlotInterceptor( pInter ); +} + +void SfxBindings_Impl::RemoveSlotInterceptor( SfxSlotInterceptor* pInter ) +{ + // bei den Bindings austragen + pInterceptors->Remove( pInter ); + + // gar kein SfxSlotInterceptor mehr => auf 0 setzen (f"ur Schnellabfrage) + if ( !pInterceptors->Count() ) + DELETEZ( pInterceptors ); + + if ( pSubBindings ) + pSubBindings->pImp->RemoveSlotInterceptor( pInter ); +} + +//-------------------------------------------------------------------- + +struct SfxFoundCache_Impl + +/* [Beschreibung] + + In Instanzen dieser Struktur werden in <SfxBindings::CreateSet_Impl()> + weitere Informationen zu den gemeinsam von einem <Slot-Server> zu + erfragenden Status gesammelt, deren Ids dort in die Ranges eines + <SfxItemSet>s aufgenommen werden. + + Diese Informationen werden w"ahrend der Suche nach den zusammen + upzudatenden Ids sowieso als Zwischenergebnis ermittelt und nachher + wieder ben"otigt, daher macht es Sinn, sie f"ur diesen kurzen Zeitraum + gleich aufzubewahren. +*/ + +{ + 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; } const + + int operator==( const SfxFoundCache_Impl &r ) + { 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() + +/* [Beschreibung] + + Konstruktor der Klasse SfxBindings. Genau eine Instanz wird automatisch + von der <SfxApplication> vor <SfxApplication::Init()> angelegt. Wird + eine Instanz ben"otigt, z.B. zum Invalidieren von Slots, sollte diese + "uber den zugeh"origen <SfxViewFrame> besorgt werden. Bestimmte + SfxViewFrame Subklassen (z.B. <SfxInPlaceFrame>) legen ihre eigene + Instanz der SfxBindings an. + + <SfxControllerItem> Instanzen k"onnen erst angelegt werden, wenn + die zugeh"orige SfxBindings Instanz existiert. +*/ + +: pImp(new SfxBindings_Impl), + pDispatcher(0), + nRegLevel(1) // geht erst auf 0, wenn Dispatcher gesetzt +{ + pImp->nMsgPos = 0; + pImp->bAllMsgDirty = sal_True; + 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->bInExecute = 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) ); + pImp->pInterceptors = 0; +} + +//==================================================================== + +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); + + delete pImp->pCaches; + delete pImp; +} + +//-------------------------------------------------------------------- + +void SfxBindings::DeleteControllers_Impl() + +/* [Beschreibung] + + Interne Methode zum l"oschen noch existierender <SfxControllerItem> + Instanzen, die bei dieser SfxBindings Instanz angemeldet sind. + + Dies sind i.d.R. <SfxPopupWindow>s. Nich sich selbst geh"orende + SfxControllerItems d"urfen bei Aufruf nur noch existieren, wenn sie + einem der restlichen SfxPopupWindows geh"oren. + + + [Anmerkung] + + Wird beim Beenden der Applikation gerufen, bevor das Applikations- + Fenster gel"oscht wird. +*/ + +{ + // 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(); + } + + // 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 nCount = pImp->pUnoCtrlArr->Count(); + for ( sal_uInt16 n=nCount; 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( FASTBOOL bHide ) + +/* [Beschreibung] + + Dieser Methode versteckt und zeigt die <SfxPopupWindows>, die aus + <SfxToolboxControl>s dieser SfxBindings-Instanz abgerissen wurden bzw. + floating <SfxChildWindow>-Instanzen dieser SfxBindings-Instanz. + + + [Anmerkung] + + Es k"onnten noch weitere Floating-Windows exisitieren, die durch + diese Methode nicht erfa\st werden. +*/ + +{ + // 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 +) + +/* [Beschreibung] + + Interne Methode zum Updaten eines Caches und den von derselben + Status-Methode in derselben Shell bedienten und dirty Slots. +*/ + +{ + if( pCache->GetDispatch().is() && pCache->GetItemLink() ) + { + pCache->SetCachedState(); + 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 aFound( pCache->GetId(), 0, + pRealSlot, pCache ); + UpdateControllers_Impl( 0, &aFound, 0, SFX_ITEM_DISABLED); + } + + DBG_PROFSTOP(SfxBindingsUpdate_Impl); +} + +//-------------------------------------------------------------------- + +void SfxBindings::Update +( + sal_uInt16 nId // die gebundene und upzudatende Slot-Id +) + +/* [Beschreibung] + + Diese Methode sorgt f"ur synchrones Updaten der auf die Slot-Id nId + gebundenen <SfxContollerItem> Instanzen, die an dieser SfxBindings + Instanz angemeldet sind. Vergleichbar zu Window::Update() + (StarView) erfolgt ein Update nur, wenn entweder ein auf diese + Slot-Id gebundenes SfxContollerItem dirty ist, oder die Slot-Id + selbst dirty ist. Dies kann durch einen vorhergehendes Aufruf von + <SfxBindings::Invalidate(sal_uInt16)> erzwungen werden. + + + [Anmerkung] + + Es ist g"unstiger, zun"achst alle zu invalidierenden Slot-Ids per + <SfxBindings::Invalidate(sal_uInt16)> zu invalidieren und dann + Update() aufzurufen, als einzelne abwechselnde Invalidate/Update, + da von derselben Status-Methode bediente Status-Anfragen von + den SfxBindings automatisch zusammengefa"st werden. + + + [Querverweise] + + <SfxShell::Invalidate(sal_uInt16)> + <SfxBindings::Invalidate(sal_uInt16)> + <SfxBindings::InvalidateAll(sal_Bool)> + <SfxBindings::Update()> +*/ + +{ + 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) + { + if( pCache->GetDispatch().is() && pCache->GetItemLink() ) + { + pCache->SetCachedState(); + } + else + { + // Status erfragen + const SfxSlotServer* pMsgServer = + pCache->GetSlotServer(*pDispatcher, pImp->xProv); + if ( !pCache->IsControllerDirty() && + ( !pMsgServer || + !pMsgServer->GetSlot()->IsMode(SFX_SLOT_VOLATILE) ) ) + { + pImp->bInUpdate = sal_False; + return; + } + if (!pMsgServer) + { + pCache->SetState(SFX_ITEM_DISABLED, 0); + pImp->bInUpdate = sal_False; + return; + } + + Update_Impl(pCache); + } + + pImp->bAllDirty = sal_False; + } + + pImp->bInUpdate = sal_False; + } +} + +//-------------------------------------------------------------------- + +void SfxBindings::Update() + +/* [Beschreibung] + + Diese Methode sorgt f"ur synchrones Updaten aller <SfxContollerItem> + Instanzen, die an dieser SfxBindings Instanz angemeldet sind. Vergleichbar + zu Window::Update() (StarView) erfolgt ein Update nur, wenn entweder ein + SfxContollerItem dirty ist, in einem Status-Cache der Zeiger auf den + <Slot-Server> dirty ist. Ersteres kann durch einen Aufruf von + <SfxBindings::Invalidate(sal_uInt16)> erzwungen werden, letzters durch + <SfxBindings::InvalidateAll(sal_Bool)>. + + + [Querverweise] + + <SfxShell::Invalidate(sal_uInt16)> + <SfxBindings::Invalidate(sal_uInt16)> + <SfxBindings::InvalidateAll(sal_Bool)> + <SfxBindings::Update(sal_uInt16)> +*/ + +{ + 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; + } +} + +//-------------------------------------------------------------------- + +void SfxBindings::SetState +( + const SfxItemSet& rSet // zu setzende Status-Werte +) + +/* [Beschreibung] + + Diese Methode erlaubt das direkte Setzen neuer Status-Werte, ohne + den Umweg "uber <SfxBindings::Invalidate()> und das dann im Update + erfolgende Rufen der Status-Methoden an den <SfxShell>s. + + + [Querverweise] + + <SfxBindings::SetState(const SfxPoolItem&)> +*/ + +{ + // 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 +) + +/* [Beschreibung] + + Diese Methode erlaubt das direkte Setzen eines neuen Status-Wertes, + ohne den Umweg "uber <SfxBindings::Invalidate()> und das dann im Update + erfolgende Rufen der Status-Methoden an den <SfxShell>s. + + Mit dieser Methode k"onnen nur <SfxPoolItem>s mit Slot, nicht + aber mit Which-Id gesetzt werden, da kein <SfxItemPool> bekannt ist, + "uber den gemappt werden k"onnte. + + + [Querverweise] + + <SfxBindings::SetState(const SfxItemSet&)> +*/ + +{ + 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. */ +) + +/* [Beschreibung] + + Diese Methode sucht die zu einer Slot-Id geh"orige <SfxStatusCache> + Instanz. Falls die Slot-Id in keinem Controller gebunden ist, wird + ein 0-Pointer zur"uckgegeben. + + Falls pPos != 0, wird erst ab der Position mit der Suche angefangen. + Dieses ist eine Optimierung, f"ur den Fall, da"s die kleineren + Ids bereits abgearbeitet wurden. + + In *pPos wird der ::com::sun::star::sdbcx::Index innerhalb der SfxBindings zur"uckgegeben, + unter dem dieser Cache z.Zt. abgelegt ist. Dieser ::com::sun::star::sdbcx::Index ist bis zum + n"achsten Aufruf von <SfxBindings::EnterRegistrations()> g"ultig. + W"ahrend der Umkonfiguration (<SfxBindings::IsInRegistrations()> == sal_True) + kann ist der ::com::sun::star::sdbcx::Index und der R"uckgabewert nur sehr kurzfristig + g"ultig. +*/ + +{ + 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 */ +) + +/* [Beschreibung] + + Invalidiert alle <SfxControllerItem> Instanzen, die an dieser + SfxBindings Instanz angemeldet sind, und bei bWithMsg == sal_True + ebenfalls die <Slot-Server>-Caches. + + Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten + beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden, + bevor "uberhaupt etwas passiert. + + + [Querverweise] + + <SfxShell::Invalidate(sal_uInt16)> + <SfxBindings::Invalidate(sal_uInt16)> + <SfxBindings::Invalidate(sal_uInt16*)> + <SfxBindings::Update()> + <SfxBindings::Update(sal_uInt16)> +*/ + +{ + 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); + pImp->nMsgPos = 0; + if ( !nRegLevel ) + { + 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!) */ +) + +/* [Beschreibung] + + Invalidiert die <SfxControllerItem> Instanzen der Slot-Ids in 'pIds', + die an dieser SfxBindings Instanz angemeldet sind. + + Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten + beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden, + bevor "uberhaupt etwas passiert. + + + [Querverweise] + + <SfxShell::Invalidate(sal_uInt16)> + <SfxBindings::Invalidate(sal_uInt16)> + <SfxBindings::InvalidateAll(sal_uInt16)> + <SfxBindings::Update()> + <SfxBindings::Update(sal_uInt16)> +*/ + +{ + DBG_PROFSTART(SfxBindingsInvalidateAll); + DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" ); + + DBG_MEMTEST(); + + 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.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 +) + +/* [Beschreibung] + + Invalidiert alle <SfxControllerItem> Instanzen, die zur Zeit von + der angegebenen SfxShell Instanz bedient werden und an dieser + SfxBindings Instanz angemeldet sind + + Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten + beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden, + bevor "uberhaupt etwas passiert. + + + [Querverweise] + + <SfxShell::Invalidate(sal_uInt16)> + <SfxBindings::Invalidate(sal_uInt16)> + <SfxBindings::Update()> + <SfxBindings::Update(sal_uInt16)> +*/ + +{ + 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.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 +) + +/* [Beschreibung] + + Invalidiert alle <SfxControllerItem> Instanzen, die auf die Slot-Id + nId gebunden sind und an dieser SfxBindings Instanz angemeldet sind. + + Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten + beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden, + bevor "uberhaupt etwas passiert. + + + [Querverweise] + <SfxBindings::Invalidate(sal_uInt16*)> + <SfxBindings::InvalidateAll(sal_Bool)> + <SfxBindings::Update()> + <SfxBindings::Update(sal_uInt16)> +*/ + +{ + DBG_MEMTEST(); + DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" ); + + 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.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 ? +) + +/* [Beschreibung] + + Invalidiert alle <SfxControllerItem> Instanzen, die auf die Slot-Id + nId gebunden sind und an dieser SfxBindings Instanz angemeldet sind, + und bei bWithMsg == sal_True ebenfalls den <Slot-Server>-Cache. + + Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten + beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden, + bevor "uberhaupt etwas passiert. + + [Querverweise] + <SfxBindings::Invalidate(sal_uInt16*)> + <SfxBindings::InvalidateAll(sal_Bool)> + <SfxBindings::Update()> + <SfxBindings::Update(sal_uInt16)> +*/ + +{ + 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.SetTimeout(TIMEOUT_FIRST); + pImp->aTimer.Start(); + } + } +} + +void SfxBindings::Invalidate +( + sal_uInt16 nId, // zu invalidierende Slot-Id + sal_Bool bWithMsg // SlotServer neu holen ? +) + +/* [Beschreibung] + + Invalidiert alle <SfxControllerItem> Instanzen, die auf die Slot-Id + nId gebunden sind und an dieser SfxBindings Instanz angemeldet sind, + und bei bWithMsg == sal_True ebenfalls den <Slot-Server>-Cache. + + Es wird daraufhin ein Timer gestartet, bei dessen Ablauf das Updaten + beginnt. Somit k"onnen mehrere Invalidierungen vorgenommen werden, + bevor "uberhaupt etwas passiert. + + [Querverweise] + <SfxBindings::Invalidate(sal_uInt16*)> + <SfxBindings::InvalidateAll(sal_Bool)> + <SfxBindings::Update()> + <SfxBindings::Update(sal_uInt16)> +*/ + +{ + DBG_ERROR( "Methode veraltet!" ); +/* + DBG_MEMTEST(); + DBG_ASSERT( !pImp->bInUpdate, "SfxBindings::Invalidate while in update" ); + DBG_ASSERT( sal_False, "alte Methode aus Kompatibilitaetsgruenden gerettet (MH)"); + + if ( pImp->pSubBindings ) + pImp->pSubBindings->Invalidate( nId, bWithMsg ); + + if ( !pDispatcher || pImp->bAllDirty || SFX_APP()->IsDowning() ) + return; + + SfxStateCache* pCache = GetStateCache(nId); + if ( pCache ) + { + pCache->Invalidate(bWithMsg); + pImp->nMsgPos = Min(GetSlotPos(nId), pImp->nMsgPos); + if ( !nRegLevel ) + { + pImp->aTimer.SetTimeout(TIMEOUT_FIRST); + pImp->aTimer.Start(); + } + } +*/ +} + +//-------------------------------------------------------------------- + +sal_Bool SfxBindings::IsBound( sal_uInt16 nSlotId, sal_uInt16 nStartSearchAt ) + +/* [Beschreibung] + + Stellt fest, ob die angegebene Slot-Id in einem <SfxControllerItem> + gebunden ist, der an dieser SfxBindings Instanz angemeldet ist. + + + [R"uckgabewert] + + sal_Bool sal_True + Die angegeben Slot-Id ist gebunden. + + sal_False + Die angegeben Slot-Id ist nicht gebunden. +*/ + +{ + 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 ) + +/* [Beschreibung] + + Ermittelt den ::com::sun::star::sdbcx::Index der angegebenen Slot-Id in den SfxBindings. + Falls die Slot-Id nicht gebunden ist, wird der ::com::sun::star::sdbcx::Index zur"uckgegeben, + an dem sie eingef"ugt w"urde. +*/ + +{ + 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; + } + size_t nLow = nStartSearchAt, nMid, 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::Register( SfxControllerItem& rItem ) + +/* [Beschreibung] + + Mit dieser Methode melden sich Instanzen der Klasse <SfxControllerItem> + an der betreffenden SfxBindings Instanz an, wenn sie eine Slot-Id binden. + + + [Querverweise] + <SfxBindings::Release(SfxControllerItem&)> + <SfxBindings::EnterRegistrations()> + <SfxBindings::LeaveRegistrations()> +*/ + +{ + DBG_MEMTEST(); + DBG_ASSERT( nRegLevel > 0, "registration without EnterRegistrations" ); + DBG_ASSERT( !pImp->bInNextJob, "SfxBindings::Register while status-updating" ); + //! EnterRegistrations(); + + // if not exist, insert a new cache + 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 + SfxControllerItem *pOldItem = (*pImp->pCaches)[nPos]->ChangeItemLink(&rItem); + rItem.ChangeItemLink(pOldItem); + + //! LeaveRegistrations(); +} +//-------------------------------------------------------------------- + +void SfxBindings::Release( SfxControllerItem& rItem ) + +/* [Beschreibung] + + Mit dieser Methode melden sich Instanzen der Klasse <SfxControllerItem> + an den SfxBindings ab. + + + [Querverweise] + <SfxBindings::Register(SfxControllerItem&)> + <SfxBindings::Release(SfxControllerItem&)> + <SfxBindings::EnterRegistrations()> + <SfxBindings::LeaveRegistrations()> +*/ + +{ + 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 ) + { + // 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 ) + { +#ifdef slow + // remove the BoundFunc + delete (*pImp->pCaches)[nPos]; + pImp->pCaches->Remove(nPos, 1); +#endif + if ( SfxMacroConfig::IsMacroSlot( nId ) ) + { + delete (*pImp->pCaches)[nPos]; + pImp->pCaches->Remove(nPos, 1); + } + else + pImp->bCtrlReleased = sal_True; + } + } + + LEAVEREGISTRATIONS(); +} + +//-------------------------------------------------------------------- +#if SUPD<582 +sal_Bool SfxBindings::Execute( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi ) +{ + return Execute( nId, SFX_CALLMODE_SLOT, ppItems, nModi ); +} + +sal_Bool SfxBindings::Execute( sal_uInt16 nId, SfxCallMode nCallMode, const SfxPoolItem** ppItems, sal_uInt16 nModi, const SfxPoolItem **ppInternalArgs ) +#else +sal_Bool SfxBindings::Execute( sal_uInt16 nId, const SfxPoolItem** ppItems, sal_uInt16 nModi, SfxCallMode nCallMode, const SfxPoolItem **ppInternalArgs ) +#endif +/* [Beschreibung] + + F"uhrt den Slot mit der Slot-Id nId "uber den <Slot-Server> Cache + aus. Dies ist nur bei in dieser SfxBindings INstanz gebundenen + Slot-Ids m"oglich. + + + [R"uckgabewert] + + sal_Bool sal_True + Das Execute wurde ausgef"uhrt. + + sal_False + Das Execute konnte nicht ausgef"uhrt werden, + weil der Slot entweder nicht zur Verf"ugung steht + (in keiner aktiven <SfxShell> vorhanden oder + disabled) ist oder der Anwender die Ausf"uhrung + abgebrochen hat (Cancel in einem Dialog). + + + [Querverweise] + <SfxDispatcher> +*/ +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + + if( !nId || !pDispatcher ) + return sal_False; + + SfxStateCache *pCache = GetStateCache( nId ); + if ( !pCache ) + { + SfxBindings *pBind = pImp->pSubBindings; + while ( pBind ) + { + if ( pBind->GetStateCache( nId ) ) +#if SUPD<582 + return pBind->Execute( nId, nCallMode, ppItems, nModi, ppInternalArgs ); +#else + return pBind->Execute( nId, ppItems, nModi, nCallMode, ppInternalArgs ); +#endif + pBind = pBind->pImp->pSubBindings; + }; + } + + // synchronisieren + SfxDispatcher &rDispatcher = *pDispatcher; + rDispatcher.Flush(); +// pImp->bInExecute = sal_True; + SfxViewFrame *pFrame = rDispatcher.GetFrame(); + + // vom cache den Server (Slot+ShellLevel) und die Shell etc. abholen + sal_Bool bDeleteCache = sal_False; + if ( !pCache && pImp->xProv.is() ) + { + pCache = new SfxStateCache( nId ); + pCache->GetSlotServer( rDispatcher, pImp->xProv ); + bDeleteCache = sal_True; + } + + if ( pCache && pCache->GetDispatch().is() ) + { + pCache->Dispatch( nCallMode == SFX_CALLMODE_SYNCHRON ); + if ( bDeleteCache ) + DELETEZ( pCache ); + return sal_True; + } + + // abgefangen? + if ( pImp->pInterceptors ) + { + for ( sal_uInt16 n = 0; n < pImp->pInterceptors->Count(); ++n ) + { + SfxSlotInterceptor *pInterceptor = pImp->pInterceptors->GetObject(n); + SfxPoolItem *pState = 0; + if ( SFX_ITEM_DISABLED != pInterceptor->QueryState(nId, pState) && + pInterceptor->Execute(nId, (SfxPoolItem**) ppItems) ) + { + delete pState; +// pImp->bInExecute = sal_False; + return sal_True; + } + } + } + + // Zur Sicherheit! + if ( pImp->bMsgDirty ) + UpdateSlotServer_Impl(); + + // Neuerdings k"onnen wir auch nicht gecachete Slots executen + // ( wg. Acceleratoren, deren Controller aus Performance-Gr"unden nicht mehr + // gebunden werden ). + SfxShell *pShell=0; + const SfxSlot *pSlot=0; + + const SfxSlotServer* pServer = pCache ? pCache->GetSlotServer( rDispatcher, pImp->xProv ) : 0; + if ( !pServer ) + { + SfxSlotServer aServer; +// if ( !rDispatcher._TryIntercept_Impl( nId, aServer, sal_False ) ) + { + if ( !rDispatcher._FindServer( nId, aServer, sal_False ) ) + { +// pImp->bInExecute = sal_False; + if ( bDeleteCache ) + delete pCache; + return sal_False; + } + } + + pShell = rDispatcher.GetShell( aServer.GetShellLevel() ); + pSlot = aServer.GetSlot(); + } + else + { + pShell = rDispatcher.GetShell( pServer->GetShellLevel() ); + pSlot = pServer->GetSlot(); + } + + 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 ); + } + +/* + if ( pFrame && pFrame->IsVisible() ) + { + // Bugfix #48745 + // damit der Benutzer nicht verwirrt wird, wird bei Executes vom + // UI aus, die "Anderungen am Dokument vornehmen, der Focus auf das + // EditWindow gezogen, sofern der Frame sichtbar ist und der Focus + // nicht schon im Frame liegt + SfxViewFrame *pTop = pFrame->GetTopViewFrame(); + SfxViewFrame *pAct = SfxViewFrame::Current()->GetTopViewFrame(); + if ( !pSlot->IsMode( SFX_SLOT_READONLYDOC ) && pTop == pAct && !pFrame->GetWindow().HasChildPathFocus( sal_True ) ) + pFrame->GetFrame()->GrabFocusOnComponent_Impl(); + } +*/ + 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() ) ); + rDispatcher._Execute( *pShell, *pRealSlot, aReq, nCallMode | SFX_CALLMODE_RECORD ); + } + else if ( SFX_KIND_ATTR == pSlot->GetKind() ) + { + // bei Attr-Slots mu 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 ( SFX_ITEM_SET == eState || + ( SFX_ITEM_AVAILABLE == eState && + SfxItemPool::IsWhich(nWhich) && + ( pOldItem = &aSet.Get(nWhich) ) ) ) + { + 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" ); + } + rDispatcher._Execute( *pShell, *pSlot, aReq, nCallMode | SFX_CALLMODE_RECORD ); + } + else + rDispatcher._Execute( *pShell, *pSlot, aReq, nCallMode | SFX_CALLMODE_RECORD ); + +// pImp->bInExecute = sal_False; + if ( bDeleteCache ) + delete pCache; + return sal_True; +} + +//-------------------------------------------------------------------- + +void SfxBindings::UpdateSlotServer_Impl() + +/* [Beschreibung] + + Interne Methode zum Updaten der Pointer auf die SlotServer + nach <SfxBindings::InvalidateAll(sal_Bool)>. +*/ + +{ + DBG_PROFSTART(SfxBindingsUpdateServers); + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + + // synchronisieren + pDispatcher->Flush(); +// pDispatcher->Update_Impl(); + + 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 +) + +/* [Beschreibung] + + Diese interne Methode sucht zu pCache die Slot-Ids, die von derselben + Status-Methode bedient werden und ebenfalls gebunden und dirty sind. + Es wird ein SfxItemSet zusammengestellt, das die Slot-Ids (oder falls + vorhanden die mit dem Pool der Shell gemappten Which-Ids) enth"alt. + Die Caches dieser Slots werden in pFoundCaches zur"uckgeliefert. +*/ + +{ + 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 ); + + if ( !SfxMacroConfig::IsMacroSlot( pRealSlot->GetSlotId() ) ) + { + 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 ? + FASTBOOL bInsert = pSiblingCache && pSiblingCache->IsControllerDirty(); + + // Bugfix #26161#: Es reicht nicht, nach der selben Shell zu fragen !! + FASTBOOL 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 *pFound = new SfxFoundCache_Impl( + pSibling->GetSlotId(), pSibling->GetWhich(rPool), + pSibling, pSiblingCache ); + + rFound.Insert( pFound ); + } + + pSibling = pSibling->GetNextSlot(); + } + + // aus den Ranges ein Set erzeugen + sal_uInt16 *pRanges = new sal_uInt16[rFound.Count() * 2 + 1]; + int j = 0; + int 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 +) + +/* [Beschreibung] + + Dieses ist eine Hilfsmethode f"ur NextJob_Impl mit der die SfxController, + welche auf nSlotId gebunden sind, upgedated werden. Dabei wird der + Wert aus dem SfxPoolItem unter dem Which-Wert nWhich aus dem Set rSet + genommen. + + Falls zu rSlot Enum-Werte in der Slotmap eingetragen sind, und diese + gebunden sind, werden sie ebenfalls upgedated. +*/ + +{ + 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() ) + { + // Slot abgefangen? + sal_Bool bIntercepted = sal_False; + if ( pImp->pInterceptors ) + { + for ( sal_uInt16 n = 0; n < pImp->pInterceptors->Count(); ++n ) + { + SfxSlotInterceptor *pInterceptor = pImp->pInterceptors->GetObject(n); + SfxPoolItem *pState = 0; + sal_uInt16 nSID = pCache->GetId(); + SfxItemState eState = pInterceptor->QueryState( nSID, pState ); + if ( SFX_ITEM_UNKNOWN != eState ) + { + bIntercepted = sal_True; + if ( eState == SFX_ITEM_AVAILABLE ) + { + // Default + SfxVoidItem aVoid(nSID); + pCache->SetState( eState, &aVoid ); + } + else + { + // Gesetzt + pCache->SetState( + eState == SFX_ITEM_SET ? SFX_ITEM_AVAILABLE : eState, pState ); + delete pState; + } + + return; + } + } + } + + if ( !bIntercepted ) + { + 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 +#ifdef OV_hat_das_SvxChooseControlItem_angepasst + || USHRT_MAX == pEnumItem->GetPosByValue(pEnumCache->GetValue()) +#endif + ) + { + // 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 ) + +/* [Beschreibung] + + Die SfxController werden "uber einen Timer updated. Dieses ist der + dazugeh"orige interne TimeOut-Handler. + */ + +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->pCaches != 0, "SfxBindings not initialized" ); + + DBG_PROFSTART(SfxBindingsNextJob_Impl0); + SfxApplication *pSfxApp = SFX_APP(); + + if( pDispatcher ) + pDispatcher->Update_Impl(); + + // modifying the SfxObjectInterface-stack without SfxBindings => nothing to do + SfxViewFrame* pFrame = pDispatcher->GetFrame(); + if ( pFrame && pFrame->GetObjectShell()->IsInModalMode() || pSfxApp->IsDowning() || !pImp->pCaches->Count() ) + { + 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 + FASTBOOL 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; + } + } + } + + // volatiles wieder von vorne starten + pImp->nMsgPos = 0; + pImp->aTimer.SetTimeout(TIMEOUT_IDLE); + 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); + } + + // Update-Runde ist beendet + pImp->bInNextJob = sal_False; + Broadcast(SfxSimpleHint(SFX_HINT_UPDATEDONE)); + DBG_PROFSTOP(SfxBindingsNextJob_Impl); + return sal_True; +} + +//-------------------------------------------------------------------- + +sal_uInt16 SfxBindings::EnterRegistrations(char *pFile, int nLine) + +/* [Beschreibung] + + Die An- oder Abmeldung von <SfxControllerItem> Instanzen mu"s in + EnterRegistrations() und LeaveRegistrations() geklammert werden. + W"ahrend dieser Zeit erfolgen keine Udates der <SfxContollerItem> + Instanzen (weder der alten noch der neu angemeldeten). + + [Parameter] + + pFile, nLine Dateiname und Zeilennummer der rufenden + Methode (nur Debug) + + [R"uckgabewert] + + sal_uInt16 Level der Registrierung. Dieser kann in + <SfxBindings::LeaveRegistrations(sal_uInt16)> als + Parameter angegeben werden, um die Paarigkeit + der EnterRegistrations() und LeaveRegistrations() + zu pr"ufen. + + + [Querverweise] + <SfxBindings::IsInRegistrations()> + <SfxBindings::Register(SfxControllerItem&)> + <SfxBindings::Release(SfxControllerItem&)> + <SfxBindings::LeaveRegistrations()> +*/ + +{ + 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); + } + 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, char *pFile, int nLine ) + +/* [Beschreibung] + + Die An- oder Abmeldung von <SfxControllerItem> Instanzen mu"s in + EnterRegistrations() und LeaveRegistrations() geklammert werden. + W"ahrend dieser Zeit erfolgen keine Udates der <SfxContollerItem> + Instanzen (weder der alten noch der neu angemeldeten). + + + [Parameter] + + sal_uInt16 nLevel == USRT_MAX + keine Paarigkeits-Pr"ufung f"ur diese Klammerung + + + pFile, nLine Dateiname und Zeilennummer der rufenden + Methode (nur Debug) + + < USHRT_MAX + R"uckgabewert des zugeh"origen EnterRegistrations() + zum pr"ufen der Paarigkeit. + + + [Querverweise] + <SfxBindings::IsInRegistrations()> + <SfxBindings::Register(SfxControllerItem&)> + <SfxBindings::Release(SfxControllerItem&)> + <SfxBindings::EnterRegistrations()> +*/ + +{ + 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() ) + { +#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 ) + { + // Cache entfernen + delete (*pImp->pCaches)[nCache-1]; + pImp->pCaches->Remove(nCache-1, 1); + } + 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.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); + } + DbgTrace( aMsg.GetBuffer() ); +#endif +} + +//-------------------------------------------------------------------- + +const SfxSlot* SfxBindings::GetSlot(sal_uInt16 nSlotId) + +/* [Beschreibung] + + Diese Methode liefert einen Pointer auf den zur Zeit gecacheten + SfxSlot f"ur die angegebene Slot-Id. + + + [R"uckgabewert] + + const <SfxSlot>* 0 + Falls die Slot-Id nicht gebunden ist oder + ein solcher Slot momentan in keiner aktiven + <SfxShell> vorhanden ist. + + != 0 + Falls die Slot-Id gebunden ist und ein solcher + Slot momentan in einer aktiven <SfxShell> + vorhanden ist. +*/ + +{ + 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 ) + +/* [Beschreibung] + + Setzt den zur Zeit von dieser SfxBindings Instanz zu verwendenden + Dispatcher um. + + Falls sich der Dispatcher dadurch "andert, wird intern + <SFxBindings::InvalidateAll(sal_Bool)> mit sal_True gerufen, also jegliche + gecachete Information der Bindings weggeworfen. +*/ + +{ + 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; + 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 ) + +// interne Methode zum forwarden dieses Methodenaufrufs + +{ + GetStateCache(nSlotId)->ClearCache(); +} + +//-------------------------------------------------------------------- + +// interne Methode zum Ansto\sen des Statusupdates + +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); +} + +//-------------------------------------------------------------------- + +#if SUPD<359 +SfxSlotInterceptor::SfxSlotInterceptor( SfxBindings *pBindings ) +: _pImp( new SfxSlotInterceptor_Impl ) +{ + DBG_ASSERT( pBindings, "SfxBindings: 0-Pointer not allowed" ); + _pImp->_pBindings = pBindings; + _pImp->_bIsActive = sal_False; + + // ggf. Interceptor-Liste on-demand erzeugen + if ( !_pImp->_pBindings->pImp->pInterceptors ) + _pImp->_pBindings->pImp->pInterceptors = new SfxInterceptorArr_Impl; + + Activate(sal_True); +} +#endif + +SfxSlotInterceptor::SfxSlotInterceptor( SfxBindings *pBindings, sal_Bool bActivate ) + +/* [Bindings] + + Registriert diese Instanz an den angegebenen <SfxBindings>. + Ab jetzt wird vor jedem Ausf"uhren eines Slots "uber diese + Bindings die virtuelle Methode <SfxSlotInterceptor::Execute()> + gerufen und vor jedem Erfragen eines Status die virtuelle + Methode <SfxSlotInterceptor::QueryState()>. +*/ + +: _pImp( new SfxSlotInterceptor_Impl ) +{ + _pImp->_pBindings = pBindings; + _pImp->_bIsActive = sal_False; + + Activate( bActivate ); +} + +//-------------------------------------------------------------------- + +SfxSlotInterceptor::~SfxSlotInterceptor() + +/* [Bindings] + + Beendet das Abfangen der Execute- und Status-Aufrufe an den + im Ctor angegebenen Bindings. +*/ + +{ + Activate(sal_False); + delete _pImp; +} + +void SfxSlotInterceptor::SetBindings( SfxBindings* pBindings ) +{ + DBG_ASSERT( !_pImp->_pBindings, "SetBindings bei gesetzten Bindings" ); + _pImp->_pBindings = pBindings; +} + +SfxBindings* SfxSlotInterceptor::GetBindings() const +{ + return _pImp->_pBindings; +} + + +//-------------------------------------------------------------------- + +void SfxSlotInterceptor::Activate( sal_Bool bActivate ) +{ + + if ( _pImp->_bIsActive == bActivate ) + return; + + if ( bActivate) + _pImp->_pBindings->pImp->InsertSlotInterceptor( this ); + else + _pImp->_pBindings->pImp->RemoveSlotInterceptor( this ); + + _pImp->_bIsActive = bActivate; + _pImp->_pBindings->InvalidateAll( sal_False ); +} + +//------------------------------------------------------------------------- + +sal_Bool SfxSlotInterceptor::IsActive() const +{ + return _pImp->_bIsActive; +} + +//------------------------------------------------------------------------- + +#if SUPD < 355 +sal_Bool SfxSlotInterceptor::Execute( sal_uInt16 nSID ) +#else +sal_Bool SfxSlotInterceptor::Execute( sal_uInt16 nSID, SfxPoolItem **ppArgs ) +#endif + + +/* [Beschreibung] + + Diese pur-virtuelle Methode mu\s von Subklassen "uberladen werden. + Sie wird gerufen, um 'nSID' auszuf"uhren. + + Wurde die SID nicht bearbeitet und soll an den Dispatcher weitergeleitet + werden, so mu\s sal_False zur"uckgegeben werden. + + [Beispiel] + + sal_Bool X::Execute( sal_uInt16 nSID ) + { + switch ( nSID ) + { + case SID_A: + ... + return sal_True; + + case SID_B: + ... + return sal_True; + + case SID_C: + ... + return sal_True; + } + + return sal_False; + } +*/ + +{ + return sal_False; +} + +//------------------------------------------------------------------------- + +SfxItemState SfxSlotInterceptor::QueryState +( + sal_uInt16 nSID, // IN: Slot-Id, deren Status erfragt wird + SfxPoolItem*& rpState // OUT: Status-Wert (Eigent"umer"ubergang) +) + +/* [Beschreibung] + + Diese pur-virtuelle Methode mu\s von Subklassen "uberladen werden. + Sie wird gerufen, um den Status f"ur 'nSID' zu erfragen. 'rpState' + darf nur dann ein mit 'new' anzulegendes <SfxPoolItem> zugewiesen + werden, wenn <SFX_ITEM_SET> zur"uckgeliefert wird. + + Wurde die SID nicht bearbeitet und soll an den Dispatcher weitergeleitet + werden, so mu\s <SFX_ITEM_UNKNOWN> zur"uckgegeben werden (Basisklasse + rufen!). + + [Beispiel] + + SfxItemState X::QueryState( sal_uInt16 nSID, SfxPoolItem*& rpState ) + { + switch ( nSID ) + { + case SID_A: + // Status-Item verschicken => enabled + rpState = new SfxStringItem( nSID, ... ); + return SFX_ITEM_SET; + + case SID_B: + // kein Status aber trotzdem enabled + return SFX_ITEM_AVAILABLE; + + case SID_C: + // disabled + return SFX_ITEM_DISABLED; + + case SID_D: + // mehrdeutig, enabled + return SFX_ITEM_DONTCARE; + } + + return SfxSlotInterceptor::QueryState( nSID, rpState ); + } +*/ + +{ + return SFX_ITEM_UNKNOWN; +} + +//------------------------------------------------------------------------- + +SfxItemState SfxBindings::QueryState( sal_uInt16 nSlot, SfxPoolItem* &rpState ) +/* [Beschreibung] + + Wird gerufen, um den Status f"ur 'nSlot' zu erfragen. Wenn der return + value SFX_ITEM_SET ist, wird ein SfxPoolItem zur"uckgegeben, indem der + rpState entsprechend gesetzt wird. Es findet dabei ein Eigent"umer"ubergang + statt, d.h. die aufrufende Methode mu\s das Item l"oschen. + + Anmerkung: diese Methode ist sehr teuer und sollte nur gerufen werden, + wenn kein Controller f"ur das Erfragen des Status angelegt werden kann oder + der Status unbedingt sofort geliefert werden mu\s. +*/ + +{ + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp; + SfxStateCache *pCache = GetStateCache( nSlot ); + if ( pCache ) + xDisp = pCache->GetDispatch(); + if ( xDisp.is() || !pCache && pImp->xProv.is() ) + { +//(mba)/compview + const SfxSlot* pSlot = 0;//SfxComponentViewShell::GetUnoSlot( nSlot ); + ::com::sun::star::util::URL aURL; + if ( pSlot ) + { + String aCmd( DEFINE_CONST_UNICODE(".uno:")); + aCmd += String::CreateFromAscii(pSlot->GetUnoName()); + aURL.Complete = aCmd; + } + else + { + String aCmd( DEFINE_CONST_UNICODE("slot:") ); + aCmd += String::CreateFromInt32(nSlot); + aURL.Complete = aCmd; + } + + Reference < XURLTransformer > xTrans( ::utl::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY ); + xTrans->parseStrict( aURL ); + 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 = (SfxOfficeDispatch*)(nImplementation); + } + + if ( !pDisp || pDisp->IsInterceptDispatch() ) + { + SfxItemState eState = SFX_ITEM_SET; + SfxPoolItem *pItem=NULL; + BindDispatch_Impl *pBind = new BindDispatch_Impl( xDisp, aURL, NULL ); + 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 ; + aAny >>= bTemp ; + pItem = new SfxBoolItem( nSlot, bTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt16*)0) ) + { + sal_uInt16 nTemp ; + aAny >>= nTemp ; + pItem = new SfxUInt16Item( nSlot, nTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt32*)0) ) + { + sal_uInt32 nTemp ; + 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 ); + } + + pBind->Release(); + rpState = pItem; + return eState; + } + } + } + + SfxSlotServer aServer; +/* + if ( pDispatcher->_TryIntercept_Impl( nSlot, aServer, sal_False ) ) + { + SfxShell* pShell = pDispatcher->GetShell( aServer.GetShellLevel() ); + const SfxPoolItem *pItem = pShell->GetSlotState(nSlot); + if ( !pItem ) + return SFX_ITEM_DISABLED; + else + { + rpState = pItem->Clone(); + return SFX_ITEM_SET; + } + } +*/ + if ( pImp->pInterceptors ) + { + // Zuerst die Interceptoren testen + for ( sal_uInt16 n = 0; n < pImp->pInterceptors->Count(); ++n ) + { + SfxSlotInterceptor *pInterceptor = pImp->pInterceptors->GetObject(n); + SfxItemState eState = pInterceptor->QueryState( nSlot, rpState ); + if ( SFX_ITEM_UNKNOWN != eState ) + 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; +} + +#if 0 +sal_Bool SfxBindings::IsInExecute_Impl() const +{ + return pImp->bInExecute; +} +#endif + +void SfxBindings::SetSubBindings_Impl( SfxBindings *pSub ) +{ + if ( pImp->pSubBindings ) + { + if ( pImp->pInterceptors ) + { + for ( sal_uInt16 n = 0; n < pImp->pInterceptors->Count(); ++n ) + { + SfxSlotInterceptor *pInter = pImp->pInterceptors->GetObject(n); + pImp->pSubBindings->pImp->RemoveSlotInterceptor( pInter ); + } + } + + 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; + + if ( pImp->pInterceptors ) + { + for ( sal_uInt16 n = 0; n < pImp->pInterceptors->Count(); ++n ) + { + SfxSlotInterceptor *pInter = pImp->pInterceptors->GetObject(n); + pImp->pSubBindings->pImp->InsertSlotInterceptor( pInter ); + } + } + } +} + +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::SetActiveFrame( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > & rFrame ) +{ + if ( rFrame.is() ) + SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > ( rFrame, ::com::sun::star::uno::UNO_QUERY ) ); + else if ( pDispatcher && pDispatcher->GetFrame() ) + { + SfxFrame *pFrame = pDispatcher->GetFrame()->GetFrame(); + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv( pFrame->GetInterceptor_Impl(), ::com::sun::star::uno::UNO_QUERY ); + SetDispatchProvider_Impl( xProv ); + } + else + SetDispatchProvider_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > () ); +} + +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(); + SfxTopViewFrame* pTop = PTR_CAST( SfxTopViewFrame, pFrame->GetTopViewFrame() ); + return pTop->GetTopFrame_Impl()->GetTopWindow_Impl(); +} diff --git a/sfx2/source/control/ctrlitem.cxx b/sfx2/source/control/ctrlitem.cxx new file mode 100644 index 000000000000..2d832fd0ef80 --- /dev/null +++ b/sfx2/source/control/ctrlitem.cxx @@ -0,0 +1,480 @@ +/************************************************************************* + * + * $RCSfile: ctrlitem.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SFXITEMPOOL_HXX //autogen +#include <svtools/itempool.hxx> +#endif +#pragma hdrstop + +#include "ctrlitem.hxx" +#include "bindings.hxx" +#include "dispatch.hxx" +#include "msgpool.hxx" +#include "statcach.hxx" + +//==================================================================== + +DBG_NAME(SfxControllerItem); + +//-------------------------------------------------------------------- +#ifdef DBG_UTIL + +void SfxControllerItem::CheckConfigure_Impl( ULONG nType ) +{ + // echter Slot? (also kein Separator etc.) + if ( !nId ) + return; + + // ist die Id "uberhaupt in 'nType' konfigurierbar? + const SfxSlot *pSlot = SFX_SLOTPOOL().GetSlot(nId); + DBG_ASSERTWARNING( pSlot, "SfxControllerItem: binding not existing slot" ); + if ( pSlot && !pSlot->IsMode(nType) ) + { + DBG_WARNING( "SfxControllerItem: slot without ...Config-flag" ); + DbgOutf( "SfxControllerItem: Config-flag missing at SID %5d", + pSlot->GetSlotId() ); + } +} + +#endif + +//-------------------------------------------------------------------- + +// returns the next registered SfxControllerItem with the same id + +SfxControllerItem* SfxControllerItem::GetItemLink() +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + return pNext == this ? 0 : pNext; +} + +//-------------------------------------------------------------------- + +// returns TRUE if this binding is really bound to a function + +BOOL SfxControllerItem::IsBound() const +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + return pNext != this; +} + +//-------------------------------------------------------------------- + +// returns the associated function-id or 0 if none + +// USHORT SfxControllerItem::GetId() const; + +//==================================================================== + +// registeres with the id at the bindings + +void SfxControllerItem::Bind( USHORT nNewId, SfxBindings *pBindinx ) +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT(pBindings || pBindinx, "Keine Bindings"); + + if ( IsBound() ) { + DBG_ASSERT(pBindings, "Keine Bindings"); + pBindings->Release(*this); + } + + nId = nNewId; + pNext = 0; + + if (pBindinx) + pBindings = pBindinx; + pBindings->Register(*this); +} + + +//==================================================================== + +void SfxControllerItem::UnBind() + +/* [Beschreibung] + + "ost die Verbindung dieses SfxControllerItems mit der SfxBindings-Instanz, + an der es zur Zeit gebunden ist. Ab diesem Zeitpunkt erh"alt es keine + Statusbenachrichtigungen (<SfxControllerItem::StateChented()>) mehr. + + + [Querverweise] + + <SfxControllerItem::ReBind()> + <SfxControllerItem::ClearCache()> +*/ +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT(pBindings, "Keine Bindings"); + DBG_ASSERT( IsBound(), "unbindings unbound SfxControllerItem" ); + + pBindings->Release(*this); + pNext = this; +} + +//==================================================================== + +void SfxControllerItem::ReBind() + +/* [Beschreibung] + + Binded dieses SfxControllerItem wieder an die SfxBindings-Instanz, + an der es zuletzt gebunden war. Ab diesem Zeitpunkt erh"alt es wieder + Statusbenachrichtigungen (<SfxControllerItem::StateChented()>). + + + [Querverweise] + + <SfxControllerItem::UnBind()> + <SfxControllerItem::ClearCache()> +*/ + +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT(pBindings, "Keine Bindings"); + DBG_ASSERT( !IsBound(), "bindings rebound SfxControllerItem" ); + + pBindings->Register(*this); +} + +//==================================================================== + +void SfxControllerItem::UpdateSlot() + +/* [Beschreibung] + + Holt den Status 'hart' neu. + + [Querverweise] + + <SfxControllerItem::ClearCache()> +*/ + +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT(pBindings, "Keine Bindings"); + + pBindings->Update( GetId() ); +} + +//-------------------------------------------------------------------- + +void SfxControllerItem::ClearCache() + +/* [Beschreibung] + + "oscht den Status-Cache f"ur dieses SfxControllerItem. D.h. beim + n"achsten Status-Update wird das <SfxPoolItem> auf jeden Fall geschickt, + auch wenn zuvor dasselbe geschickt wurde. Dies wird ben"otigt, wenn + ein Controller umgeschaltet werden kann und sich diesen Status + selbst merkt. + + + [Beispiel] + + Der Kombi-Controller f"ur das Einstellen des Fl"achentyps und der + konkreten Auspr"agung (Farbe blau oder Schraffur X) kann im Typ + umgestellt werden, wird jedoch dann bei der n"achsten Selektion + wieder benachrichtigt, auch wenn es dieselben Daten sind. + + + [Querverweise] + + <SfxControllerItem::UnBind()> + <SfxControllerItem::ReBind()> +*/ + + +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT(pBindings, "Keine Bindings"); + + pBindings->ClearCache_Impl( GetId() ); +} + +//-------------------------------------------------------------------- + +// replaces the successor in the list of bindings of the same id + +SfxControllerItem* SfxControllerItem::ChangeItemLink( SfxControllerItem* pNewLink ) +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + SfxControllerItem* pOldLink = pNext; + pNext = pNewLink; + return pOldLink == this ? 0 : pOldLink; +} + +//-------------------------------------------------------------------- + +// changes the id of unbound functions (e.g. for sub-menu-ids) + +void SfxControllerItem::SetId( USHORT nItemId ) +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); + DBG_ASSERT( !IsBound(), "changing id of bound binding" ); + nId = nItemId; +} + +//-------------------------------------------------------------------- + +SvStream& operator<<( SvStream& rStream, const SfxControllerItem& rFunc ) +{ + DBG_MEMTEST(); + SFX_SLOTPOOL().StoreId( rStream, rFunc.nId ); + return rStream; +} + +//-------------------------------------------------------------------- + +SvStream& operator>>( SvStream& rStream, SfxControllerItem& rFunc ) +{ + DBG_MEMTEST(); + USHORT nId; + SFX_SLOTPOOL().LoadId( rStream, nId ); + rFunc.Bind(nId); + return rStream; +} + +//-------------------------------------------------------------------- + +// creates a atomic item for a controller without registration + +SfxControllerItem::SfxControllerItem(): + nId(0), + pNext(this), + pBindings(0) +{ + DBG_MEMTEST(); + DBG_CTOR(SfxControllerItem, 0); +} + +//-------------------------------------------------------------------- + +// creates a representation of the function nId and registeres it + +SfxControllerItem::SfxControllerItem( USHORT nId, SfxBindings &rBindings ): + nId(nId), + pNext(this), + pBindings(&rBindings) +{ + DBG_MEMTEST(); + DBG_CTOR(SfxControllerItem, 0); + Bind(nId, &rBindings); +} + +//-------------------------------------------------------------------- + +// unregisteres the item in the bindings + +SfxControllerItem::~SfxControllerItem() +{ + DBG_MEMTEST(); + if ( IsBound() ) + pBindings->Release(*this); + DBG_DTOR(SfxControllerItem, 0); +} + +//-------------------------------------------------------------------- + +void SfxControllerItem::StateChanged +( + USHORT nSID, // <SID> des ausl"osenden Slot + SfxItemState eState, // <SfxItemState> von 'pState' + const SfxPoolItem* pState // Slot-Status, ggf. 0 oder IsInvalidItem() +) + +/* [Beschreibung] + + Diese virtuelle Methode wird vom SFx gerufen, um <SfxControllerItem>s + dar"uber zu benachrichtigen, da\s sich der Status des Slots 'nSID' + ge"andert hat. Der neue Wert sowie der von diesem Wert ermittelte + Status wird als 'pState' bzw. 'eState' mitgegeben. + + Der Status eines Slots kann sich "andern, wenn z.B. das MDI-Fenster + gewechselt wird oder der Slot explizit mit <SfxBindings::Invalidate()> + invalidiert wurde. + + Achtung! Die Methode wird nicht gerufen, wenn der Slot ung"ultig wurde, + danach jedoch wieder denselben Wert angenommen hat. + + Diese Basisklasse braucht nicht gerufen zu werden, weitere Zwischenstufen + jedoch (z.B. <SfxToolboxControl>) sollten gerufen werden. +*/ + +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); +} + +//-------------------------------------------------------------------- + +void SfxControllerItem::DeleteFloatingWindow() +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxControllerItem, 0); +} + +//-------------------------------------------------------------------- + +void SfxStatusForwarder::StateChanged +( + USHORT nSID, // <SID> des ausl"osenden Slot + SfxItemState eState, // <SfxItemState> von 'pState' + const SfxPoolItem* pState // Slot-Status, ggf. 0 oder IsInvalidItem() +) + +{ + pMaster->StateChanged( nSID, eState, pState ); +} + +//-------------------------------------------------------------------- + +SfxStatusForwarder::SfxStatusForwarder( + USHORT nSlotId, + SfxControllerItem& rMaster ): + SfxControllerItem( nSlotId, rMaster.GetBindings() ), + pMaster( &rMaster ) +{ +} + +//-------------------------------------------------------------------- + +SfxItemState SfxControllerItem::GetItemState +( + const SfxPoolItem* pState /* Pointer auf das <SfxPoolItem>, dessen + Status erfragt werden soll. */ +) + +/* [Beschreibung] + + Statische Methode zum Ermitteln des Status des SfxPoolItem-Pointers, + in der Methode <SfxControllerItem::StateChanged(const SfxPoolItem*)> + zu verwenden. + + [R"uckgabewert] + + SfxItemState SFX_ITEM_UNKNOWN + Enabled, aber keine weitere Statusinformation + verf"ugbar. Typisch f"ur <Slot>s, die allenfalls + zeitweise disabled sind, aber ihre Darstellung sonst + nicht "andern. + + SFX_ITEM_DISABLED + Disabled und keine weiter Statusinformation + verf"ugbar. Alle anderen ggf. angezeigten Werte sollten + auf den Default zur"uckgesetzt werden. + + SFX_ITEM_DONTCARE + Enabled aber es waren nur uneindeutige Werte + verf"ugbar (also keine, die abgefragt werden k"onnen). + + SFX_ITEM_AVAILABLE + Enabled und mit verf"ugbarem Wert, der von 'pState' + erfragbar ist. Der Typ ist dabei im gesamten + Programm eindeutig und durch den Slot festgelegt. +*/ + +{ + return !pState + ? SFX_ITEM_DISABLED + : IsInvalidItem(pState) + ? SFX_ITEM_DONTCARE + : pState->ISA(SfxVoidItem) && !pState->Which() + ? SFX_ITEM_UNKNOWN + : SFX_ITEM_AVAILABLE; +} + +//-------------------------------------------------------------------- + +SfxMapUnit SfxControllerItem::GetCoreMetric() const + +/* [Beschreibung] + + Holt vom zust"andigen Pool die Ma\seinheit ab, in der das Status-Item + vorliegt. +*/ + +{ + SfxStateCache *pCache = pBindings->GetStateCache( nId ); + SfxDispatcher *pDispat = pBindings->GetDispatcher_Impl(); + const SfxSlotServer *pServer = pCache->GetSlotServer( *pDispat ); + SfxShell *pSh = pDispat->GetShell( pServer->GetShellLevel() ); + SfxItemPool &rPool = pSh->GetPool(); + USHORT nWhich = rPool.GetWhich( nId ); + return rPool.GetMetric( nWhich ); +} + +//------------------------------------------------------------------------ + +#ifdef WNT +#pragma optimize("g",off) +#endif + + diff --git a/sfx2/source/control/dispatch.cxx b/sfx2/source/control/dispatch.cxx new file mode 100644 index 000000000000..57c5c7f6e630 --- /dev/null +++ b/sfx2/source/control/dispatch.cxx @@ -0,0 +1,3493 @@ +/************************************************************************* + * + * $RCSfile: dispatch.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SFXITEMPOOL_HXX //autogen +#include <svtools/itempool.hxx> +#endif +#ifndef _SFXITEMITER_HXX //autogen +#include <svtools/itemiter.hxx> +#endif +#ifndef _SFX_WHITER_HXX //autogen +#include <svtools/whiter.hxx> +#endif +#ifndef _SFXINTITEM_HXX //autogen +#include <svtools/intitem.hxx> +#endif +#ifndef _SFXEITEM_HXX //autogen +#include <svtools/eitem.hxx> +#endif +#ifndef _UNDO_HXX //autogen +#include <svtools/undo.hxx> +#endif +#ifndef _WRKWIN_HXX //autogen +#include <vcl/wrkwin.hxx> +#endif +#ifndef _SVTOOLS_TTPROPS_HXX +#include <svtools/ttprops.hxx> +#endif +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> // wg. bsearch + +#define _SVSTDARR_ULONGS +#include <svtools/svstdarr.hxx> + +#pragma hdrstop + +#include "sfxhelp.hxx" +#include "appdata.hxx" +#include "dispatch.hxx" +#include "minstack.hxx" +#include "msg.hxx" +#include "objface.hxx" +#include "bindings.hxx" +#include "request.hxx" +#include "app.hxx" +#include "hintpost.hxx" +#include "slotserv.hxx" +#include "ipfrm.hxx" +#include "interno.hxx" +#include "sfxtypes.hxx" +#include "macrconf.hxx" +#include "virtmenu.hxx" +#include "viewfrm.hxx" +#include "viewsh.hxx" +#include "mnumgr.hxx" +#include "childwin.hxx" +#include "docfac.hxx" +#include "saveopt.hxx" +#include "ipenv.hxx" +#include "msgpool.hxx" +#include "module.hxx" +#include "tbxconf.hxx" +#include "topfrm.hxx" +#include "sfxuno.hxx" + +//================================================================== +DBG_NAME(SfxDispatcherFlush); +DBG_NAME(SfxDispatcherFillState); + +//================================================================== +SV_IMPL_PTRARR( SfxItemPtrArray, SfxPoolItemPtr ); + +DECL_PTRSTACK(SfxShellStack_Impl, SfxShell*, 8, 4 ); +//================================================================== + +struct SfxToDo_Impl +{ + SfxShell* pCluster; + sal_Bool bPush; + sal_Bool bDelete; + sal_Bool bUntil; + + SfxToDo_Impl(): + bPush(sal_False), bDelete(sal_False), bUntil(sal_False), pCluster(0) {} + SfxToDo_Impl( sal_Bool bOpPush, sal_Bool bOpDelete, sal_Bool bOpUntil, SfxShell& rCluster ): + bPush(bOpPush), bDelete(bOpDelete), bUntil(bOpUntil), pCluster(&rCluster) {} + ~SfxToDo_Impl(){} + + sal_Bool operator==( const SfxToDo_Impl& rWith ) const + { return pCluster==rWith.pCluster && bPush==rWith.bPush; } +}; + +DECL_OBJSTACK(SfxToDoStack_Impl, SfxToDo_Impl, 8, 4); +IMPL_OBJSTACK(SfxToDoStack_Impl, SfxToDo_Impl); + +struct SfxObjectBars_Impl +{ + ResId aResId; // Resource - und ConfigId der Toolbox + sal_uInt16 nMode; // spezielle Sichtbarkeitsflags + String aName; + SfxInterface* pIFace; + + SfxObjectBars_Impl() : + aResId( 0,0 ) + {} +}; + +//------------------------------------------------------------------ + +struct SfxDispatcher_Impl +{ + const SfxSlotServer* pCachedServ1; // zuletzt gerufene Message + const SfxSlotServer* pCachedServ2; // vorletzt gerufene Message + SfxShellStack_Impl aStack; // aktive Funktionalitaet + Timer aTimer; // fuers flushen + SfxToDoStack_Impl aToDoStack; // nicht abgearb. Push/Pop + SfxViewFrame* pFrame; // 0 oder zugeh"or. Frame + SfxDispatcher* pParent; // z.B. AppDispatcher, ggf. 0 + SfxHintPosterRef xPoster; // asynchrones Execute + sal_Bool bFlushing; // sal_True waehrend Flush //? + sal_Bool bFlushed; // aToDoStack.Count() == 0 + sal_Bool bUpdated; // Update_Impl gelaufen + sal_Bool bLocked; // kein Execute + sal_Bool bInvalidateOnUnlock;// da fragte jemand + sal_Bool bActive; // nicht verwechseln mit gesetzt! + sal_Bool* pInCallAliveFlag; // dem Stack den Dtor anzeigen + SfxObjectBars_Impl aObjBars[SFX_OBJECTBAR_MAX]; + SfxObjectBars_Impl aFixedObjBars[SFX_OBJECTBAR_MAX]; + SvULongs aChildWins; + sal_uInt16 nActionLevel; // in EnterAction + sal_uInt32 nEventId; // EventId UserEvent + sal_Bool bUILocked; // Update abgeklemmt (!zappeln) + sal_Bool bNoUI; // UI nur vom Parent Dispatcher + sal_Bool bReadOnly; // Dokument ist ReadOnly + sal_Bool bQuiet; // nur parent dispatcher verwenden + sal_Bool bModal; // nur Slots vom Parent-Dispatcher + + sal_Bool bFilterEnabling; // sal_True=filter enabled slots, 2==ReadOnlyDoc uebersteuert + sal_uInt16 nFilterCount; // Anzahl der SIDs in pFilterSIDs + const sal_uInt16* pFilterSIDs; // sortiertes Array von SIDs + sal_uInt16 nStandardMode; // ExecuteMode f. PlugInDispatcher + SvUShorts* pDisableList; + sal_uInt32 nDisableFlags; +}; + +#define NO_OBJECTBAR 0 +#define OWN_OBJECTBAR 1 +#define OTHER_OBJECTBAR 2 + +//------------------------------------------------------------------ + +#define SFX_FLUSH_TIMEOUT 50 + +//==================================================================== +sal_Bool SfxDispatcher::IsLocked( sal_uInt16 nSID ) const + +/* [Beschreibung] + + Mit dieser Methode kann festgestellt werden, ob der SfxDispatcher + gesperrt oder freigegeben ist. Ein gesperrter SfxDispatcher + f"uhrt keine <SfxRequest>s mehr aus und liefert keine + Status-Informationen mehr. Er verh"alt sich so als w"aren alle + Slots disabled. + + Der Dispatcher gilt auch als gesperrt, wenn alle Dispatcher + gelockt sind (<SfxApplication::LockDispatcher()>) oder der zugeh"orige + Top-Frame im modal-mode ist und der angegebene Slot Frame-spezifisch + (also nicht von der Application) bedient wird. +*/ + +{ + return nSID != SID_BROWSE_STOP && nSID != SID_HELP_PI && + ( pImp->bLocked || SFX_APP()->IsDispatcherLocked() ); +} + +//-------------------------------------------------------------------- +sal_Bool SfxDispatcher::IsAppDispatcher() const + +/* [Beschreibung] + + Mit dieser Methode l"a\st sich festellen, ob der SfxDispacher der + Applikations-Dispatcher ist. + + + [R"uckgabewert] + + sal_Bool sal_True + Es ist der Applikations-Dispatcher. + + sal_False + Es ist ein Dispatcher eines SfxViewFrame. +*/ + +{ + return !pImp->pFrame; +} + +//-------------------------------------------------------------------- +int SfxDispatcher::Call_Impl( SfxShell& rShell, const SfxSlot &rSlot, SfxRequest &rReq, sal_Bool bRecord ) + +/* [Beschreibung] + + Hilfsfunktion zum pr"ufen, ob ein Slot executed werden darf und + der Execution selbst. +*/ + +{ + SFX_STACK(SfxDispatcher::Call_Impl); + + // darf der Slot gerufen werden (i.S.v. enabled) + SfxApplication *pSfxApp = SFX_APP(); + if ( rSlot.IsMode(SFX_SLOT_FASTCALL) || rShell.CanExecuteSlot_Impl(rSlot) ) + { + // ggf. die Bindings locken (MI: warum?) + SfxBindings *pBindings = GetBindings(); +#if modal_mode_sinnlos + sal_Bool bLockBindings = rSlot.GetSlotId() != SID_OPENDOC && rSlot.GetSlotId() != SID_OPENURL; + if ( bLockBindings && pBindings ) + pBindings->DENTERREGISTRATIONS(); +#endif + + // Alles holen, was gebraucht wird, da der Slot den Execute evtl. nicht + // "uberlebt, falls es ein 'Pseudoslot' f"ur Macros oder Verben ist + sal_Bool bAutoUpdate = rSlot.IsMode(SFX_SLOT_AUTOUPDATE); + SFX_REQUEST_ARG(rReq, pOrigItem, SfxExecuteItem, SID_SUBREQUEST, sal_False); + SfxExecuteItem *pExecuteItem = pOrigItem + ? (SfxExecuteItem*)pOrigItem->Clone() + : 0; + + // ggf. TabPage-ID setzen und SID merken + SfxAppData_Impl *pAppData = pSfxApp->Get_Impl(); + SFX_REQUEST_ARG(rReq, pTabPageItem, SfxUInt16Item, SID_TABPAGE, sal_False); + if ( pTabPageItem ) + { + pAppData->nAutoTabPageId = pTabPageItem->GetValue(); + rReq.RemoveItem( SID_TABPAGE ); // sonst ArgCount > 0 => Seiteneff. + } + pAppData->nExecutingSID = rReq.GetSlot(); + + // API-Call-Klammerung und Document-Lock w"ahrend des Calls + { + // 'this' mu\s im Dtor bescheid sagen + sal_Bool bThisDispatcherAlive = sal_True; + sal_Bool *pOldInCallAliveFlag = pImp->pInCallAliveFlag; + pImp->pInCallAliveFlag = &bThisDispatcherAlive; + + // eigentlichen Call durchf"uhren + sal_Bool bDone = sal_False; +/* + SfxViewFrame *pViewFrame = GetFrame(); + if ( pViewFrame ) + { + SFX_REQUEST_ARG(rReq, pInterceptorItem, SfxBoolItem, SID_INTERCEPTOR, sal_False); + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProviderInterceptor > xProv( pViewFrame->GetFrame()->GetInterceptor_Impl() ); + sal_Bool bDirect = ( pInterceptorItem != 0 ); + if ( bDirect ) + { + bDirect = !pInterceptorItem->GetValue(); + rReq.RemoveItem( SID_INTERCEPTOR ); + } + + if ( xProv.is() && !bDirect ) + { + bDone = sal_True; + ::com::sun::star::util::URL aURL; + String aName( rSlot.GetUnoName() ); + String aCmd; + if ( aName.getLength() ) + { + aCmd = ".uno:"; + aCmd += aName; + } + else + { + aCmd = "slot:"; + aCmd += rSlot.GetSlotId(); + } + + aURL.Complete = S2U( aCmd ); + SfxURLTransformer aTrans; + aTrans.parseStrict( aURL ); + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp = xProv->queryDispatch( aURL, "", 0 ); + if ( xDisp.is() ) + { +// automatisch auskommentiert - [getImplementation] - Wird von OWeakObject nicht weiter untersttzt! +// void* pDisp = xDisp->getImplementation( ::getCppuType((const SfxOfficeDispatch*)0) ); + + if ( pDisp) + bDone = sal_False; + else + { + ::com::sun::star::uno::Sequence <PropertyValue> aSequ; + if ( rReq.GetArgs() ) + TransformItems( rSlot.GetSlotId(), *rReq.GetArgs(), aSequ, &rSlot ); + xDisp->dispatch( aURL, aSequ ); + } + } + } + } +*/ + if ( !bDone ) + { + // Bei neuen/komplizierten Funktionen den HelpAgent feuern... + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + ((SfxHelp_Impl*)pHelp)->SlotExecutedOrFocusChanged( rReq.GetSlot(), sal_True, pSfxApp->GetOptions().IsAutoHelpAgent() ); + + SfxExecFunc pFunc = rSlot.GetExecFnc(); + rShell.CallExec( pFunc, rReq ); + } + + // falls 'this' noch lebt + if ( bThisDispatcherAlive ) + pImp->pInCallAliveFlag = pOldInCallAliveFlag; + else if ( pOldInCallAliveFlag ) + // auch verschachtelte Stack-Frames sch"utzen + *pOldInCallAliveFlag = sal_False; + } + + // TabPage-ID und Executing-SID zurueck setzen + if ( pTabPageItem ) + pAppData->nAutoTabPageId = 0; + pAppData->nExecutingSID = 0; + +#if modal_mode_sinnlos + // ggf. Lock wieder freigeben + if ( bLockBindings ) + pBindings->DLEAVEREGISTRATIONS(); +#endif + + if( pExecuteItem ) + { + Execute( *pExecuteItem ); + delete pExecuteItem; + } + + if ( rReq.IsDone() ) + { + // bei AutoUpdate sofort updaten; "Pseudoslots" d"urfen nicht + // Autoupdate sein! + if ( bAutoUpdate ) + { + const SfxSlot* pSlave = rSlot.GetLinkedSlot(); + if (pSlave) + { + // bei Enum-Slots irgendeinen gebundenen Slave-Slot nehmen + while (!pBindings->IsBound(pSlave->GetSlotId()) && pSlave != &rSlot ) + pSlave = pSlave->GetLinkedSlot(); + pBindings->Invalidate(pSlave->GetSlotId()); + pBindings->Update(pSlave->GetSlotId()); + } + else + { + pBindings->Invalidate(rSlot.GetSlotId()); + pBindings->Update(rSlot.GetSlotId()); + } + } + return sal_True; + } + } + + return sal_False; +} + +//==================================================================== +void SfxDispatcher::Construct_Impl( SfxDispatcher* pParent ) +{ + pImp = new SfxDispatcher_Impl; + bFlushed = sal_True; + SfxApplication *pSfxApp = SFX_APP(); + + pImp->pCachedServ1 = 0; + pImp->pCachedServ2 = 0; + pImp->bFlushing = sal_False; + pImp->bUpdated = sal_False; + pImp->bLocked = sal_False; + pImp->bActive = sal_False; + pImp->pParent = NULL; + pImp->bUILocked = sal_False; + pImp->bNoUI = sal_False; + pImp->bReadOnly = sal_False; + pImp->bQuiet = sal_False; + pImp->bModal = sal_False; + pImp->pInCallAliveFlag = 0; + pImp->bFilterEnabling = sal_False; + pImp->nFilterCount = 0; + pImp->pFilterSIDs = 0; + pImp->nStandardMode = 0; + pImp->pDisableList = pSfxApp->GetDisabledSlotList_Impl(); + pImp->nDisableFlags = 0; + + pImp->pParent = pParent; + + pImp->bInvalidateOnUnlock = sal_False; + pImp->nActionLevel = 0; + + for (sal_uInt16 n=0; n<SFX_OBJECTBAR_MAX; n++) + pImp->aObjBars[n].aResId = ResId( 0,0 ); + + GenLink aGenLink( LINK(this, SfxDispatcher, PostMsgHandler) ); + + pImp->xPoster = new SfxHintPoster(aGenLink); + + pImp->aTimer.SetTimeout(SFX_FLUSH_TIMEOUT); + pImp->aTimer.SetTimeoutHdl( LINK(this, SfxDispatcher, EventHdl_Impl ) ); +} + +SfxDispatcher::SfxDispatcher( SfxDispatcher* pParent ) +{ + Construct_Impl( pParent ); + pImp->pFrame = 0; +} + +SfxDispatcher::SfxDispatcher( SfxViewFrame *pViewFrame ) + +/* [Beschreibung] + + Der Konstruktor der Klasse SfxDispatcher legt einen leeren Stack + von <SfxShell>-Pointern an. Er ist initial nicht gelockt und gilt als + geflusht. +*/ + +{ + if ( pViewFrame ) + { + SfxViewFrame *pFrame = pViewFrame->GetParentViewFrame(); + if ( pFrame ) + Construct_Impl( pFrame->GetDispatcher() ); + else + Construct_Impl( 0 ); + } + else + Construct_Impl( 0 ); + pImp->pFrame = pViewFrame; +} + +//==================================================================== +SfxDispatcher::~SfxDispatcher() + +/* [Beschreibung] + + Der Destruktor der Klasse SfxDispatcher darf nicht gerufen werden, + wenn die SfxDispatcher-Instanz aktiv ist. Es d"urfen sich allerdings + noch <SfxShell>-Pointer auf dem Stack befinden. +*/ + +{ +#ifdef DBG_UTIL + ByteString sTemp( "Delete Dispatcher " ); + sTemp += ByteString::CreateFromInt32( (sal_uInt32)this ); + DBG_TRACE( sTemp.GetBuffer() ); + DBG_ASSERT( !pImp->bActive, "deleting active Dispatcher" ); +#endif + + // Damit in LeaveRegistrations kein Timer per Reschedule in PlugComm + // zuschlaegt + pImp->aTimer.Stop(); + pImp->xPoster->SetEventHdl( Link() ); + + // die Stack-Varialblem in Call_Impl benachrichtigen + if ( pImp->pInCallAliveFlag ) + *pImp->pInCallAliveFlag = sal_False; + + // Bindings und App besorgen + SfxApplication *pSfxApp = SFX_APP(); + SfxBindings* pBindings = GetBindings(); + +// if (pImp->nEventId) +// pSfxApp->RemoveEventHdl(pImp->nEventId); + + // wenn noch nicht flushed, die Bindings wiederbeleben + if ( pBindings && !pSfxApp->IsDowning() && !bFlushed ) + pBindings->DLEAVEREGISTRATIONS(); + + // ggf. bei den Bindings abmelden + while ( pBindings ) + { + if ( pBindings->GetDispatcher_Impl() == this) + pBindings->SetDispatcher(0); + pBindings = pBindings->GetSubBindings_Impl(); + } + + delete pImp; +} + +//==================================================================== +void SfxDispatcher::Pop +( + SfxShell& rShell, /* Die vom Stack zu nehmende SfxShell-Instanz. */ + + sal_uInt16 nMode /* SFX_SHELL_POP_UNTIL + Es werden auch alle "uber 'rShell' liegenenden + SfxShell's vom Stack genommen. + + SFX_SHELL_POP_DELETE + Alle tats"achlich vom Stack genommenen + SfxShells werden gel"oscht. + + SFX_SHELL_PUSH (InPlace use only) + Die Shell wird gepusht. */ +) +/* [Beschreibung] + + Mit dieser Methode wird eine oder mehrere <SfxShell> vom SfxDispatcher + gepoppt. Die SfxShell wird zun"achst zum poppen vermerkt und + es wird ein Timer aufgesetzt. Erst bei Ablauf des Timers wird + tats"achlich gepoppt (<SfxDispatcher::Flush()>) und die <SfxBindings> + werden invalidiert. W"ahrend der Timer l"auft gleichen sich + entgegengesetzte Push und Pop Befehle mit derselben SfxShell aus. +*/ + +{ + DBG_MEMTEST(); + DBG_ASSERT( rShell.GetInterface(), + "pushing SfxShell without previous RegisterInterface()" ); + DBG_ASSERT( pImp->nActionLevel == 0, "Push or Pop within Action" ); +// DBG_ASSERT( SFX_APP()->IsInAsynchronCall_Impl(), +// "Dispatcher Push/Pop in synchron-call-stack" ); + + FASTBOOL bDelete = (nMode & SFX_SHELL_POP_DELETE) == SFX_SHELL_POP_DELETE; + FASTBOOL bUntil = (nMode & SFX_SHELL_POP_UNTIL) == SFX_SHELL_POP_UNTIL; + FASTBOOL bPush = (nMode & SFX_SHELL_PUSH) == SFX_SHELL_PUSH; + + SfxApplication *pSfxApp = SFX_APP(); + +#ifdef DBG_UTIL + ByteString aMsg( "SfxDispatcher(" ); + aMsg += ByteString::CreateFromInt32( (long) this ); + aMsg += bPush ? ")::Push(" : ")::Pop("; + if ( rShell.GetInterface() ) + aMsg += rShell.GetInterface()->GetClassName(); + else + aMsg += ByteString::CreateFromInt32( (long) &rShell ); + aMsg += bDelete ? ") with delete" : ")"; + DbgTrace( aMsg.GetBuffer() ); +#endif + + // gleiche Shell wie on-Top des ToDo-Stacks? + if ( pImp->aToDoStack.Count() && pImp->aToDoStack.Top().pCluster == &rShell ) + { + // inverse Actions heben sich auf + if ( pImp->aToDoStack.Top().bPush != bPush ) + pImp->aToDoStack.Pop(); + else + { + DBG_ASSERT( bPush, "SfxInterface pushed more than once" ); + DBG_ASSERT( !bPush, "SfxInterface popped more than once" ); + } + } + else + { + // ::com::sun::star::chaos::Action merken + pImp->aToDoStack.Push( SfxToDo_Impl(bPush, bDelete, bUntil, rShell) ); + if ( bFlushed ) + { + bFlushed = sal_False; + pImp->bUpdated = sal_False; + + // Bindings schlafen legen + SfxBindings* pBindings = GetBindings(); + if ( pBindings ) + pBindings->DENTERREGISTRATIONS(); + } + } + + if ( !pSfxApp->IsDowning() && pImp->aToDoStack.Count() ) + { + //! if (SFX_APP()->AnyInput(INPUT_KEYBOARD | INPUT_MOUSE) ) + //! AnyInput haut nicht hin; hier muss noch ein Kriterium gefunden + //! werden. Solange wieder immer mit Timer. + + if (sal_True) + { + // Kein sofortiges Update gewuenscht + pImp->aTimer.SetTimeout(SFX_FLUSH_TIMEOUT); + pImp->aTimer.SetTimeoutHdl( LINK(this, SfxDispatcher, EventHdl_Impl ) ); + pImp->aTimer.Start(); + } + else + { + // Schnellstmoegliches Update (sollte Normalfall sein) + pImp->aTimer.Stop(); + GetpApp()->PostUserEvent(pImp->nEventId, (void*)0); + } + } + else + { + // doch nichts zu tun + pImp->aTimer.Stop(); + + // ggf. Bindings wieder aufwecken + if ( !pImp->aToDoStack.Count() ) + { + SfxBindings* pBindings = GetBindings(); + if ( pBindings ) + pBindings->DLEAVEREGISTRATIONS(); + } + } +} + +//-------------------------------------------------------------------- + +IMPL_LINK_INLINE_START( SfxDispatcher, EventHdl_Impl, void *, pvoid ) + +/* [Beschreibung] + + Dieser Handler wird nach <SfxDispatcher::Invalidate()> oder Bewegungen + auf dem Stack (<SfxDispatcher::Push()> und <SfxDispatcher::Pop()) gerufen. + + Er flusht den Stack, falls er dirty ist, f"uhrt also die ausstehenden + Push und Pop Befehle tats"achlich aus. +*/ + +{ + DBG_MEMTEST(); + + Flush(); + Update_Impl(); + SfxBindings* pBindings = GetBindings(); + if ( pBindings ) + pBindings->StartUpdate_Impl(sal_False); + return 0; +} +IMPL_LINK_INLINE_END( SfxDispatcher, EventHdl_Impl, void *, pvoid ) + +//-------------------------------------------------------------------- +sal_Bool SfxDispatcher::CheckVirtualStack( const SfxShell& rShell, sal_Bool bDeep ) + +/* [Beschreibung] + + Mit dieser Methode kann gepr"uft werden, ob sich die <SfxShell> rShell + auf dem Stack befindet, wenn er geflusht w"are. Dabei wird der + SfxDispatcher jedoch nicht tats"achlich geflusht. + + Diese Methode ist u.a. dazu gedacht, Assertions zu erm"oglichen, ohne + als Seiteneffekt den SfxDispathcer flushen zu m"ussen. +*/ + +{ + DBG_MEMTEST(); + SFX_STACK(SfxDispatcher::CheckVirtualStack); + + SfxShellStack_Impl aStack( pImp->aStack ); + for ( short nToDo = pImp->aToDoStack.Count()-1; nToDo >= 0; --nToDo ) + { + SfxToDo_Impl aToDo( pImp->aToDoStack.Top(nToDo) ); + if ( aToDo.bPush ) + aStack.Push( (SfxShell*) aToDo.pCluster ); + else + { + SfxShell* pPopped = 0; + do + { + DBG_ASSERT( aStack.Count(), "popping from empty stack" ); + pPopped = aStack.Pop(); + } + while ( aToDo.bUntil && pPopped != aToDo.pCluster ); + DBG_ASSERT( pPopped == aToDo.pCluster, "popping unpushed SfxInterface" ); + } + } + + sal_Bool bReturn; + if ( bDeep ) + bReturn = aStack.Contains(&rShell); + else + bReturn = aStack.Top() == &rShell; + return bReturn; +} + +//-------------------------------------------------------------------- +sal_uInt16 SfxDispatcher::GetShellLevel( const SfxShell& rShell ) + +/* [Beschreibung] + + Ermittelt die Position einer SfxShell im Stack des Dispatchers. + Dazu wird dieser ggf. zuvor geflusht. + + + [Rckgabewert] + + sal_uInt16 == USRT_MAX + Die SfxShell befindet sich nicht auf + diesem SfxDispatcher. + + < USHRT_MAX + Position der SfxShell auf dem Dispatcher + von oben mit 0 beginnend gez"ahlt. +*/ + +{ + DBG_MEMTEST(); + SFX_STACK(SfxDispatcher::GetShellLevel); + Flush(); + + for ( sal_uInt16 n = 0; n < pImp->aStack.Count(); ++n ) + if ( pImp->aStack.Top( n ) == &rShell ) + return n; + if ( pImp->pParent ) + { + sal_uInt16 nRet = pImp->pParent->GetShellLevel(rShell); + if ( nRet == USHRT_MAX ) + return nRet; + return nRet + pImp->aStack.Count(); + } + + return USHRT_MAX; +} + +//-------------------------------------------------------------------- +SfxShell *SfxDispatcher::GetShell(sal_uInt16 nIdx) const + +/* [Beschreibung] + + Liefert einen Pointer auf die <SfxShell>, welche sich an der Position + nIdx (von oben, letzt-gepushte liegt bei 0) auf dem Stack befindet. + + Dabei wird der SfxDispatcher nicht geflusht. + + Ist der Stack nicht tief genug, wird ein 0-Pointer zur"uckgegeben. +*/ + +{ + DBG_MEMTEST(); + + sal_uInt16 nShellCount = pImp->aStack.Count(); + if ( nIdx < nShellCount ) + return pImp->aStack.Top(nIdx); + else if ( pImp->pParent ) + return pImp->pParent->GetShell( nIdx - nShellCount ); + return 0; +} + +//-------------------------------------------------------------------- +SfxBindings* SfxDispatcher::GetBindings() const + +/* [Beschreibung] + + Diese Methode liefert einen Pointer auf die <SfxBindings> Instanz + zur"uck, an die der SfxDispatcher gerade gebunden ist. Ein SfxDispatcher + ist nur dann an SfxBindings gebunden, wenn er <UI-aktiv> ist. Ist + er nicht UI-aktiv, wird ein 0-Pointer zur"uckgegeben. + + Der zur"uckgegebene Pointer ist nur im <unmittelbaren Kontext> des + Methodenaufrufs g"ultig. +*/ + +{ + if ( pImp->pFrame ) + return &pImp->pFrame->GetBindings(); + else + return NULL; +} + +//-------------------------------------------------------------------- +SfxViewFrame* SfxDispatcher::GetFrame() const + +/* [Beschreibung] + + Liefert einen Pointer auf die <SfxViewFrame> Instanz, der dieser + SfxDispatcher geh"ort. Falls es sich um den Applikations-Dispatcher + handelt, wird ein 0-Pointer zur"uckgegeben. +*/ + +{ + DBG_MEMTEST(); + return pImp->pFrame; +} + +//-------------------------------------------------------------------- +void SfxDispatcher::DoActivate_Impl( sal_Bool bMDI ) + +/* [Beschreibung] + + Diese Methode steuert das Aktivieren eines Dispatchers. + + Da der Applikations-Dispatcher immer aktiv ist, entweder als + Unterdispatcher des <SfxViewFrame>-Dispatchers oder selbst, wird + er nie als ganzes Aktiviert, sondern nur seine einzelnen <SfxShell>s + bei <SfxDispatcher::Push(SfxShell&)>. + + Beim Aktivieren eines SfxDispatchers wird an allen auf seinem + Stack befindlichen SfxShells, beginnend mit der untersten, der Handler + <SfxShell::Activate(sal_Bool)> gerufen. +*/ + +{ + DBG_MEMTEST(); + SFX_STACK(SfxDispatcher::DoActivate); + if ( bMDI ) + { + #ifdef DBG_UTIL + ByteString sTemp("Activate Dispatcher "); + sTemp += ByteString::CreateFromInt32( (sal_uInt32) this ); + DBG_TRACE(sTemp.GetBuffer()); + DBG_ASSERT( !pImp->bActive, "Activate-Fehler" ); + #endif + pImp->bActive = sal_True; + pImp->bUpdated = sal_False; + SfxBindings* pBindings = GetBindings(); + if ( pBindings ) + { + pBindings->SetDispatcher(this); + pBindings->SetActiveFrame( ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > () ); + } + } + else + { + #ifdef DBG_UTIL + ByteString sTemp("Non-MDI-Activate Dispatcher"); + sTemp += ByteString::CreateFromInt32( (sal_uInt32) this ); + DBG_TRACE( sTemp.GetBuffer() ); + #endif + } + + if ( IsAppDispatcher() ) + return; + + for ( int i = int(pImp->aStack.Count()) - 1; i >= 0; --i ) + pImp->aStack.Top( (sal_uInt16) i )->DoActivate(pImp->pFrame, bMDI); + + if ( pImp->aToDoStack.Count() ) + { + if (sal_True) + { + // Kein sofortiges Update gewuenscht + pImp->aTimer.SetTimeout(SFX_FLUSH_TIMEOUT); + pImp->aTimer.SetTimeoutHdl( LINK(this, SfxDispatcher, EventHdl_Impl ) ); + pImp->aTimer.Start(); + } + else + { + // Schnellstmoegliches Update (sollte Normalfall sein) + pImp->aTimer.Stop(); + GetpApp()->PostUserEvent(pImp->nEventId, (void*)0); + } + } +} + +void SfxDispatcher::DoParentActivate_Impl() +{ + for ( int i = int(pImp->aStack.Count()) - 1; i >= 0; --i ) + pImp->aStack.Top( (sal_uInt16) i )->ParentActivate(); +} + +//-------------------------------------------------------------------- +void SfxDispatcher::DoDeactivate_Impl( sal_Bool bMDI ) + +/* [Beschreibung] + + Diese Methode steuert das Deaktivieren eines Dispatchers. + + Da der Applikations-Dispatcher immer aktiv ist, entweder als + Unterdispatcher des <SfxViewFrame>-Dispatchers oder selbst, wird + er nie als ganzes Deaktiviert, sondern nur seine einzelnen <SfxShell>s + bei <SfxDispatcher::Pop(SfxShell&)>. + + Beim Deaktivieren eines SfxDispatchers wird an allen auf seinem + Stack befindlichen SfxShells, beginnend mit der obersten, der Handler + <SfxShell::Deactivate(sal_Bool)> gerufen. +*/ + +{ + DBG_MEMTEST(); + SFX_STACK(SfxDispatcher::DoDeactivate); + + SfxApplication *pSfxApp = SFX_APP(); + + if ( bMDI ) + { + DBG_TRACE(ByteString("Deactivate Dispatcher ").Append(ByteString::CreateFromInt32( (sal_uInt32) this )).GetBuffer()); + DBG_ASSERT( pImp->bActive, "Deactivate-Fehler" ); + pImp->bActive = sal_False; + + if ( pImp->pFrame && !pImp->pFrame->IsA(TYPE(SfxInPlaceFrame)) ) + { + SfxWorkWindow *pWorkWin = pSfxApp->GetWorkWindow_Impl(pImp->pFrame); + for (sal_uInt16 n=0; n<pImp->aChildWins.Count();) + { + SfxChildWindow *pWin = + pWorkWin->GetChildWindow_Impl( + (sal_uInt16) ( pImp->aChildWins[n] & 0xFFFF ) ); + if (!pWin || pWin && pWin->GetAlignment() == SFX_ALIGN_NOALIGNMENT) + pImp->aChildWins.Remove(n); + else + n++; + } + } + } + else + DBG_TRACE( ByteString ("Non-MDI-DeActivate Dispatcher").Append(ByteString::CreateFromInt32( (sal_uInt32) this )).GetBuffer() ); + + if ( IsAppDispatcher() && !pSfxApp->IsDowning() ) + return; + + for ( sal_uInt16 i = 0; i < pImp->aStack.Count(); ++i ) + pImp->aStack.Top(i)->DoDeactivate(pImp->pFrame, bMDI); + + Flush(); +} + +void SfxDispatcher::DoParentDeactivate_Impl() +{ + for ( int i = int(pImp->aStack.Count()) - 1; i >= 0; --i ) + pImp->aStack.Top( (sal_uInt16) i )->ParentDeactivate(); +} + +//-------------------------------------------------------------------- +int SfxDispatcher::GetShellAndSlot_Impl +( + sal_uInt16 nSlot, // die zu suchende Slot-Id + SfxShell** ppShell, // die SfxShell, welche nSlot z.Zt. bedient + const SfxSlot** ppSlot, // der SfxSlot, welcher nSlot z.Zt. bedient + sal_Bool bOwnShellsOnly, + sal_Bool bModal // trotz ModalMode +) + +/* [Beschreibung] + + Diese Methode sucht im SfxDispatcher nach der <SfxShell>, von der + die Slot-Id nSlot zur Zeit bedient wird. Dazu wird der Dispatcher + zuvor geflusht. + + + [R"uckgabewert] + + int sal_True + Die SfxShell wurde gefunden, ppShell und ppSlot + sind g"ultig. + + sal_True + Die SfxShell wurde nicht gefunden, ppShell und ppSlot + sind ung"ultig. +*/ + +{ + SFX_STACK(SfxDispatcher::GetShellAndSlot_Impl); + + Flush(); + SfxSlotServer aSvr; + if ( _FindServer(nSlot, aSvr, bModal) ) + { + if ( bOwnShellsOnly && aSvr.GetShellLevel() >= pImp->aStack.Count() ) + return sal_False; + + *ppShell = GetShell(aSvr.GetShellLevel()); + *ppSlot = aSvr.GetSlot(); + if ( 0 == (*ppSlot)->GetExecFnc() ) + *ppSlot = (*ppShell)->GetInterface()->GetRealSlot(*ppSlot); + +#ifdef DBG_UTILx + ByteString aMsg( nSlot ); + aMsg += " found in "; + aMsg += (*ppShell)->GetInterface()->GetClassName(); + DbgTrace( aMsg.GetBuffer() ); +#endif + + return sal_True; + } + +#ifdef DBG_UTILx + ByteString aMsg( nSlot ); + aMsg += " not found"; + DbgTrace( aMsg.GetBuffer() ); +#endif + + return sal_False; +} + +/* +struct Executer : public SfxHint +{ + SfxRequest *pRequest; + const SfxSlot* pSlot; + sal_uInt16 nLevel; + + Executer( SfxRequest* pReq, const SfxSlot* p, sal_uInt16 n ) + : pRequest( pReq ) + , pSlot(p) + , nLevel(n) + {} + ~Executer() + {delete pRequest;} +}; +*/ + +//-------------------------------------------------------------------- +void SfxDispatcher::_Execute +( + SfxShell& rShell, // zu rufende <SfxShell> + const SfxSlot& rSlot, // zu rufender <SfxSlot> + SfxRequest& rReq, // auszuf"uhrende Funktion (Id und optional Parameter) + SfxCallMode eCallMode // synchron, asynchron oder wie beim Slot angegeben +) + +/* [Beschreibung] + + Diese Methode f"uhrt einen Request "uber einen gecachten <Slot-Server> + aus. +*/ + +{ + DBG_MEMTEST(); + DBG_ASSERT( !pImp->bFlushing, "recursive call to dispatcher" ); + DBG_ASSERT( !pImp->aToDoStack.Count(), "unprepared InPlace _Execute" ); + + if ( IsLocked( rSlot.GetSlotId() ) ) + return; + + sal_uInt16 nSlot = rSlot.GetSlotId(); + if ( SfxMacroConfig::IsMacroSlot( nSlot ) ) + SFX_APP()->GetMacroConfig()->RegisterSlotId( nSlot ); + + if ( (eCallMode & SFX_CALLMODE_ASYNCHRON) || + ( !(eCallMode & SFX_CALLMODE_SYNCHRON) && + rSlot.IsMode(SFX_SLOT_ASYNCHRON) ) ) + { + SfxDispatcher *pDispat = this; + while ( pDispat ) + { + sal_uInt16 nShellCount = pDispat->pImp->aStack.Count(); + for ( sal_uInt16 n=0; n<nShellCount; n++ ) + { + if ( &rShell == pDispat->pImp->aStack.Top(n) ) + { + pDispat->pImp->xPoster->Post(new SfxRequest(rReq)); +// pDispat->pImp->xPoster->Post(new Executer(new SfxRequest(rReq), &rSlot, n )); + return; + } + } + + pDispat = pDispat->pImp->pParent; + } + } + else + Call_Impl( rShell, rSlot, rReq, SFX_CALLMODE_RECORD==(eCallMode&SFX_CALLMODE_RECORD) ); +} + +//-------------------------------------------------------------------- +void MappedPut_Impl( SfxAllItemSet &rSet, const SfxPoolItem &rItem ) + +/* [Beschreibung] + + Hilfsfunktion zum putten von rItem unter der im Pool des Item-Sets + rSet geltenden Which-Id. +*/ + +{ + // mit ggf. gemappter Which-Id putten + const SfxItemPool *pPool = rSet.GetPool(); + sal_uInt16 nWhich = rItem.Which(); +#ifdef TF_POOLABLE + if ( pPool->IsSlot(nWhich) ) +#else + if ( pPool->HasMap() && pPool->IsSlot(nWhich) ) +#endif + nWhich = pPool->GetWhich(nWhich); + rSet.Put( rItem, nWhich ); +} + +//-------------------------------------------------------------------- + +#ifndef SFX_USE_BINDINGS +#define SFX_USE_BINDINGS 0x8000 +#endif + +sal_uInt16 SfxDispatcher::ExecuteFunction( sal_uInt16 nSlot, SfxPoolItem **pArgs, + sal_uInt16 nMode ) +{ + if ( !nMode ) + nMode = pImp->nStandardMode; + + // via Bindings/Interceptor? (dann ist der Returnwert nicht exakt) + sal_Bool bViaBindings = SFX_USE_BINDINGS == ( nMode & SFX_USE_BINDINGS ); + nMode &= ~sal_uInt16(SFX_USE_BINDINGS); + if ( bViaBindings && GetBindings() ) + return GetBindings()->Execute( nSlot, (const SfxPoolItem **) pArgs, nMode ) + ? EXECUTE_POSSIBLE + : EXECUTE_NO; + + // sonst via Dispatcher + if ( IsLocked(nSlot) ) + return 0; + SfxShell *pShell = 0; + SfxCallMode eCall = SFX_CALLMODE_SYNCHRON; + sal_uInt16 nRet = EXECUTE_NO; + const SfxSlot *pSlot = 0; + if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, sal_False, sal_False ) ) + { + // Ausf"uhrbarkeit vorher testen + if ( pSlot->IsMode( SFX_SLOT_FASTCALL ) || + pShell->CanExecuteSlot_Impl( *pSlot ) ) + nRet = EXECUTE_POSSIBLE; + + if ( nMode == EXECUTEMODE_ASYNCHRON ) + eCall = SFX_CALLMODE_ASYNCHRON; + else if ( nMode == EXECUTEMODE_DIALOGASYNCHRON && pSlot->IsMode( SFX_SLOT_HASDIALOG ) ) + eCall = SFX_CALLMODE_ASYNCHRON; + else if ( pSlot->GetMode() & SFX_SLOT_ASYNCHRON ) + eCall = SFX_CALLMODE_ASYNCHRON; + sal_Bool bDone = sal_False; + if ( pArgs && *pArgs ) + { + SfxAllItemSet aSet( pShell->GetPool() ); + for ( SfxPoolItem **pArg = pArgs; *pArg; ++pArg ) + MappedPut_Impl( aSet, **pArg ); + SfxRequest aReq( nSlot, eCall, aSet ); + _Execute( *pShell, *pSlot, aReq, eCall ); + bDone = aReq.IsDone(); + } + else + { + SfxRequest aReq( nSlot, eCall, pShell->GetPool() ); + _Execute( *pShell, *pSlot, aReq, eCall ); + bDone = aReq.IsDone(); + } + } + + return nRet; +} + +sal_uInt16 SfxDispatcher::GetSlotId( const String& rCommand ) +{ + // Anzahl der Shells auf den verkettenten Dispatchern z"ahlen + Flush(); + sal_uInt16 nTotCount = pImp->aStack.Count(); + if ( pImp->pParent ) + { + SfxDispatcher *pParent = pImp->pParent; + while ( pParent ) + { + nTotCount += pParent->pImp->aStack.Count(); + pParent = pParent->pImp->pParent; + } + } + + const SfxSlot *pSlot=NULL; + sal_uInt16 nFirstShell = 0; + for ( sal_uInt16 i = nFirstShell; i < nTotCount; ++i ) + { + SfxShell *pObjShell = GetShell(i); + SfxInterface *pIFace = pObjShell->GetInterface(); + pSlot = pIFace->GetSlot( rCommand ); + if ( pSlot ) + return pSlot->GetSlotId(); + } + + return 0; +} + +//-------------------------------------------------------------------- +int SfxExecuteItem::operator==( const SfxPoolItem& rItem ) const +{ + SfxExecuteItem& rArg = (SfxExecuteItem& )rItem; + sal_uInt16 nCount = Count(); + if( nCount != rArg.Count() ) + return sal_False; + while( nCount -- ) + if( *GetObject( nCount ) != *rArg.GetObject( nCount ) ) + return sal_False; + return eCall == rArg.eCall; +} + +//-------------------------------------------------------------------- +SfxPoolItem* SfxExecuteItem::Clone( SfxItemPool* pPool ) const +{ + return new SfxExecuteItem( *this ); +} + +//-------------------------------------------------------------------- +SfxExecuteItem::SfxExecuteItem( const SfxExecuteItem& rArg ) + : SfxPoolItem( rArg ), nModifier( 0 ) +{ + eCall = rArg.eCall; + nSlot = rArg.nSlot; + sal_uInt16 nCount = rArg.Count(); + for( sal_uInt16 nPos = 0; nPos < nCount; nPos++ ) + Insert( rArg[ nPos ]->Clone(), nPos ); +} + +//-------------------------------------------------------------------- +SfxExecuteItem::SfxExecuteItem( + sal_uInt16 nWhich, sal_uInt16 nSlotP, SfxCallMode eModeP, + const SfxPoolItem* pArg1, ... ) : + SfxPoolItem( nWhich ), eCall( eModeP ), nSlot( nSlotP ), nModifier( 0 ) +{ + va_list pVarArgs; + va_start( pVarArgs, pArg1 ); + for ( const SfxPoolItem *pArg = pArg1; pArg; + pArg = va_arg( pVarArgs, const SfxPoolItem* ) ) + Insert( pArg->Clone(), Count() ); + va_end(pVarArgs); +} + +//-------------------------------------------------------------------- +SfxExecuteItem::SfxExecuteItem( + sal_uInt16 nWhich, sal_uInt16 nSlotP, SfxCallMode eModeP ) + : SfxPoolItem( nWhich ), nSlot( nSlotP ), eCall( eModeP ), nModifier( 0 ) +{ +} + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxDispatcher::Execute( const SfxExecuteItem& rItem ) +{ + const SfxPoolItem** pPtr = new const SfxPoolItem*[ rItem.Count() + 1 ]; + for( sal_uInt16 nPos = rItem.Count(); nPos--; ) + pPtr[ nPos ] = rItem.GetObject( nPos ); + pPtr[ rItem.Count() ] = 0; + const SfxPoolItem* pRet = Execute( + rItem.GetSlot(), rItem.GetCallMode(), pPtr, rItem.GetModifier() ); + + __DELETE(rItem.Count() + 1) (SfxPoolItem**)pPtr; + + return pRet; +} + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxDispatcher::Execute +( + sal_uInt16 nSlot, // die Id der auszufuehrenden Funktion + SfxCallMode eCall, // SFX_CALLMODE_SYNCRHON, ..._ASYNCHRON oder ..._SLOT + const SfxPoolItem **pArgs, // 0-terminiertes C-Array von Parametern + sal_uInt16 nModi, + const SfxPoolItem **pInternalArgs // 0-terminiertes C-Array von Parametern +) + +/* [Beschreibung] + + Methode zum Ausf"uhren eines <SfxSlot>s "uber die Slot-Id. + + + [R"uckgabewert] + + const SfxPoolItem* Pointer auf ein bis zum n"achsten Durchlauf + der Message-Loop g"ultiges SfxPoolItem, + welches den R"uckgabewert enth"alt. + + Oder ein 0-Pointer, wenn die Funktion nicht + ausgef"uhrt wurde (z.B. Abbruch durch den + Benutzer). +*/ + +{ + if ( IsLocked(nSlot) ) + return 0; + + SfxShell *pShell = 0; + const SfxSlot *pSlot = 0; + if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, sal_False, + SFX_CALLMODE_MODAL==(eCall&SFX_CALLMODE_MODAL) ) ) + { + SfxRequest* pReq; + if ( pArgs && *pArgs ) + { + SfxAllItemSet aSet( pShell->GetPool() ); + for ( const SfxPoolItem **pArg = pArgs; *pArg; ++pArg ) + MappedPut_Impl( aSet, **pArg ); + pReq = new SfxRequest( nSlot, eCall, aSet ); + } + else + pReq = new SfxRequest( nSlot, eCall, pShell->GetPool() ); + pReq->SetModifier( nModi ); + if( pInternalArgs && *pInternalArgs) + { + SfxAllItemSet aSet( SFX_APP()->GetPool() ); + for ( const SfxPoolItem **pArg = pInternalArgs; *pArg; ++pArg ) + aSet.Put( **pArg ); + pReq->SetInternalArgs_Impl( aSet ); + } + _Execute( *pShell, *pSlot, *pReq, eCall ); + const SfxPoolItem* pRet = pReq->GetReturnValue(); + delete pReq; return pRet; + } + return 0; +} + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxDispatcher::Execute +( + sal_uInt16 nSlot, // die Id der auszufuehrenden Funktion + SfxCallMode eCall, // SFX_CALLMODE_SYNCRHON, ..._ASYNCHRON oder ..._SLOT + const SfxItemSet &rArgs // <SfxItemSet> mit Parametern +) + +/* [Beschreibung] + + Methode zum Ausf"uhren eines <SfxSlot>s "uber die Slot-Id. + + + [R"uckgabewert] + + const SfxPoolItem* Pointer auf ein bis zum n"achsten Durchlauf + der Message-Loop g"ultiges SfxPoolItem, + welches den R"uckgabewert enth"alt. + + Oder ein 0-Pointer, wenn die Funktion nicht + ausgef"uhrt wurde (z.B. Abbruch durch den + Benutzer). +*/ + +{ + if ( IsLocked(nSlot) ) + return 0; + + SfxShell *pShell = 0; + const SfxSlot *pSlot = 0; + if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, sal_False, + SFX_CALLMODE_MODAL==(eCall&SFX_CALLMODE_MODAL) ) ) + { + SfxAllItemSet aSet( pShell->GetPool() ); + SfxItemIter aIter(rArgs); + for ( const SfxPoolItem *pArg = aIter.FirstItem(); + pArg; + pArg = aIter.NextItem() ) + MappedPut_Impl( aSet, *pArg ); + SfxRequest aReq( nSlot, eCall, aSet ); + _Execute( *pShell, *pSlot, aReq, eCall ); + return aReq.GetReturnValue(); + } + return 0; +} + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxDispatcher::_Execute +( + sal_uInt16 nSlot, // die Id der auszufuehrenden Funktion + SfxCallMode eCall, // SFX_CALLMODE_SYNCRHON, ..._ASYNCHRON oder ..._SLOT + va_list pVarArgs, // Parameterliste ab 2. Parameter + const SfxPoolItem* pArg1 // erster Parameter +) + +/* [Beschreibung] + + Methode zum Ausf"uhren eines <SfxSlot>s "uber die Slot-Id. + + + [R"uckgabewert] + + const SfxPoolItem* Pointer auf ein bis zum n"achsten Durchlauf + der Message-Loop g"ultiges SfxPoolItem, + welches den R"uckgabewert enth"alt. + + Oder ein 0-Pointer, wenn die Funktion nicht + ausgef"uhrt wurde (z.B. Abbruch durch den + Benutzer). +*/ + +{ + if ( IsLocked(nSlot) ) + return 0; + + SfxShell *pShell = 0; + const SfxSlot *pSlot = 0; + if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, sal_False, + SFX_CALLMODE_MODAL==(eCall&SFX_CALLMODE_MODAL) ) ) + { + SfxAllItemSet aSet( pShell->GetPool() ); + + for ( const SfxPoolItem *pArg = pArg1; + pArg; + pArg = va_arg( pVarArgs, const SfxPoolItem* ) ) + MappedPut_Impl( aSet, *pArg ); + + SfxRequest aReq( nSlot, eCall, aSet ); + _Execute( *pShell, *pSlot, aReq, eCall ); + return aReq.GetReturnValue(); + } + return 0; +} + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxDispatcher::Execute +( + sal_uInt16 nSlot, // die Id der auszufuehrenden Funktion + SfxCallMode eCall, // SFX_CALLMODE_SYNCRHON, ..._ASYNCHRON oder ..._SLOT + const SfxPoolItem* pArg1, // erster Parameter + ... // 0-terminiertes Liste Parametern +) + +/* [Beschreibung] + + Methode zum Ausf"uhren eines <SfxSlot>s "uber die Slot-Id. + + + [Anmerkung] + + Die Parameter werden kopiert, k"onnen daher als Adresse von + Stack-Objekten "ubergeben werden. + + + [R"uckgabewert] + + const SfxPoolItem* Pointer auf ein bis zum n"achsten Durchlauf + der Message-Loop g"ultiges SfxPoolItem, + welches den R"uckgabewert enth"alt. + + Oder ein 0-Pointer, wenn die Funktion nicht + ausgef"uhrt wurde (z.B. Abbruch durch den + Benutzer). + + + [Beispiel] + + pDispatcher->Execute( SID_OPENDOCUMENT, SFX_CALLMODE_SYNCHRON, + &SfxStringItem( SID_FILE_NAME, "\\tmp\\temp.sdd" ), + &SfxStringItem( SID_FILTER_NAME, "StarDraw Presentation" ), + &SfxBoolItem( SID_DOC_READONLY, sal_False ), + 0L ); +*/ + +{ + if ( IsLocked(nSlot) ) + return 0; + + SfxShell *pShell = 0; + const SfxSlot *pSlot = 0; + if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, sal_False, + SFX_CALLMODE_MODAL==(eCall&SFX_CALLMODE_MODAL) ) ) + { + SfxAllItemSet aSet( pShell->GetPool() ); + + va_list pVarArgs; + va_start( pVarArgs, pArg1 ); + for ( const SfxPoolItem *pArg = pArg1; + pArg; + pArg = va_arg( pVarArgs, const SfxPoolItem* ) ) + MappedPut_Impl( aSet, *pArg ); + va_end(pVarArgs); + + SfxRequest aReq( nSlot, eCall, aSet ); + _Execute( *pShell, *pSlot, aReq, eCall ); + return aReq.GetReturnValue(); + } + return 0; +} + +//-------------------------------------------------------------------- + +IMPL_LINK( SfxDispatcher, PostMsgHandler, SfxRequest*, pReq ) + +/* [Beschreibung] + + Hilfsmethode zum Empfangen der asynchron auszuf"uhrenden <SfxRequest>s. +*/ + +{ + DBG_MEMTEST(); + DBG_ASSERT( !pImp->bFlushing, "recursive call to dispatcher" ); + SFX_STACK(SfxDispatcher::PostMsgHandler); + + // ist auch der Pool noch nicht gestorben? +// SfxRequest* pReq = pExec->pRequest; + if ( !pReq->IsCancelled() ) + { + if ( !IsLocked(pReq->GetSlot()) ) + { + Flush(); + SfxSlotServer aSvr; + if ( _FindServer(pReq->GetSlot(), aSvr, HACK(x) sal_True ) ) +// SfxShell *pShell = GetShell(pExec->nLevel); +// if ( pShell && pShell->GetInterface()->GetSlot( pExec->pSlot->GetSlotId() ) ) + { + const SfxSlot *pSlot = aSvr.GetSlot(); + SfxShell *pSh = GetShell(aSvr.GetShellLevel()); + + DBG( SfxApplication *pSfxApp = SFX_APP() ); + DBG( pSfxApp->EnterAsynchronCall_Impl() ); + + // Wenn pSlot ein "Pseudoslot" f"ur Macros oder Verben ist, kann + // er im Call_Impl zerst"ort werden, also nicht mehr benutzen! + pReq->SetSynchronCall( sal_False ); + Call_Impl( *pSh, *pSlot, *pReq, sal_True ); //! woher bRecord? +// Call_Impl( *pShell, *pExec->pSlot, *pReq, sal_True ); //! woher bRecord? + DBG( pSfxApp->LeaveAsynchronCall_Impl() ); + } + +// delete pExec; + } + else + { +// pImp->xPoster->Post(pExec); + pImp->xPoster->Post(new SfxRequest(*pReq)); + } + } +// else +// delete pExec; + + delete pReq; + return 0; +} +//-------------------------------------------------------------------- +void SfxDispatcher::EnterAction( const String& rName ) + +// marks the beginning of a block of actions + +{ + DBG_MEMTEST(); + Flush(); + DBG_ASSERT( pImp->aStack.Count() > 0, "EnterAction on empty dispatcher stack" ); + if ( ++pImp->nActionLevel == 1 ) + { + SfxUndoManager *pUndoMgr = GetShell(0)->GetUndoManager(); + if ( pUndoMgr ) + pUndoMgr->EnterListAction( rName, rName HACK(RepeatComment), 0 HACK(ID) ); + } +} +//-------------------------------------------------------------------- +void SfxDispatcher::LeaveAction() + +// marks the end of a block of actions + +{ + DBG_MEMTEST(); + DBG_ASSERT( pImp->nActionLevel > 0, "EnterAction without LeaveAction" ); + if ( --pImp->nActionLevel == 0 ) + { + SfxUndoManager *pUndoMgr = GetShell(0)->GetUndoManager(); + if ( pUndoMgr ) + pUndoMgr->LeaveListAction(); + } +} +//-------------------------------------------------------------------- +void SfxDispatcher::SetMenu_Impl() +{ + SfxApplication *pSfxApp = SFX_APP(); + if ( pImp->pFrame ) + { + if ( !pImp->pFrame->GetViewShell() ) + return; + + SfxTopViewFrame* pTop= PTR_CAST( SfxTopViewFrame, pImp->pFrame->GetTopViewFrame() ); + if ( pTop && pTop->GetBindings().GetDispatcher() == this ) + { + SfxTopFrame* pFrm = pTop->GetTopFrame_Impl(); + SfxMenuBarManager* pMenuBar = pImp->pFrame->GetViewShell()->GetMenuBar_Impl(); + if ( pMenuBar ) + { + MenuBar* pMenu = (MenuBar*) pMenuBar->GetMenu()->GetSVMenu(); + pFrm->LockResize_Impl( TRUE ); + pFrm->SetMenuBar_Impl( pMenu ); + pFrm->LockResize_Impl( FALSE ); + } + else if ( pImp->pParent ) + { + pImp->pParent->SetMenu_Impl(); + } + } + } +} + +long SfxDispatcher::Update_Impl( sal_Bool bForce ) + +/* [Beschreibung] + + Hilfsmethode zum Updaten der <Object-Bars> und <Object-Menus>, + nach Bewegungen auf dem Stack. +*/ + +{ + SFX_STACK(SfxDispatcher::Update_Impl); + + Flush(); + + if ( !pImp->pFrame ) + return 0; + + if ( pImp->bUILocked ) + return 0; + + SfxApplication *pSfxApp = SFX_APP(); + SfxDispatcher *pDisp = this; + sal_Bool bUpdate = bForce; + while ( pDisp && pDisp->pImp->pFrame ) + { + SfxWorkWindow *pWork = pSfxApp->GetWorkWindow_Impl( pDisp->pImp->pFrame ); + SfxDispatcher *pAct = pWork->GetBindings().GetDispatcher_Impl(); + if ( pAct == pDisp || pAct == this ) + { + if ( !bUpdate ) + bUpdate = !pDisp->pImp->bUpdated; + pDisp->pImp->bUpdated = sal_True; + } + else + break; + + pDisp = pDisp->pImp->pParent; + } + + if ( !bUpdate ) + return 0; + + SfxTopViewFrame* pTop = pImp->pFrame ? PTR_CAST( SfxTopViewFrame, pImp->pFrame->GetTopViewFrame() ) : NULL; + sal_Bool bUIActive = pTop && pTop->GetBindings().GetDispatcher() == this; + SfxMenuBarManager* pAppMenu = NULL; + + if ( !bUIActive && pTop && GetBindings() == &pTop->GetBindings() ) + // Eigene Tools nur intern festhalten und da"fur sorgen, da\s der + // aktive Dispatcher sie abholt + GetBindings()->GetDispatcher()->pImp->bUpdated = sal_False; + + // Bindings schlafen legen + SfxBindings* pBindings = GetBindings(); + if ( pBindings ) + pBindings->DENTERREGISTRATIONS(); + + // Test auf InPlaceFrame und speziell internes InPlace + SfxInPlaceFrame *pIPFrame = PTR_CAST ( SfxInPlaceFrame, pImp->pFrame); + sal_Bool bIsIPOwner = (pIPFrame && pIPFrame->GetObjectShell()->GetInPlaceObject()->GetIPClient()->Owner()); + SvInPlaceClient *pClient = pImp->pFrame ? pImp->pFrame->GetViewShell()->GetIPClient() : NULL; + if ( bUIActive && !pIPFrame && ( !pClient || !pClient->GetProtocol().IsUIActive() ) ) + { + SetMenu_Impl(); + pAppMenu = pImp->pFrame->GetViewShell()->GetMenuBar_Impl(); + pAppMenu->ResetObjectMenus(); + } + + // Environment + SfxWorkWindow *pWorkWin = pSfxApp->GetWorkWindow_Impl(pImp->pFrame); + + // der SfxInternalFrame oder SfxTopViewFrame, zu dem ich geh"ore + SfxViewFrame *pAct = + bIsIPOwner ? + pImp->pFrame->GetParentViewFrame_Impl() : + pImp->pFrame; + + // Ich kontrolliere die StatusBar einer Task auch wenn ich nicht aktiv bin, aber + // zu einem internem InPlaceFrame oder einem anderen ViewFrame innerhalb der Task geh"ore + SfxFrame *pTask = pAct ? pAct->GetFrame()->GetTopFrame() : NULL; + + SfxWorkWindow *pTaskWin = NULL; + sal_Bool bSet = sal_True; + if ( pImp->pFrame && pImp->pFrame->GetViewShell() ) + { + SvInPlaceClient *pClient = pImp->pFrame->GetViewShell()->GetIPClient(); + if ( pClient && pClient->GetProtocol().IsUIActive() ) + bSet = sal_False; + } + + if ( pTask && bSet ) + { + pTaskWin = pTask->GetWorkWindow_Impl(); + pTaskWin->ResetStatusBar_Impl(); + } + + SfxDispatcher *pDispat = this; + while ( pDispat ) + { + SfxWorkWindow *pWork = pSfxApp->GetWorkWindow_Impl(pDispat->pImp->pFrame); + SfxDispatcher *pAct = pWork->GetBindings().GetDispatcher_Impl(); + if ( pAct == pDispat || pAct == this ) + { + pWork->ResetObjectBars_Impl(); + pWork->ResetChildWindows_Impl(); + } + + pDispat = pDispat->pImp->pParent; + } + + sal_Bool bIsActive = sal_False; + SfxDispatcher *pActDispat = pWorkWin->GetBindings().GetDispatcher_Impl(); + pDispat = this; + while ( pActDispat && !bIsActive ) + { + if ( pDispat == pActDispat ) + bIsActive = sal_True; + pActDispat = pActDispat->pImp->pParent; + } + + if ( !pIPFrame && !IsAppDispatcher() && bIsActive ) + CollectTools_Impl( pWorkWin ); + + // Jetzt rekursiv die Dispatcher abklappern + sal_uInt32 nHelpId = _Update_Impl( bUIActive, !pIPFrame, bIsIPOwner, pAppMenu, bSet ? pTaskWin : NULL ); + if ( bUIActive || bIsActive ) + { + pWorkWin->UpdateObjectBars_Impl(); + + if ( pAppMenu ) + pAppMenu->UpdateObjectMenus(); + + if ( bUIActive ) + { + // ggf. Hilfe-PI antriggern + SfxHelpPI* pHelpPI = pSfxApp->GetHelpPI(); + if (pHelpPI && nHelpId) + pHelpPI->LoadTopic( nHelpId ); + } + } + + if ( pTaskWin ) + pTaskWin->UpdateStatusBar_Impl(); + + if ( pBindings ) + pBindings->DLEAVEREGISTRATIONS(); + return 1; +} + + +void SfxDispatcher::CollectTools_Impl( SfxWorkWindow* pWorkWin ) +{ + // Innerhalb eines ToolSpace werden auch die Tools von nicht aktiven Frames + // angezeigt, damit es beim Wechsel der Frames nicht zappelt + SfxApplication *pSfxApp = SFX_APP(); + SfxToolBoxConfig *pTbxCfg = SfxToolBoxConfig::GetOrCreate(); + + // Die Objectbars aller ViewFrames der aktuellen Task einsammeln + for ( SfxViewFrame* pViewFrame = SfxViewFrame::GetFirst(); + pViewFrame; + pViewFrame = SfxViewFrame::GetNext(*pViewFrame) ) + { + // Frames mit anderem WorkWindow interessieren hier nicht + if ( pViewFrame->GetFrame()->GetWorkWindow_Impl() != pWorkWin ) + continue; + + // Nur weitermachen, wenn es nicht sowieso einer meiner parents ist + SfxDispatcher *pDispat = pViewFrame->GetDispatcher(); + SfxDispatcher *pParent = this; + while ( pParent ) + { + if ( pParent == pDispat ) + break; + pParent = pParent->pImp->pParent; + } + + if ( pParent ) + continue; + + // Alle objectbars des ViewFrames vormerken + sal_uInt16 n; + for (n=0; n<SFX_OBJECTBAR_MAX; n++) + { + SfxObjectBars_Impl& rBar = pDispat->pImp->aObjBars[n]; + sal_uInt16 nId = rBar.aResId.GetId(); + if ( nId && pTbxCfg->GetAlignment(n) != SFX_ALIGN_NOALIGNMENT ) + pWorkWin->SetObjectBar_Impl( rBar.nMode, + rBar.aResId, rBar.pIFace, &rBar.aName ); + } + + SfxShell *pShell = pDispat->GetShell(0); + SfxModule *pMod = pShell->GetInterface()->GetModule(); + SfxSlotPool& rSlotPool = pMod ? *pMod->GetSlotPool() : pShell->GetSlotPool_Impl(); + + // ChildWindows auch "bunkern" + for (n=0; n<pDispat->pImp->aChildWins.Count(); n++) + { + sal_uInt32 nId = pDispat->pImp->aChildWins[n]; + const SfxSlot *pSlot = rSlotPool.GetSlot( (sal_uInt16) nId ); + sal_uInt16 nMode = SFX_VISIBILITY_STANDARD; + if( pSlot ) + { + if ( pSlot->IsMode(SFX_SLOT_CONTAINER) ) + { + if ( !pWorkWin->IsVisible_Impl( SFX_VISIBILITY_CLIENT ) ) + continue; + nMode |= SFX_VISIBILITY_CLIENT; + } + else + { + if ( !pWorkWin->IsVisible_Impl( SFX_VISIBILITY_SERVER ) ) + continue; + nMode |= SFX_VISIBILITY_SERVER; + } + } + + pWorkWin->SetChildWindowVisible_Impl( nId, sal_False, nMode ); + } + } +} + + +sal_uInt32 SfxDispatcher::_Update_Impl( sal_Bool bUIActive, sal_Bool bIsMDIApp, + sal_Bool bIsIPOwner, SfxMenuBarManager *pAppMenu, SfxWorkWindow *pTaskWin ) +{ + sal_uInt32 nHelpId = 0L; + SfxApplication *pSfxApp = SFX_APP(); + SfxWorkWindow *pWorkWin = pSfxApp->GetWorkWindow_Impl( pImp->pFrame ); + sal_Bool bIsActive = sal_False; + sal_Bool bIsTaskActive = sal_False; + SfxDispatcher *pActDispat = pWorkWin->GetBindings().GetDispatcher_Impl(); + SfxDispatcher *pDispat = this; + while ( pActDispat && !bIsActive ) + { + if ( pDispat == pActDispat ) + bIsActive = sal_True; + pActDispat = pActDispat->pImp->pParent; + } + + if ( pImp->pParent && !pImp->bQuiet /* && bUIActive */ ) + // Das Men"u kommt immer vom obersten Dispatcher, also pAppMenu nicht weiterreichen + nHelpId = pImp->pParent->_Update_Impl( bUIActive, bIsMDIApp, bIsIPOwner, NULL, pTaskWin ); + + // Internen Zwischenspeicher ObjectBars und ChildWindows zur"ucksetzen + for (sal_uInt16 n=0; n<SFX_OBJECTBAR_MAX; n++) + pImp->aObjBars[n].aResId = ResId( 0,0 ); + pImp->aChildWins.Remove(0, pImp->aChildWins.Count()); + + // bQuiet : eigene Shells weder f"ur UI noch f"ur SlotServer ber"ucksichtigen + // bNoUI: eigene Shells f"ur das UI nicht ber"ucksichtigen + if ( pImp->bQuiet || pImp->bNoUI || pImp->pFrame && pImp->pFrame->GetObjectShell()->IsPreview() ) + return nHelpId; + + sal_uInt16 nStatBarId=0; + SfxShell *pStatusBarShell = NULL; + + sal_uInt16 nTotCount = pImp->aStack.Count(); + for ( sal_uInt16 nShell = nTotCount; nShell > 0; --nShell ) + { + SfxShell *pShell = GetShell( nShell-1 ); + SfxInterface *pIFace = pShell->GetInterface(); + if (pShell->GetHelpId()) + nHelpId = pShell->GetHelpId(); + + // Shells von Dispatcher mit Attribut "Hidden" oder "Quiet" auslassen + sal_Bool bReadOnlyShell = IsReadOnlyShell_Impl( nShell-1 ); + SfxSlotPool& rSlotPool = pIFace->GetModule() ? + *pIFace->GetModule()->GetSlotPool() : pShell->GetSlotPool_Impl(); + + sal_uInt16 nNo; + for ( nNo = 0; pIFace && nNo<pIFace->GetObjectBarCount(); ++nNo ) + { + sal_uInt16 nPos = pIFace->GetObjectBarPos(nNo); + if ( bReadOnlyShell && !( nPos & SFX_VISIBILITY_READONLYDOC ) ) + continue; + + // Soll die ObjectBar nur angezeigt werden, wenn die Shell + // einen bestimmten UI-Modus hat? + sal_uInt32 nFeature = pIFace->GetObjectBarFeature(nNo); + if ( nFeature && !pShell->HasUIFeature( nFeature ) ) + continue; + + // Auf jeden Fall eintragen, auch wenn unsichtbar. Dann kann + // WorkWindow anbieten, wieder anzuschalten + sal_Bool bVisible = pIFace->IsObjectBarVisible(nNo); + if ( !bVisible ) + nPos &= SFX_POSITION_MASK; + + SfxObjectBars_Impl& rBar = pImp->aObjBars[nPos & SFX_POSITION_MASK]; + rBar.nMode = nPos; + rBar.aResId = pIFace->GetObjectBarResId(nNo); + const String *pName = pIFace->GetObjectBarName(nNo); + if ( pName ) + rBar.aName = *pName; + else + rBar.aName.Erase(); + rBar.pIFace = pIFace; + + if ( bUIActive || bIsActive ) + { + pWorkWin->SetObjectBar_Impl( + nPos, rBar.aResId, rBar.pIFace, &rBar.aName ); + } + + if ( !bVisible ) + rBar.aResId = ResId( 0,0 ); + } + + for ( nNo=0; pIFace && nNo<pIFace->GetChildWindowCount(); nNo++ ) + { + sal_uInt32 nId = pIFace->GetChildWindowId(nNo); + const SfxSlot *pSlot = rSlotPool.GetSlot( (sal_uInt16) nId ); + DBG_ASSERT( pSlot, "Da fehlt ein Childwindow-Slot!"); + if ( bReadOnlyShell ) + { + // Bei read only documents nur solche ChildWindows anzeigen, + // die daf"ur freigegeben sind + if ( pSlot && !pSlot->IsMode( SFX_SLOT_READONLYDOC ) ) + continue; + } + + sal_uInt32 nFeature = pIFace->GetChildWindowFeature(nNo); + if ( nFeature && !pShell->HasUIFeature( nFeature ) ) + continue; + + // Bei den anderen auf CONTAINER/SERVER-Slots abfragen + sal_uInt16 nMode = SFX_VISIBILITY_STANDARD; + if( pSlot ) + { + if ( pSlot->IsMode(SFX_SLOT_CONTAINER) ) + { + if ( !pWorkWin->IsVisible_Impl( SFX_VISIBILITY_CLIENT ) ) + continue; + nMode |= SFX_VISIBILITY_CLIENT; + } + else + { + if ( !pWorkWin->IsVisible_Impl( SFX_VISIBILITY_SERVER ) ) + continue; + nMode |= SFX_VISIBILITY_SERVER; + } + } + + if ( bUIActive || bIsActive ) + pWorkWin->SetChildWindowVisible_Impl( nId, sal_True, nMode ); + if ( bUIActive || bIsActive || !pWorkWin->IsFloating( (sal_uInt16) ( nId & 0xFFFF ) ) ) + pImp->aChildWins.Insert( nId, pImp->aChildWins.Count()); + } + + if ( pAppMenu ) + { + // update Object-Menus + for ( nNo = 0; pIFace && nNo<pIFace->GetObjectMenuCount(); ++nNo ) + pAppMenu->SetObjectMenu( pIFace->GetObjectMenuPos(nNo), + pIFace->GetObjectMenuResId(nNo)); + } + + if ( bIsMDIApp || bIsIPOwner ) + { + // Bei MDIEnvironment oder internem InPlace Statuszeile setzen + sal_uInt16 nId = pIFace->GetStatusBarResId().GetId(); + if ( nId ) + { + nStatBarId = nId; + pStatusBarShell = pShell; + } + } + } + + for ( sal_uInt16 nPos=0; nPos<SFX_OBJECTBAR_MAX; nPos++ ) + { + SfxObjectBars_Impl& rFixed = pImp->aFixedObjBars[nPos]; + if ( rFixed.aResId.GetId() ) + { + SfxObjectBars_Impl& rBar = pImp->aObjBars[nPos]; + rBar = rFixed; + pWorkWin->SetObjectBar_Impl( rFixed.nMode, + rFixed.aResId, rFixed.pIFace, &rFixed.aName ); + } + } + + if ( pTaskWin && ( bIsMDIApp || bIsIPOwner ) ) + { + SfxDispatcher *pActDispat = pTaskWin->GetBindings().GetDispatcher_Impl(); + SfxDispatcher *pDispat = this; + if ( bIsIPOwner && pImp->pFrame ) + pDispat = pImp->pFrame->GetParentViewFrame_Impl()->GetDispatcher(); + + while ( pActDispat && !bIsTaskActive ) + { + if ( pDispat == pActDispat ) + bIsTaskActive = sal_True; + pActDispat = pActDispat->pImp->pParent; + } + + if ( bIsTaskActive && nStatBarId && pImp->pFrame ) + { + // Ich kontrolliere die StatusBar einer Task auch wenn ich nicht aktiv bin, aber + // zu einem internem InPlaceFrame oder einem anderen ViewFrame innerhalb der Task geh"ore + SfxBindings& rBindings = pImp->pFrame->GetBindings(); + pTaskWin->SetStatusBar_Impl( nStatBarId, pStatusBarShell, rBindings ); + } + } + + return nHelpId; +} + +//-------------------------------------------------------------------- +long SfxDispatcher::UpdateObjectMenus_Impl( SfxMenuBarManager *pMenuMgr ) + +/* [Beschreibung] + + Hilfsmethode zum Updaten der <Object-Menus>. +*/ + +{ + SFX_STACK(SfxDispatcher::UpdateObjecteMenus_Impl); + + Flush(); + + if (!pImp->pFrame && !IsAppDispatcher()) + { + DBG_ERROR( "Dispatcher ohne Frame aber mit Parent?!?" ); + return 0; + } + + // Bindings und App besorgen + SfxApplication *pSfxApp = SFX_APP(); + SfxBindings* pBindings = GetBindings(); + if ( pBindings ) + pBindings->DENTERREGISTRATIONS(); + pMenuMgr->ResetObjectMenus(); + + sal_uInt16 nTotCount = pImp->aStack.Count(); + sal_uInt16 nMinCount = pImp->bQuiet || pImp->bNoUI ? nTotCount : 0; + + if ( pImp->pParent ) // && !(pImp->pFrame->GetFrameType() & SFXFRAME_PLUGIN ) ) + { + // Parents nur bei PlugIns nicht ber"ucksichtigen + // (AppDispatcher oder parent frame) + SfxDispatcher *pParent = pImp->pParent; + while ( pParent ) + { + nTotCount += pParent->pImp->aStack.Count(); + if ( pParent->pImp->bQuiet || pParent->pImp->bNoUI ) + nMinCount = nTotCount; + pParent = pParent->pImp->pParent; + } + } + + for ( sal_uInt16 nShell = nTotCount; nShell > nMinCount; --nShell ) + { + SfxShell *pShell = GetShell( nShell-1 ); + const SfxInterface *pIFace = pShell->GetInterface(); + + // update Object-Menus + for ( sal_uInt16 nNo = 0; pIFace && nNo<pIFace->GetObjectMenuCount(); ++nNo ) + pMenuMgr->SetObjectMenu( pIFace->GetObjectMenuPos(nNo), + pIFace->GetObjectMenuResId(nNo)); + } + + pMenuMgr->UpdateObjectMenus(); + if ( pBindings ) + pBindings->DLEAVEREGISTRATIONS(); + return 0; +} + +//-------------------------------------------------------------------- +void SfxDispatcher::FlushImpl() + +/* [Beschreibung] + + Hilfsmethode zum Ausf"uhren der ausstehenden Push- und Pop-Befehle. +*/ + +{ + DBG_PROFSTART(SfxDispatcherFlush); + DBG_MEMTEST(); + SFX_STACK(SfxDispatcher::FlushImpl); + + +#ifdef DBG_UTIL + ByteString aMsg( "SfxDispatcher(" ); + aMsg += ByteString::CreateFromInt32( (long) this ); + aMsg += ")::Flush()"; +#endif + + pImp->aTimer.Stop(); + + if ( pImp->pParent ) + pImp->pParent->Flush(); + +// if ( pImp->bQuiet ) +// return; + + pImp->bFlushing = !pImp->bFlushing; + if ( !pImp->bFlushing ) + { + pImp->bFlushing = sal_True; + DBG_PROFSTOP(SfxDispatcherFlush); +//! +#ifdef DBG_UTIL_MESSEHACK_AUSKOMMENT + DBG_ERROR( "reentering SfxDispatcher::Flush()" ); + aMsg += " reentering, aborted"; + DbgTrace( aMsg.GetBuffer() ); +#endif + return; + } + + SfxApplication *pSfxApp = SFX_APP(); + + // in der 1. Runde den echten Stack 'um'bauen + SfxToDoStack_Impl aToDoCopy; + sal_Bool bModify = sal_False; + short nToDo; + for ( nToDo = pImp->aToDoStack.Count()-1; nToDo >= 0; --nToDo ) + { + bModify = sal_True; + + SfxToDo_Impl aToDo( pImp->aToDoStack.Top(nToDo) ); + if ( aToDo.bPush ) + { + // tats"aechlich pushen + DBG_ASSERT( !pImp->aStack.Contains( aToDo.pCluster ), + "pushed SfxShell already on stack" ); + pImp->aStack.Push( aToDo.pCluster ); + aToDo.pCluster->SetDisableFlags( pImp->nDisableFlags ); + + // die bewegte Shell merken + aToDoCopy.Push( aToDo ); + } + else + { + // tats"aechlich poppen + SfxShell* pPopped = 0; + FASTBOOL bFound = sal_False; + do + { + DBG_ASSERT( pImp->aStack.Count(), "popping from empty stack" ); + pPopped = pImp->aStack.Pop(); + pPopped->SetDisableFlags( 0 ); + bFound = pPopped == aToDo.pCluster; + + // die bewegte Shell merken + aToDoCopy.Push( SfxToDo_Impl( sal_False, aToDo.bDelete, sal_False, *pPopped) ); + } + while ( aToDo.bUntil && !bFound ); + DBG_ASSERT( bFound, "wrong SfxShell popped" ); + } + + if ( nToDo == 0 ) + pImp->aToDoStack.Clear(); + } + + // ggf. Bindings invalidieren + if ( !pSfxApp->IsDowning() ) + { + if ( bModify ) + { + pImp->pCachedServ1 = 0; + pImp->pCachedServ2 = 0; + } + + InvalidateBindings_Impl( bModify ); + } + + pImp->bFlushing = sal_False; + pImp->bUpdated = sal_False; // nicht nur bei bModify, falls Doc/Template-Config + bFlushed = sal_True; + + // in der 2. Runde die Shells aktivieren und ggf. l"oschen + for ( nToDo = aToDoCopy.Count()-1; nToDo >= 0; --nToDo ) + { + SfxToDo_Impl aToDo( aToDoCopy.Top(nToDo) ); + if ( aToDo.bPush ) + { + if ( pImp->bActive ) + aToDo.pCluster->DoActivate(pImp->pFrame, sal_True); + } + else + if ( pImp->bActive ) + aToDo.pCluster->DoDeactivate(pImp->pFrame, sal_True); + } + for ( nToDo = aToDoCopy.Count()-1; nToDo >= 0; --nToDo ) + { + SfxToDo_Impl aToDo( aToDoCopy.Top(nToDo) ); + if ( aToDo.bDelete ) delete aToDo.pCluster; + } + sal_Bool bAwakeBindings = aToDoCopy.Count() != 0; + if( bAwakeBindings ) + aToDoCopy.Clear(); + + // Wenn bei Activate/Deactivate/Delete weitere Stackbewegungen erfolgt sind : + if (!bFlushed) + // falls jemand Push/Pop gerufen hat, wurde auch EnterReg gerufen! + FlushImpl(); + + if( bAwakeBindings && GetBindings() ) + GetBindings()->DLEAVEREGISTRATIONS(); + DBG_PROFSTOP(SfxDispatcherFlush); + + for (sal_uInt16 n=0; n<SFX_OBJECTBAR_MAX; n++) + pImp->aFixedObjBars[n].aResId = ResId( 0,0 ); + +#ifdef DBG_UTIL + aMsg += " done"; + DbgTrace( aMsg.GetBuffer() ); +#endif +} + +//-------------------------------------------------------------------- +void SfxDispatcher::SetSlotFilter +( + HACK(hier muss mal ein enum rein) + sal_Bool bEnable, /* sal_True: + nur angegebene Slots enablen, + alle anderen disablen + + sal_False: + die angegebenen Slots disablen, + alle anderen zun"achst enablen + */ + sal_uInt16 nCount, // Anzahl der SIDs im folgenden Array + const sal_uInt16* pSIDs // sortiertes Array von 'nCount' SIDs +) + +/* [Beschreibung] + + Mit dieser Methode wird ein Filter gesetzt, mit dem gezielt Slots + enabled bzw. disabled werden k"onnen. Das "ubergebene Array mu\s + bis zum Dtor bzw. n"achsten <SetSlotFilter()> erhalten bleiben, es + wird nicht vom Dispatcher gel"oscht, es kann daher static sein. + + In ReadOnly-Dokumenten kann man mit 'bEnable==2' quasi das ReadOnlyDoc + Flag von Slots "ubersteuern, dieser werden also wieder gefunden. Auf + andere Slots hat das dann keine Auswirkung. + + + [Beispiel] + + gezieltes disablen der Slots 1, 2 und 3: + + static sal_uInt16 __READONLY_DATA pSIDs[] = { 1, 2, 3 }; + pDisp->SetSlotFilter( sal_False, sizeof(pSIDs)/sizeof(sal_uInt16), pSIDs ); + + nur die Slots 5, 6 und 7 zulassen: + + static sal_uInt16 __READONLY_DATA pSIDs[] = { 5, 6, 7 }; + pDisp->SetSlotFilter( sal_True, sizeof(pSIDs)/sizeof(sal_uInt16), pSIDs ); + + Filter ausschalten: + + pDisp->SetSlotFilter(); +*/ + +{ +#ifdef DBG_UTIL + // Array "uberpr"ufen + for ( sal_uInt16 n = 1; n < nCount; ++n ) + DBG_ASSERT( pSIDs[n] > pSIDs[n-1], "SetSlotFilter: SIDs not sortet" ); +#endif + + if ( pImp->pFilterSIDs ) + pImp->pFilterSIDs = 0; + + pImp->bFilterEnabling = bEnable; + pImp->nFilterCount = nCount; + pImp->pFilterSIDs = pSIDs; + + GetBindings()->InvalidateAll(sal_True); +} + +//-------------------------------------------------------------------- +EXTERN_C +#if defined( PM2 ) && (!defined( CSET ) && !defined ( MTW ) && !defined( WTC )) +int _stdcall +#else +#ifdef WNT +int _cdecl +#else +int +#endif +#endif + +SfxCompareSIDs_Impl( const void* pSmaller, const void* pBigger ) +{ + DBG_MEMTEST(); + return ( (long) *((sal_uInt16*)pSmaller) ) - ( (long) *((sal_uInt16*)pBigger) ); +} + +//-------------------------------------------------------------------- +sal_Bool SfxDispatcher::IsSlotEnabledByFilter_Impl( sal_uInt16 nSID ) const + +/* [Beschreibung] + + Sucht 'nSID' in dem mit <SetSlotFilter()> gesetzten Filter und + liefert sal_True, falls die SID erlaubt ist, bzw. sal_False, falls sie + durch den Filter disabled ist. + + [R"uckgabewert] + sal_Bool 0 => disabled + 1 => enabled + 2 => enabled even if ReadOnlyDoc +*/ + +{ + // kein Filter? + if ( 0 == pImp->nFilterCount ) + // => alle SIDs erlaubt + return sal_True; + + // suchen + sal_Bool bFound = 0 != bsearch( &nSID, pImp->pFilterSIDs, pImp->nFilterCount, + sizeof(sal_uInt16), SfxCompareSIDs_Impl ); + + // even if ReadOnlyDoc + if ( 2 == pImp->bFilterEnabling ) + return bFound ? 2 : 1; + // sonst je nach Negativ/Positiv Filter + return pImp->bFilterEnabling ? bFound : !bFound; +} + +//-------------------------------------------------------------------- +sal_Bool SfxDispatcher::_TryIntercept_Impl +( + sal_uInt16 nSlot, // zu suchende Slot-Id + SfxSlotServer& rServer, // zu f"uellende <SfxSlotServer>-Instanz + sal_Bool bSelf +) +{ + // Eventuell geh"ort der parent auch zu einer Komponente + SfxDispatcher *pParent = pImp->pParent; + sal_uInt16 nLevels = pImp->aStack.Count(); + while ( pParent && pParent->pImp->pFrame ) + { + if ( pParent->pImp->pFrame->GetFrame()->HasComponent() ) + { + // Components d"urfen intercepten + if ( pParent->_TryIntercept_Impl( nSlot, rServer, sal_True ) ) + { + // Die eigenen Shells zum Shelllevel hinzuz"ahlen + rServer.SetShellLevel( rServer.GetShellLevel() + nLevels ); + return sal_True; + } + else + // Keine weitere Interception + break; + } + else + nLevels += pParent->pImp->aStack.Count(); + + pParent = pParent->pImp->pParent; + } + + if ( bSelf ) + { + // Die ComponentViewShell befragen + Flush(); + SfxShell *pObjShell = GetShell(0); + SfxInterface *pIFace = pObjShell->GetInterface(); + const SfxSlot *pSlot = pIFace->GetSlot(nSlot); + + if ( pSlot ) + { + rServer.SetSlot(pSlot); + rServer.SetShellLevel(0); +#ifdef DBG_UTILx + String aMsg( nSlot ); + aMsg += " intercepted"; + DbgTrace( aMsg.GetBuffer() ); +#endif + return sal_True; + } + } + + return sal_False; +} + +sal_Bool SfxDispatcher::_FindServer +( + sal_uInt16 nSlot, // zu suchende Slot-Id + SfxSlotServer& rServer, // zu f"uellnde <SfxSlotServer>-Instanz + sal_Bool bModal // trotz ModalMode +) + +/* [Beschreibung] + + Diese Hilfsmethode sucht den <Slot-Server>, der nSlot zur Zeit bedient. + Als Ergebnis wird rServer entsprechend gef"ullt. + + Falls bekannt, kann das SfxInterface mitgegeben werden, von welchem + nSlot momentan bedient wird. + + Vor der Suche nach nSlot wird der SfxDispatcher geflusht. + + + [R"uckgabewert] + + sal_Bool sal_True + Der Slot wurde gefunden, rServer ist g"ultig. + + sal_False + Der Slot wird momentan nicht bedient, rServer + ist ung"ultig. +*/ + +{ + SFX_STACK(SfxDispatcher::_FindServer); + + // Dispatcher gelockt? (SID_BROWSE_STOP und SID_HELP_PI trotzdem durchlassen) + SfxApplication *pSfxApp = SFX_APP(); + sal_Bool bAllLocked = pSfxApp->IsDispatcherLocked(); + if ( IsLocked(nSlot) ) + { + if ( bAllLocked ) + pSfxApp->Get_Impl()->bInvalidateOnUnlock = sal_True; + pImp->bInvalidateOnUnlock = sal_True; + return sal_False; + } + + // Anzahl der Shells auf den verkettenten Dispatchern z"ahlen + Flush(); + sal_uInt16 nTotCount = pImp->aStack.Count(); + if ( pImp->pParent ) + { + SfxDispatcher *pParent = pImp->pParent; + while ( pParent ) + { + nTotCount += pParent->pImp->aStack.Count(); + pParent = pParent->pImp->pParent; + } + } + + // Makro-Slot? + if ( SfxMacroConfig::IsMacroSlot( nSlot ) ) + { + rServer.SetShellLevel(nTotCount-1); + rServer.SetSlot(pSfxApp->GetMacroConfig()->GetMacroInfo(nSlot)->GetSlot()); + return sal_True; + } + // Verb-Slot? + else if (nSlot >= SID_VERB_START && nSlot <= SID_VERB_END) + { + SfxShell *pSh = 0; + for ( sal_uInt16 nShell = 0; pSh = GetShell(nShell); ++nShell ) + { + if ( pSh->ISA(SfxViewShell) ) + { + rServer.SetShellLevel(nShell); + rServer.SetSlot(pSh->GetVerbSlot_Impl(nSlot)); + return sal_True; + } + } + + return sal_False; + } + + // SID gegen gesetzten Filter pr"ufen + sal_uInt16 nSlotEnableMode=0; + if ( pImp->pFrame ) + { + nSlotEnableMode = IsSlotEnabledByFilter_Impl( nSlot ); + if ( 0 == nSlotEnableMode ) + return sal_False; + } + + // im Quiet-Mode nur Parent-Dispatcher + if ( pImp->bQuiet ) + { + if ( pImp->pParent ) + { + sal_Bool bRet = pImp->pParent->_FindServer( nSlot, rServer, bModal ); + rServer.SetShellLevel + ( rServer.GetShellLevel() + pImp->aStack.Count() ); + return bRet; + } + else + return sal_False; + } + + sal_Bool bReadOnly = ( 2 != nSlotEnableMode && pImp->bReadOnly ) || + ( pImp->pFrame && pImp->pFrame->GetObjectShell() && + pImp->pFrame->GetObjectShell()->IsLoading() ); + + // durch alle Shells der verketteten Dispatchern von oben nach unten suchen +#ifdef DBG_UTILx + String aStack( "Stack:" ); +#endif + sal_uInt16 nFirstShell = pImp->bModal && !bModal ? pImp->aStack.Count() : 0; + for ( sal_uInt16 i = nFirstShell; i < nTotCount; ++i ) + { + SfxShell *pObjShell = GetShell(i); + SfxInterface *pIFace = pObjShell->GetInterface(); + const SfxSlot *pSlot = pIFace->GetSlot(nSlot); + + if ( pSlot && pSlot->nDisableFlags && ( pSlot->nDisableFlags & pObjShell->GetDisableFlags() ) != 0 ) + return sal_False; + + if ( pSlot && !( pSlot->nFlags & SFX_SLOT_READONLYDOC ) && bReadOnly ) + return sal_False; + + if ( pSlot ) + { + // Slot geh"ort zum Container? + FASTBOOL bIsContainerSlot = pSlot->IsMode(SFX_SLOT_CONTAINER); + FASTBOOL bIsInPlace = pImp->pFrame && pImp->pFrame->ISA( SfxInPlaceFrame ); + + // Shell geh"ort zum Server? + // AppDispatcher oder IPFrame-Dispatcher + FASTBOOL bIsServerShell = !pImp->pFrame || bIsInPlace; + + // Nat"urlich sind ServerShell-Slots auch ausf"uhrbar, wenn sie auf + // einem Container-Dispatcher ohne IPClient ausgef"uhrt werden sollen. + if ( !bIsServerShell ) + { + SfxViewShell *pViewSh = pImp->pFrame->GetViewShell(); + bIsServerShell = !pViewSh || !pViewSh->GetIPClient(); + } + + // Shell geh"ort zum Container? + // AppDispatcher oder kein IPFrameDispatcher + FASTBOOL bIsContainerShell = !pImp->pFrame || !bIsInPlace; +#ifdef MBA + if ( !bIsContainerShell ) + { + // Bei internem InPlace auch den AppDispatcher zug"angig machen + if ( pImp->pFrame && pImp->pFrame->GetParentViewFrame_Impl() ) + { + if ( i == nTotCount - 1 ) + bIsContainerShell = sal_True; + } + } +#endif + // Shell und Slot passen zusammen + if ( !( ( bIsContainerSlot && bIsContainerShell ) || + ( !bIsContainerSlot && bIsServerShell ) ) ) + pSlot = 0; + } + +#ifdef DBG_UTILx + if ( pSlot ) + { + String aMsg( nSlot ); + aMsg += " found in "; + aMsg += pObjShell->GetInterface()->GetClassName(); + DbgTrace( aMsg.GetBuffer() ); + } + else + { + aStack += " "; + aStack += pObjShell->GetInterface()->GetClassName(); + } +#endif + if ( pSlot && !IsAllowed( nSlot ) ) + { + pSlot = NULL; + } + + if ( pSlot ) + { + rServer.SetSlot(pSlot); + rServer.SetShellLevel(i); + return sal_True; + } + } + +#ifdef DBG_UTILx + String aMsg( nSlot ); + aMsg += " not found in "; + aMsg += aStack; + DbgTrace( aMsg.GetBuffer() ); +#endif + return sal_False; +} +//-------------------------------------------------------------------- +sal_Bool SfxDispatcher::_FillState +( + const SfxSlotServer& rSvr, // abzufragende <Slot-Server> + SfxItemSet& rState, // zu f"ullendes <SfxItemSet> + const SfxSlot* pRealSlot // ggf. der tats"achliche Slot +) + +/* [Beschreibung] + + Hilfsmethode zum Abfragen des Status des <Slot-Server>s rSvr. + In rState m"ussen die gew"unschten Slots-Ids (teilweise in Which-Ids + des betreffenden Pools umgewandelt) vorhanden sein. + + Der SfxDispatcher wird vor der Abfrage geflusht. +*/ + +{ + SFX_STACK(SfxDispatcher::_FillState); + + DBG_PROFSTART(SfxDispatcherFillState); + + const SfxSlot *pSlot = rSvr.GetSlot(); + SfxApplication *pSfxApp = SFX_APP(); + sal_Bool bAllLocked = pSfxApp->IsDispatcherLocked(); + if ( pSlot && IsLocked( pSlot->GetSlotId() ) ) + { + if ( bAllLocked ) + pSfxApp->Get_Impl()->bInvalidateOnUnlock = sal_True; + pImp->bInvalidateOnUnlock = sal_True; + DBG_PROFSTOP(SfxDispatcherFillState); + return sal_False; + } + + if ( pSlot ) + { + Flush(); + + // Objekt ermitteln und Message an diesem Objekt aufrufen + SfxShell *pSh = GetShell(rSvr.GetShellLevel()); + DBG_ASSERT(pSh, "ObjektShell nicht gefunden"); + + SfxStateFunc pFunc; + + if (pRealSlot) + pFunc = pRealSlot->GetStateFnc(); + else + pFunc = pSlot->GetStateFnc(); + + pSh->CallState( pFunc, rState ); +#ifdef DBG_UTIL + // pr"ufen, ob IDL (SlotMap) und aktuelle Items "ubereinstimmen + if ( DbgIsAssertWarning() && rState.Count() ) + { + SfxInterface *pIF = pSh->GetInterface(); + SfxItemIter aIter( rState ); + for ( const SfxPoolItem *pItem = aIter.FirstItem(); + pItem; + pItem = aIter.NextItem() ) + if ( !IsInvalidItem(pItem) && !pItem->ISA(SfxVoidItem) ) + { + sal_uInt16 nSlotId = rState.GetPool()->GetSlotId(pItem->Which()); + if ( !pItem->IsA(pIF->GetSlot(nSlotId)->GetType()->Type()) ) + { + ByteString aMsg( "item-type unequal to IDL (=> no BASIC)" ); + aMsg += "\nwith SID: "; + aMsg += ByteString::CreateFromInt32( nSlotId ); + aMsg += "\nin "; + aMsg += pIF->GetClassName(); + DbgOut( aMsg.GetBuffer(), DBG_OUT_ERROR, __FILE__, __LINE__); + } + } + } +#endif + + DBG_PROFSTOP(SfxDispatcherFillState); + return sal_True; + } + + DBG_PROFSTOP(SfxDispatcherFillState); + return sal_False; +} + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxDispatcher::_Execute( const SfxSlotServer &rSvr ) + +/* [Beschreibung] + + Diese Methode f"uhrt einen Request "uber einen gecachten <Slot-Server> + aus. +*/ + +{ + const SfxSlot *pSlot = rSvr.GetSlot(); + if ( IsLocked( pSlot->GetSlotId() ) ) + return 0; + + if ( pSlot ) + { + Flush(); + + sal_uInt16 nSlot = pSlot->GetSlotId(); + if ( SfxMacroConfig::IsMacroSlot( nSlot ) ) + SFX_APP()->GetMacroConfig()->RegisterSlotId( nSlot ); + + if ( pSlot->IsMode(SFX_SLOT_ASYNCHRON) ) + //! ignoriert rSvr + { + SfxShell *pShell = GetShell( rSvr.GetShellLevel() ); + SfxDispatcher *pDispat = this; + while ( pDispat ) + { + sal_uInt16 nShellCount = pDispat->pImp->aStack.Count(); + for ( sal_uInt16 n=0; n<nShellCount; n++ ) + if ( pShell == pDispat->pImp->aStack.Top(n) ) + { + pDispat->pImp->xPoster->Post( + new SfxRequest( pSlot->GetSlotId(), + SFX_CALLMODE_RECORD, pShell->GetPool() ) ); +// pDispat->pImp->xPoster->Post(new Executer( +// new SfxRequest( pSlot->GetSlotId(), +// SFX_CALLMODE_RECORD, pShell->GetPool() ), +// pSlot, n )); + return 0; + } + } + } + else + { + // Objekt ermitteln und Message an diesem Objekt aufrufen + SfxShell *pSh = GetShell(rSvr.GetShellLevel()); + SfxRequest aReq( pSlot->GetSlotId(), SFX_CALLMODE_RECORD, pSh->GetPool() ); + if ( Call_Impl( *pSh, *pSlot, aReq, sal_True ) ) // von Bindings immer recorden + return aReq.GetReturnValue(); + } + } + return 0; +} + +//---------------------------------------------------------------------- +void SfxDispatcher::ExecutePopup( sal_uInt16 nConfigId, + Window *pWin, const Point *pPos, + const SfxPoolItem *pArg1, ... ) + +/* [Beschreibung] + + Diese Methode f"uhrt das unter der Id nConfigId registrierte PopupMenu + aus. Die Regisitrierung wird i.d.R. in <SFX_IMPL_INTERFACE> vorgenommen. + + Bei nConfigId == 0 werden die auf dem Stack des Dispatchers befindlichen + <SfxShell>s von oben nach unten nach dem ersten registrieren PopupMenu + durchsucht. +*/ + +{ + SfxDispatcher &rDisp = *SFX_APP()->GetDispatcher_Impl(); + sal_uInt16 nShLevel = 0; + + const SvVerbList *pVerbList = 0; + + // Nur die eigenen Shells nehmen !! + sal_uInt16 nMaxShellLevel = rDisp.pImp->aStack.Count(); + + SfxShell *pSh; + for ( pSh = rDisp.GetShell(nShLevel); + pSh && nShLevel < nMaxShellLevel ; + ++nShLevel, pSh = rDisp.GetShell(nShLevel) ) + { + + if (pSh->GetVerbs()) + { + pVerbList = pSh->GetVerbs(); + break; + } + } + + nShLevel=0; + + if ( rDisp.pImp->bQuiet ) + { + nConfigId = 0; + nShLevel = rDisp.pImp->aStack.Count(); + } + + Window *pWindow = pWin ? pWin : + SFX_APP()->GetWorkWindow_Impl( rDisp.pImp->pFrame )->GetWindow(); + + for ( pSh = rDisp.GetShell(nShLevel); + pSh; + ++nShLevel, pSh = rDisp.GetShell(nShLevel) ) + { + const ResId& rResId = pSh->GetInterface()->GetPopupMenuResId(); + if ( ( nConfigId == 0 && rResId.GetId() ) || + ( nConfigId != 0 && rResId.GetId() == nConfigId ) ) + { + SfxPopupMenuManager aPop(rResId.GetId(), *rDisp.GetBindings() ); + aPop.SetResMgr(rResId.GetResMgr()); + aPop.AddClipboardFunctions(); + aPop.Initialize(); + + if (pVerbList && pVerbList->Count()) + aPop.InsertVerbs(pVerbList); + + aPop.RemoveDisabledEntries(); + sal_uInt16 nRetId = aPop.Execute( + pPos ? *pPos : pWindow->GetPointerPosPixel(), pWindow ); + return; + } + } +} + +//---------------------------------------------------------------------- +void SfxDispatcher::ExecutePopup( sal_uInt16 nConfigId + , Window *pWin, const Point *pPos + ) + +/* [Beschreibung] + + Diese Methode f"uhrt das unter der Id nConfigId registrierte PopupMenu + aus. Die Regisitrierung wird i.d.R. in <SFX_IMPL_INTERFACE> vorgenommen. + + Bei nConfigId == 0 werden die auf dem Stack des Dispatchers befindlichen + <SfxShell>s von oben nach unten nach dem ersten registrieren PopupMenu + durchsucht. +*/ + +{ + SfxDispatcher &rDisp = *SFX_APP()->GetDispatcher_Impl(); + sal_uInt16 nShLevel = 0; + const SvVerbList *pVerbList = 0; + + // Nur die eigenen Shells nehmen !! + sal_uInt16 nMaxShellLevel = rDisp.pImp->aStack.Count(); + + SfxShell *pSh; + for ( pSh = rDisp.GetShell(nShLevel); + pSh && nShLevel < nMaxShellLevel ; + ++nShLevel, pSh = rDisp.GetShell(nShLevel) ) + { + + if (pSh->GetVerbs()) + { + pVerbList = pSh->GetVerbs(); + break; + } + } + + nShLevel=0; + + if ( rDisp.pImp->bQuiet ) + { + nConfigId = 0; + nShLevel = rDisp.pImp->aStack.Count(); + } + + Window *pWindow = pWin ? pWin : + SFX_APP()->GetWorkWindow_Impl( rDisp.pImp->pFrame )->GetWindow(); + + for ( pSh = rDisp.GetShell(nShLevel); + pSh; + ++nShLevel, pSh = rDisp.GetShell(nShLevel) ) + { + + const ResId& rResId = pSh->GetInterface()->GetPopupMenuResId(); + if ( ( nConfigId == 0 && rResId.GetId() ) || + ( nConfigId != 0 && rResId.GetId() == nConfigId ) ) + { + SfxPopupMenuManager aPop(rResId.GetId(), *rDisp.GetBindings() ); + aPop.SetResMgr(rResId.GetResMgr()); + aPop.AddClipboardFunctions(); + aPop.Initialize(); + if (pVerbList && pVerbList->Count()) + aPop.InsertVerbs(pVerbList); + + aPop.RemoveDisabledEntries(); + sal_uInt16 nRetId = aPop.Execute( + pPos ? *pPos : pWindow->GetPointerPosPixel(), pWindow ); + return; + } + } +} + +//---------------------------------------------------------------------- +void SfxDispatcher::ExecutePopup( const ResId &rId + , Window *pWin, const Point *pPos + ) + +/* [Beschreibung] + + Diese Methode l"adt ein PopupMenu aus der angegebenen Resource und + f"uhrt es aus. Die Selektion wird "uber diesen SfxDispatcher ausgef"uhrt. +*/ + +{ + Window *pWindow = pWin ? pWin : + SFX_APP()->GetWorkWindow_Impl( pImp->pFrame )->GetWindow(); + + SfxPopupMenuManager aPop( rId, *GetBindings() ); + aPop.AddClipboardFunctions(); + aPop.Initialize(); + aPop.RemoveDisabledEntries(); + sal_uInt16 nRetId = aPop.Execute( pPos ? *pPos : pWindow->GetPointerPosPixel(), + pWindow ); +} + +//-------------------------------------------------------------------- +void SfxDispatcher::Lock( sal_Bool bLock ) + +/* [Beschreibung] + + Mit dieser Methode kann der SfxDispatcher gesperrt und freigegeben + werden. Ein gesperrter SfxDispatcher f"uhrt keine <SfxRequest>s mehr + aus und liefert keine Status-Informationen mehr. Er verh"alt sich + so als w"aren alle Slots disabled. +*/ + +{ + SfxBindings* pBindings = GetBindings(); + if ( !bLock && pImp->bLocked && pImp->bInvalidateOnUnlock ) + { + if ( pBindings ) + pBindings->InvalidateAll(sal_True); + pImp->bInvalidateOnUnlock = sal_False; + } + else if ( pBindings ) + pBindings->InvalidateAll(sal_False); + pImp->bLocked = bLock; +} + +//-------------------------------------------------------------------- +void SfxDispatcher::ShowObjectBar(sal_uInt16 nId, SfxShell *pShell) const + +/* [Beschreibung] + + Mit dieser Methode kann auf einer Objektleistenposition gezielt eine + bestimmte Objektleiste eingeblendet werden. +*/ + +{ + ResId aResId(nId); + sal_uInt16 nPos = USHRT_MAX; + sal_uInt16 nNo; + SfxInterface *pIFace; + + if ( pShell ) + { + // Nur in der Shell suchen + pIFace = pShell->GetInterface(); + for ( nNo=0; nNo<pIFace->GetObjectBarCount(); nNo++ ) + { + if (pIFace->GetObjectBarResId(nNo).GetId() == nId) + { + nPos = pIFace->GetObjectBarPos(nNo); + break; + } + } + } + else + { + // Alle Shells absuchen + for ( sal_uInt16 nIdx=0; (pShell=GetShell(nIdx)); nIdx++ ) + { + pIFace = pShell->GetInterface(); + for ( nNo=0; nNo<pIFace->GetObjectBarCount(); nNo++ ) + { + if (pIFace->GetObjectBarResId(nNo).GetId() == nId) + { + nPos = pIFace->GetObjectBarPos(nNo); + break; + } + } + + if ( nPos != USHRT_MAX ) + break; + } + } + + if ( nPos != USHRT_MAX ) + { + // Auf jeden Fall eintragen, auch wenn unsichtbar. Dann kann + // WorkWindow anbieten, wieder anzuschalten + SfxObjectBars_Impl& rBar = pImp->aObjBars[nPos & SFX_POSITION_MASK]; + SfxObjectBars_Impl& rFixed = pImp->aFixedObjBars[nPos & SFX_POSITION_MASK]; + + sal_uInt16 nOldId = rBar.aResId.GetId(); + + if ( pImp->bReadOnly && !( nPos & SFX_VISIBILITY_READONLYDOC ) ) + return; + + sal_uInt32 nFeature = pIFace->GetObjectBarFeature(nNo); + if ( nFeature && !pShell->HasUIFeature( nFeature ) ) + return; + + sal_Bool bVisible = pIFace->IsObjectBarVisible(nNo); + if ( !bVisible ) + // Alle Sichtbarkeitsflags ausschalten + nPos &= SFX_POSITION_MASK; + + aResId.SetResMgr( pIFace->GetObjectBarResId(nNo).GetResMgr() ); + rBar.aResId = aResId; + rBar.nMode = nPos; + const String *pName = pIFace->GetObjectBarName(nNo); + if ( pName ) + rBar.aName = *pName; + else + rBar.aName.Erase(); + rBar.pIFace = pIFace; + + rFixed = rBar; + + if ( nOldId != aResId.GetId() && pImp->bUpdated ) + { + SfxWorkWindow *pWorkWin = SFX_APP()->GetWorkWindow_Impl(pImp->pFrame); + pWorkWin->SetObjectBar_Impl( nPos, aResId, pIFace, pName ); + pWorkWin->UpdateObjectBars_Impl(); + } + + if ( !bVisible ) + { + rBar.aResId = ResId( 0,0 ); + rFixed.aResId = ResId( 0,0 ); + } + + return; + } + +// DBG_ERROR("Objektleiste nicht bekannt!"); +} + +sal_uInt16 SfxDispatcher::GetObjectBarId( sal_uInt16 nPos ) const +{ + return pImp->aObjBars[nPos].aResId.GetId(); +} + +//-------------------------------------------------------------------- +void SfxDispatcher::ResetObjectBars_Impl() + +/* [Beschreibung] + + Mit dieser Methode werden alle Objectbar-Anforderungen, die dieser + Dispatcher an das AppWindow hat, beseitigt. +*/ +{ + for (sal_uInt16 n=0; n<SFX_OBJECTBAR_MAX; n++) + pImp->aObjBars[n].aResId = ResId( 0,0 ); + pImp->aChildWins.Remove(0, pImp->aChildWins.Count()); +} + + +//-------------------------------------------------------------------- +void SfxDispatcher::DebugOutput_Impl() const +{ +#ifdef DBG_UTIL + + sal_uInt16 nOld = (sal_uInt16) DbgGetData()->nTraceOut; + DbgGetData()->nTraceOut = DBG_OUT_FILE; + + if (pImp->bFlushed) + DBG_TRACE("Flushed"); + if (pImp->bUpdated) + DBG_TRACE("Updated"); + + for ( sal_uInt16 nShell = pImp->aStack.Count(); nShell > 0; --nShell ) + { + SfxShell *pShell = GetShell(nShell-1); + const SfxInterface *pIFace = pShell->GetInterface(); + DBG_TRACE (pIFace->GetClassName()); + } + + DbgGetData()->nTraceOut = nOld; + +#endif +} + +void SfxDispatcher::LockUI_Impl( sal_Bool bLock ) +{ + sal_Bool bWasLocked = pImp->bUILocked; + pImp->bUILocked = bLock; + if ( !bLock && bWasLocked ) + Update_Impl( sal_True ); +} + +//------------------------------------------------------------------------- +void SfxDispatcher::HideUI( sal_Bool bHide ) +{ +// if ( !bHide && pImp->bReadOnly ) +// bHide = sal_True; + sal_Bool bWasHidden = pImp->bNoUI; + pImp->bNoUI = bHide; + if ( bHide != bWasHidden ) + Update_Impl( sal_True ); +} + +void SfxDispatcher::SetReadOnly_Impl( sal_Bool bOn ) +{ + pImp->bReadOnly = bOn; +// pImp->bNoUI = bOn; +} + +sal_Bool SfxDispatcher::GetReadOnly_Impl() const +{ + return pImp->bReadOnly; +} + +//------------------------------------------------------------------------- +void SfxDispatcher::SetQuietMode_Impl( sal_Bool bOn ) + +/* [Beschreibung] + + Bei 'bOn' stellt sich dieser Dispatcher quasi tot und leitet alles + an den Parent-Dispatcher weiter. +*/ + +{ + pImp->bQuiet = bOn; + SfxBindings* pBindings = GetBindings(); + if ( pBindings ) + pBindings->InvalidateAll(sal_True); +} + +//------------------------------------------------------------------------- +void SfxDispatcher::SetModalMode_Impl( sal_Bool bOn ) + +/* [Beschreibung] + + Bei 'bOn' werden nur noch Slots des Parent-Dispatchers gefunden. +*/ + +{ + pImp->bModal = bOn; + SfxBindings* pBindings = GetBindings(); + if ( pBindings ) + pBindings->InvalidateAll(sal_True); +} + +void SfxDispatcher::SetExecuteMode( sal_uInt16 nMode ) +{ + pImp->nStandardMode = nMode; +} + +SfxItemState SfxDispatcher::QueryState( sal_uInt16 nSlot, const SfxPoolItem* &rpState ) +{ + SfxShell *pShell = 0; + const SfxSlot *pSlot = 0; + if ( GetShellAndSlot_Impl( nSlot, &pShell, &pSlot, sal_False, sal_False ) ) + { + rpState = pShell->GetSlotState(nSlot); + if ( !rpState ) + return SFX_ITEM_DISABLED; + else + return SFX_ITEM_AVAILABLE; + } + + return SFX_ITEM_DISABLED; +} + +sal_Bool SfxDispatcher::IsReadOnlyShell_Impl( sal_uInt16 nShell ) const +{ + sal_uInt16 nShellCount = pImp->aStack.Count(); + if ( nShell < nShellCount ) + { + if( nShell == nShellCount - 1 ) + return pImp->aStack.Bottom()->ISA( SfxModule ) ? + sal_False : pImp->bReadOnly; + else return pImp->bReadOnly; + } + else if ( pImp->pParent ) + return pImp->pParent->IsReadOnlyShell_Impl( nShell - nShellCount ); + return sal_True; +} + +// Ein dirty trick, um an die Methoden der private base class von +// SfxShellStack_Impl heranzukommen +class StackAccess_Impl : public SfxShellStack_Implarr_ +{}; + +void SfxDispatcher::InsertShell_Impl( SfxShell& rShell, sal_uInt16 nPos ) +{ + Flush(); + + // Der cast geht, weil SfxShellStack_Impl keine eigenen member hat + ((StackAccess_Impl*) (&pImp->aStack))->Insert( nPos, &rShell ); + rShell.SetDisableFlags( pImp->nDisableFlags ); + rShell.DoActivate(pImp->pFrame, sal_True); + + if ( !SFX_APP()->IsDowning() ) + { + pImp->bUpdated = sal_False; + pImp->pCachedServ1 = 0; + pImp->pCachedServ2 = 0; + InvalidateBindings_Impl(sal_True); + } +} + +void SfxDispatcher::RemoveShell_Impl( SfxShell& rShell ) +{ + Flush(); + + // Der cast geht, weil SfxShellStack_Impl keine eigenen member hat + StackAccess_Impl& rStack = *((StackAccess_Impl*) (&pImp->aStack)); + sal_uInt16 nCount = rStack.Count(); + for ( sal_uInt16 n=0; n<nCount; ++n ) + { + if ( rStack[n] == &rShell ) + { + rStack.Remove( n ); + rShell.SetDisableFlags( 0 ); + rShell.DoDeactivate(pImp->pFrame, sal_True); + break; + } + } + + if ( !SFX_APP()->IsDowning() ) + { + pImp->bUpdated = sal_False; + pImp->pCachedServ1 = 0; + pImp->pCachedServ2 = 0; + InvalidateBindings_Impl(sal_True); + } +} + +sal_Bool SfxDispatcher::IsAllowed +( + sal_uInt16 nSlot +) const +/* + [Beschreibung] + Die Methode prueft, ob der Zugriff auf diese Schnittstelle erlaubt ist. + */ +{ + if ( !pImp->pDisableList ) + { + return sal_True; + } + + // BinSearch in der DisableListe + SvUShorts& rList = *pImp->pDisableList; + sal_uInt16 nCount = rList.Count(); + sal_uInt16 nLow = 0, nMid, nHigh; + sal_Bool bFound = sal_False; + nHigh = nCount - 1; + + while ( !bFound && nLow <= nHigh ) + { + nMid = (nLow + nHigh) >> 1; + DBG_ASSERT( nMid < nCount, "bsearch ist buggy" ); + + int nDiff = (int) nSlot - (int) rList[nMid]; + 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; + } + + // Slot in der Liste gefunden ? + sal_uInt16 nPos = bFound ? nMid : nLow; + + DBG_ASSERT( nPos <= nCount, "" ); + DBG_ASSERT( nPos == nCount || nSlot <= rList[nPos], "" ); + DBG_ASSERT( nPos == 0 || nSlot > rList[nPos-1], "" ); + DBG_ASSERT( ( (nPos+1) >= nCount ) || nSlot < rList[nPos+1], "" ); + + return !bFound; +} + +void SfxDispatcher::InvalidateBindings_Impl( sal_Bool bModify ) +{ + // App-Dispatcher? + if ( IsAppDispatcher() ) + { + for ( SfxViewFrame *pFrame = SfxViewFrame::GetFirst(); + pFrame; + pFrame = SfxViewFrame::GetNext( *pFrame ) ) + pFrame->GetBindings().InvalidateAll(bModify); +/* + // alle Bindings sind betroffen + for ( SfxInPlaceFrame *pIPFrame = (SfxInPlaceFrame*) + SfxViewFrame::GetFirst(0, TYPE(SfxInPlaceFrame)); + pIPFrame; + pIPFrame = (SfxInPlaceFrame*) + SfxViewFrame::GetNext(*pIPFrame, 0, TYPE(SfxInPlaceFrame)) ) + pIPFrame->GetBindings().InvalidateAll(bModify); + + for ( SfxPlugInFrame *pPIFrame = (SfxPlugInFrame*) + SfxViewFrame::GetFirst(0, TYPE(SfxPlugInFrame)); + pPIFrame; + pPIFrame = (SfxPlugInFrame*) + SfxViewFrame::GetNext(*pPIFrame, 0, TYPE(SfxPlugInFrame)) ) + pPIFrame->GetBindings().InvalidateAll(bModify); + + for ( SfxTask* pTask = SfxTask::GetFirst(); pTask; + pTask = SfxTask::GetNext( *pTask ) ) + if ( !pTask->IsExternal() ) + pTask->GetBindings()->InvalidateAll(bModify); +*/ + } + else + { + SfxDispatcher *pDisp = GetBindings()->GetDispatcher_Impl(); + while ( pDisp ) + { + if ( pDisp == this ) + { + GetBindings()->InvalidateAll( bModify ); + break; + } + + pDisp = pDisp->pImp->pParent; + } + } +} + +sal_uInt16 SfxDispatcher::GetNextToolBox_Impl( sal_uInt16 nPos, sal_uInt16 nType, String *pStr ) +{ + SfxShell *pShell; + sal_Bool bReadOnly = sal_False; + SfxViewFrame *pFrame = pImp->pFrame; + if ( pFrame ) + { + SfxObjectShell *pObj = pFrame->GetObjectShell(); + bReadOnly = !pObj || pObj->IsReadOnly(); + } + + sal_Bool bFound = sal_False; + SfxWorkWindow *pWorkWin = GetBindings()->GetWorkWindow_Impl(); + + // Wenn die aktuelle Toolbox die letzte ist, mu\s die erste zur"uckgegeben + // werden + sal_uInt16 nNext = 0; + + if ( nPos != 0xFFFF ) + { + SfxDispatcher *pDispat = this; + while ( pDispat ) + { + SfxBindings* pBindings = pDispat->GetBindings(); + if ( !pBindings || pBindings->GetWorkWindow_Impl() != pWorkWin ) + break; + + sal_uInt16 nCount = pDispat->pImp->aStack.Count(); + // Alle interfaces auf dem Dispatcher-Stack durchsuchen + for ( sal_uInt16 nIdx=0; nIdx<nCount; nIdx++ ) + { + pShell = pDispat->pImp->aStack.Top(nIdx); + const SfxInterface *pInterFace = pShell->GetInterface(); + for ( sal_uInt16 nNo = 0; pInterFace && nNo<pInterFace->GetObjectBarCount(); ++nNo ) + { + // Ist die Objectbar an der richtigen Position und sichtbar ? + sal_uInt16 nP = pInterFace->GetObjectBarPos(nNo); + + if ( (nP & SFX_POSITION_MASK) == (nPos & SFX_POSITION_MASK) && + pInterFace->IsObjectBarVisible(nNo) && + ( !bReadOnly || ( nP & SFX_VISIBILITY_READONLYDOC ) ) ) + { + sal_uInt16 nId = pInterFace->GetObjectBarResId(nNo).GetId(); + if ( nId != nType ) + { + // Es ist eine andere Toolbox + // Ist sie aktivierbar ? + sal_uInt32 nFeature = pInterFace->GetObjectBarFeature( nNo ); + if ( nFeature && !pShell->HasUIFeature( nFeature ) ) + continue; + + // Kommt sie nach der aktuellen ? + if ( bFound ) + { + // Ja, also ist sie die n"achste + if ( pStr ) + *pStr = *pInterFace->GetObjectBarName( nNo ); + return nId; + } + else if ( !nNext ) + { + // Nein, aber vielleicht ist es die erste ? + nNext = nId; + if ( pStr ) + *pStr = *pInterFace->GetObjectBarName( nNo ); + } + } + else + // das ist die aktuelle! + bFound = sal_True; + } + } + } + + pDispat = pDispat->pImp->pParent; + } + } + + return nNext; +} + +sal_Bool SfxDispatcher::IsUpdated_Impl() const +{ + return pImp->bUpdated; +} + +void SfxDispatcher::SetDisableFlags( sal_uInt32 nFlags ) +{ + pImp->nDisableFlags = nFlags; + for ( int i = int(pImp->aStack.Count()) - 1; i >= 0; --i ) + pImp->aStack.Top( (sal_uInt16) i )->SetDisableFlags( nFlags ); +} + +sal_uInt32 SfxDispatcher::GetDisableFlags() const +{ + return pImp->nDisableFlags; +} + +sal_Bool SfxDispatcher::HasSlot_Impl( sal_uInt16 nSlot ) +{ + Flush(); + sal_uInt16 nTotCount = pImp->aStack.Count(); + + if ( pImp->pParent && !pImp->pParent->pImp->pFrame ) + { + // the last frame also uses the AppDispatcher + nTotCount += pImp->aStack.Count(); + } + + if ( SfxMacroConfig::IsMacroSlot( nSlot ) ) + // Makro-Slot? + return sal_True; + else if (nSlot >= SID_VERB_START && nSlot <= SID_VERB_END) + { + // Verb-Slot? + SfxShell *pSh = 0; + for ( sal_uInt16 nShell = 0; pSh = GetShell(nShell); ++nShell ) + { + if ( pSh->ISA(SfxViewShell) ) + return sal_True; + } + + return sal_False; + } + + // SID gegen gesetzten Filter pr"ufen + sal_uInt16 nSlotEnableMode=0; + if ( pImp->pFrame ) + { + nSlotEnableMode = IsSlotEnabledByFilter_Impl( nSlot ); + if ( 0 == nSlotEnableMode ) + return sal_False; + } + + // im Quiet-Mode nur Parent-Dispatcher + if ( pImp->bQuiet ) + return sal_False; + + sal_Bool bReadOnly = ( 2 != nSlotEnableMode && pImp->bReadOnly ) || + ( pImp->pFrame && pImp->pFrame->GetObjectShell() && + pImp->pFrame->GetObjectShell()->IsLoading() ); + + for ( sal_uInt16 i=0 ; i < nTotCount; ++i ) + { + SfxShell *pObjShell = GetShell(i); + SfxInterface *pIFace = pObjShell->GetInterface(); + const SfxSlot *pSlot = pIFace->GetSlot(nSlot); + if ( pSlot && pSlot->nDisableFlags && ( pSlot->nDisableFlags & pObjShell->GetDisableFlags() ) != 0 ) + return sal_False; + + if ( pSlot && !( pSlot->nFlags & SFX_SLOT_READONLYDOC ) && bReadOnly ) + return sal_False; + + if ( pSlot ) + { + // Slot geh"ort zum Container? + FASTBOOL bIsContainerSlot = pSlot->IsMode(SFX_SLOT_CONTAINER); + FASTBOOL bIsInPlace = pImp->pFrame && pImp->pFrame->ISA( SfxInPlaceFrame ); + + // Shell geh"ort zum Server? + // AppDispatcher oder IPFrame-Dispatcher + FASTBOOL bIsServerShell = !pImp->pFrame || bIsInPlace; + + // Nat"urlich sind ServerShell-Slots auch ausf"uhrbar, wenn sie auf + // einem Container-Dispatcher ohne IPClient ausgef"uhrt werden sollen. + if ( !bIsServerShell ) + { + SfxViewShell *pViewSh = pImp->pFrame->GetViewShell(); + bIsServerShell = !pViewSh || !pViewSh->GetIPClient(); + } + + // Shell geh"ort zum Container? + // AppDispatcher oder kein IPFrameDispatcher + FASTBOOL bIsContainerShell = !pImp->pFrame || !bIsInPlace; + + // Shell und Slot passen zusammen + if ( !( ( bIsContainerSlot && bIsContainerShell ) || + ( !bIsContainerSlot && bIsServerShell ) ) ) + pSlot = 0; + } + + if ( pSlot && !IsAllowed( nSlot ) ) + pSlot = NULL; + + if ( pSlot ) + return sal_True; + } + + return sal_False; +} + + diff --git a/sfx2/source/control/macrconf.cxx b/sfx2/source/control/macrconf.cxx new file mode 100644 index 000000000000..2e9625af311f --- /dev/null +++ b/sfx2/source/control/macrconf.cxx @@ -0,0 +1,947 @@ +/************************************************************************* + * + * $RCSfile: macrconf.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ +#if SUPD<582 +#ifndef _SFXSFXJS_HXX //autogen +#include <sfxjs.hxx> +#endif +#ifndef _SJIMPL2_HXX //autogen +#include <sj2/sjimpl2.hxx> +#endif +#endif +#ifndef _SB_SBSTAR_HXX //autogen +#include <basic/sbstar.hxx> +#endif +#ifndef _BASMGR_HXX //autogen +#include <basic/basmgr.hxx> +#endif +#ifndef _SBX_HXX //autogen +#include <svtools/sbx.hxx> +#endif +#ifndef _SB_SBMETH_HXX //autogen +#include <basic/sbmeth.hxx> +#endif +#ifndef _SB_SBMOD_HXX //autogen +#include <basic/sbmod.hxx> +#endif +#ifndef _INTN_HXX //autogen +#include <tools/intn.hxx> +#endif +#ifndef _BASIC_SBUNO_HXX +#include <basic/sbuno.hxx> +#endif + +#include <osl/mutex.hxx> + +#include <com/sun/star/script/XEngine.hpp> + +#pragma hdrstop + +#include "msgpool.hxx" +#include "macrconf.hxx" +#include "sfxbasic.hxx" +#include "sfx.hrc" +#include "app.hxx" +#include "objsh.hxx" +#include "dispatch.hxx" +#include "minfitem.hxx" +#include "imgmgr.hxx" +#include "evntconf.hxx" +#include "docfile.hxx" +#include "genlink.hxx" +#include <viewfrm.hxx> +#include <appdata.hxx> + +static const sal_uInt16 nCompatVersion = 2; +static const sal_uInt16 nVersion = 3; + +// Static member +SfxMacroConfig* SfxMacroConfig::pMacroConfig = NULL; + +SfxMacroConfig* SfxMacroConfig::GetOrCreate() +{ + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if ( !pMacroConfig ) + pMacroConfig = new SfxMacroConfig; + return pMacroConfig; +} + +void SfxMacroConfig::Release_Impl() +{ + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + DELETEZ( pMacroConfig ); +} + +//========================================================================== + +struct SfxMacroConfig_Impl +{ + SfxMacroInfoArr_Impl aArr; + sal_uInt32 nEventId; + sal_Bool bWaitingForCallback; + + SfxMacroConfig_Impl() + : nEventId( 0 ) + , bWaitingForCallback( sal_False ) + {} +}; + +//========================================================================== + +SbMethod* SfxQueryMacro_Impl( BasicManager* pMgr , const String& rMacro, + const String &rLibName, const String& rModule ) +{ + const International &rInter = Application::GetAppInternational(); + + sal_uInt16 nLibCount = pMgr->GetLibCount(); + for ( sal_uInt16 nLib = 0; nLib < nLibCount; ++nLib ) + { + if ( COMPARE_EQUAL == rInter.Compare( pMgr->GetLibName( nLib ), rLibName, INTN_COMPARE_IGNORECASE ) ) + { + StarBASIC* pLib = pMgr->GetLib( nLib ); + if( !pLib ) + { + pMgr->LoadLib( nLib ); + pLib = pMgr->GetLib( nLib ); + } + + if( pLib ) + { + sal_uInt16 nModCount = pLib->GetModules()->Count(); + for( sal_uInt16 nMod = 0; nMod < nModCount; ++nMod ) + { + SbModule* pMod = (SbModule*)pLib->GetModules()->Get( nMod ); + if ( pMod && + COMPARE_EQUAL == rInter.Compare( pMod->GetName(), rModule, INTN_COMPARE_IGNORECASE ) ) + { + SbMethod* pMethod = + (SbMethod*)pMod->Find( rMacro, SbxCLASS_METHOD ); + if( pMethod ) + return pMethod; + } + } + } + } + } + return 0; +} + +SbMethod* SfxQueryMacro( BasicManager* pMgr , const String& rMacro ) +{ + sal_uInt16 nLast = 0; + String aMacro = rMacro; + String aLibName = aMacro.GetToken( 0, '.', nLast ); + String aModule = aMacro.GetToken( 0, '.', nLast ); + aMacro.Erase( 0, nLast ); + + return SfxQueryMacro_Impl( pMgr, aMacro, aLibName, aModule ); +} + +ErrCode SfxCallMacro( BasicManager* pMgr, const String& rCode, + SbxArray *pArgs, SbxValue *pRet ) +{ + ErrCode nErr; + SfxApplication *pApp = SFX_APP(); + pApp->EnterBasicCall(); + SbMethod* pMethod = SfxQueryMacro( pMgr, rCode ); + if ( pMethod ) + { + if ( pArgs ) + pMethod->SetParameters( pArgs ); + nErr = pMethod->Call( pRet ); + } + else + nErr = ERRCODE_BASIC_PROC_UNDEFINED; + + pApp->LeaveBasicCall(); + return nErr; +} + +//========================================================================== + +SfxMacroInfo::SfxMacroInfo( SfxObjectShell *pDoc ) : + bAppBasic(pDoc == NULL), + nSlotId(0), + nRefCnt(0), + pSlot(0), + pHelpText(0) +{} + +//========================================================================== + +SfxMacroInfo::SfxMacroInfo(SfxObjectShell *pDoc, const String& rLibName, + const String& rModuleName, const String& rMethodName) : + aLibName(rLibName), + aModuleName(rModuleName), + aMethodName(rMethodName), + nSlotId(0), + nRefCnt(0), + pSlot(0), + pHelpText(0) +{ + bAppBasic = (pDoc == 0); +} + +//========================================================================== + +SfxMacroInfo::SfxMacroInfo(SfxObjectShell *pDoc, const String& rQualifiedName ) +: nSlotId(0), + nRefCnt(0), + pSlot(0), + pHelpText(0) +{ + sal_uInt16 nCount = rQualifiedName.GetTokenCount('.'); + aMethodName = rQualifiedName.GetToken( nCount-1, '.' ); + if ( nCount > 1 ) + aModuleName = rQualifiedName.GetToken( nCount-2, '.' ); + if ( nCount > 2 ) + aLibName = rQualifiedName.GetToken( 0, '.' ); + bAppBasic = (pDoc == 0); +} + +//========================================================================== + +SfxMacroInfo::SfxMacroInfo(SfxMacroInfo& rOther) : + bAppBasic(rOther.bAppBasic), + aLibName(rOther.aLibName), + aModuleName(rOther.aModuleName), + aMethodName(rOther.aMethodName), + nSlotId(rOther.nSlotId), + pSlot(0), + nRefCnt(0), + pHelpText(0) +{} + +//========================================================================== + +SfxMacroInfo::~SfxMacroInfo() +{ + delete pSlot; + delete pHelpText; +} + +//========================================================================== + +sal_Bool SfxMacroInfo::operator==(const SfxMacroInfo& rOther) const +{ + if ( GetQualifiedName() == rOther.GetQualifiedName() && + bAppBasic == rOther.bAppBasic ) + return sal_True; + else + return sal_False; +} + +//========================================================================== + +String SfxMacroInfo::GetMacroName() const +{ + String aMacroName = aMethodName; + aMacroName += '('; + aMacroName += aLibName; + aMacroName += '.'; + aMacroName += aModuleName; + aMacroName += ')'; + return aMacroName; +} + +//========================================================================== + +String SfxMacroInfo::GetQualifiedName() const +{ + String aMacroName; + if( aMacroName.Len() || aLibName.Len() ) + { + // Altes Format + aMacroName = aLibName; + aMacroName += '.'; + aMacroName += aModuleName; + aMacroName += '.'; + } + + // Wg. ::com::sun::star::script::JavaScript kein Zerlegen des Strings mehr + aMacroName += aMethodName; + return aMacroName; +} + +String SfxMacroInfo::GetFullQualifiedName() const +{ + // Liefert nur Unsinn, wenn f"ur ein ::com::sun::star::script::JavaScript aufgerufen ! + String aRet; + if ( bAppBasic ) + aRet = SFX_APP()->GetName(); + aRet += '.'; + aRet += GetQualifiedName(); + return aRet; +} + +//========================================================================== + +BasicManager* SfxMacroInfo::GetBasicManager() const +{ + if (bAppBasic) + { + return SFX_APP()->GetBasicManager(); + } + else + { + SfxObjectShell *pDocShell = SfxObjectShell::Current(); + return pDocShell ? pDocShell->GetBasicManager() : + SFX_APP()->GetBasicManager(); + } +} + +//========================================================================== + +String SfxMacroInfo::GetBasicName() const +{ + if (bAppBasic) + { + return SFX_APP()->GetName(); + } + else + { + SfxObjectShell *pDocShell = SfxObjectShell::Current(); + if ( pDocShell ) + return pDocShell->GetTitle(); + else + return SFX_APP()->GetName(); + } +} + +String SfxMacroInfo::GetHelpText() const +{ + if ( pHelpText ) + return *pHelpText; + return String(); +} + +String SfxMacroConfig::RequestHelp( sal_uInt16 nId ) +{ + SfxMacroInfo *pInfo = SFX_APP()->GetMacroConfig()->GetMacroInfo( nId ); + if ( !pInfo ) + return String(); + + if ( !pInfo->pHelpText ) + { + SbMethod *pMethod = + SfxQueryMacro_Impl( pInfo->GetBasicManager(), pInfo->aMethodName, + pInfo->aLibName, pInfo->aModuleName ); + if ( pMethod && pMethod->GetInfo() ) + pInfo->pHelpText = new String( pMethod->GetInfo()->GetComment() ); + } + + return pInfo->GetHelpText(); +} + +void SfxMacroInfo::SetHelpText( const String& rName ) +{ + if ( !pHelpText ) + pHelpText = new String; + *pHelpText = rName; +} + +//========================================================================== + +SvStream& operator >> (SvStream& rStream, SfxMacroInfo& rInfo) +{ + sal_uInt16 nAppBasic, nFileVersion; + String aDocName; + + rStream >> nFileVersion; + if ( nVersion < nCompatVersion ) + { + // In der 1.Version ohne Versionskennung + nAppBasic = nVersion; + nFileVersion = 1; + rStream.ReadByteString(aDocName,RTL_TEXTENCODING_UTF8); + rStream.ReadByteString(rInfo.aLibName,RTL_TEXTENCODING_UTF8); + rStream.ReadByteString(rInfo.aModuleName,RTL_TEXTENCODING_UTF8); + rStream.ReadByteString(rInfo.aMethodName,RTL_TEXTENCODING_UTF8); + } + else + { + String aInput; + rStream >> nAppBasic; + rStream.ReadByteString(aDocName,RTL_TEXTENCODING_UTF8); // Vorsicht: kann bei AppName Unsinn sein! + rStream.ReadByteString(rInfo.aLibName,RTL_TEXTENCODING_UTF8); + rStream.ReadByteString(rInfo.aModuleName,RTL_TEXTENCODING_UTF8); + rStream.ReadByteString(aInput,RTL_TEXTENCODING_UTF8); + + if ( nFileVersion == nCompatVersion ) + rInfo.aMethodName = aInput; + else + { + sal_uInt16 nCount = aInput.GetTokenCount('.'); + rInfo.aMethodName = aInput.GetToken( nCount-1, '.' ); + if ( nCount > 1 ) + rInfo.aModuleName = aInput.GetToken( nCount-2, '.' ); + if ( nCount > 2 ) + rInfo.aLibName = aInput.GetToken( 0, '.' ); + } + } + + rInfo.bAppBasic = (sal_Bool) nAppBasic; + rInfo.nSlotId = SFX_APP()->GetMacroConfig()->GetSlotId(&rInfo); + return rStream; +} + +//========================================================================== + +SvStream& operator << (SvStream& rStream, const SfxMacroInfo& rInfo) +{ + if ( rInfo.bAppBasic ) + { + rStream << nVersion + << (sal_uInt16) rInfo.bAppBasic; + rStream.WriteByteString(rInfo.GetBasicName(),RTL_TEXTENCODING_UTF8); + rStream.WriteByteString(rInfo.aLibName,RTL_TEXTENCODING_UTF8); + rStream.WriteByteString(rInfo.aModuleName,RTL_TEXTENCODING_UTF8); + rStream.WriteByteString(rInfo.aMethodName,RTL_TEXTENCODING_UTF8); + } + else + { + rStream << nVersion + << (sal_uInt16) rInfo.bAppBasic; + rStream.WriteByteString(SFX_APP()->GetName(),RTL_TEXTENCODING_UTF8); + rStream.WriteByteString(rInfo.aLibName,RTL_TEXTENCODING_UTF8); + rStream.WriteByteString(rInfo.aModuleName,RTL_TEXTENCODING_UTF8); + rStream.WriteByteString(rInfo.aMethodName,RTL_TEXTENCODING_UTF8); + } + + return rStream; +} + +sal_Bool SfxMacroInfo::Compare( const SvxMacro& rMacro ) const +{ + String aName = rMacro.GetLibName(); + aName += '.'; + aName += rMacro.GetMacName(); + if ( GetFullQualifiedName() == aName ) + return sal_True; + return sal_False; +} + +//========================================================================== + +SfxMacroConfig::SfxMacroConfig() +{ + pImp = new SfxMacroConfig_Impl; +} + +//========================================================================== + +SfxMacroConfig::~SfxMacroConfig() +{ + if ( pImp->nEventId ) + Application::RemoveUserEvent( pImp->nEventId ); + delete pImp; +} + +//========================================================================== + +SFX_STATE_STUB( SfxApplication, MacroState_Impl ) +SFX_EXEC_STUB( SfxApplication, MacroExec_Impl ) + +sal_uInt16 SfxMacroConfig::GetSlotId(SfxMacroInfoPtr pInfo) +{ + sal_uInt16 nCount = pImp->aArr.Count(); // Macro suchen + sal_uInt16 i; + for (i=0; i<nCount; i++) + if ((*(pImp->aArr)[i]) == (*pInfo)) + break; + + if (i == nCount) + { // Macro noch unbekannt + nCount = aIdArray.Count(); + sal_uInt16 n; + for (n=0; n<nCount; n++) // freie SlotId suchen + if (aIdArray[n] > SID_MACRO_START + n) + break; + + sal_uInt16 nNewSlotId = SID_MACRO_START + n; + if ( nNewSlotId > SID_MACRO_END ) + return 0; + aIdArray.Insert( SID_MACRO_START + n, n ); + + SfxSlot *pNewSlot = new SfxSlot; + pNewSlot->nSlotId = SID_MACRO_START + n; + pNewSlot->nGroupId = 0; + pNewSlot->nFlags = SFX_SLOT_ASYNCHRON; + pNewSlot->nMasterSlotId = 0; + pNewSlot->nValue = 0; + pNewSlot->fnExec = SFX_STUB_PTR(SfxApplication,MacroExec_Impl); + pNewSlot->fnState = SFX_STUB_PTR(SfxApplication,MacroState_Impl); + pNewSlot->pType = 0; HACK(SFX_TYPE(SfxVoidItem)) + pNewSlot->pName = pNewSlot->pMethodName = U2S(pInfo->aMethodName).getStr(); + pNewSlot->pLinkedSlot = 0; + pNewSlot->nArgDefCount = 0; + pNewSlot->pFirstArgDef = 0; + pNewSlot->pUnoName = 0; + + if (nCount) + { + SfxSlot *pSlot = (pImp->aArr)[0]->pSlot; + pNewSlot->pNextSlot = pSlot->pNextSlot; + pSlot->pNextSlot = pNewSlot; + } + else + pNewSlot->pNextSlot = pNewSlot; + + // Macro uebernehmen + SfxMacroInfoPtr pNewInfo = new SfxMacroInfo(*pInfo); + pNewInfo->nSlotId = SID_MACRO_START + n; + pImp->aArr.Insert(pNewInfo,n); + pNewInfo->pSlot = pNewSlot; + pInfo->nSlotId = pNewInfo->nSlotId; + pNewInfo->nRefCnt++; + } + else + { + pInfo->nSlotId = (pImp->aArr)[i]->nSlotId; + (pImp->aArr)[i]->nRefCnt++; + } + + return pInfo->nSlotId; +} + +//========================================================================== + +void SfxMacroConfig::ReleaseSlotId(sal_uInt16 nId) +{ + DBG_ASSERT( IsMacroSlot( nId ), "SlotId ist kein Macro!"); + + sal_uInt16 nCount = pImp->aArr.Count(); + for (sal_uInt16 i=0; i<nCount; i++) + { + SfxMacroInfo *pInfo = (pImp->aArr)[i]; + if (pInfo->nSlotId == nId) + { + pInfo->nRefCnt--; + if (pInfo->nRefCnt == 0) + { + // Slot wird nicht mehr referenziert, also holen + SfxSlot *pSlot = pInfo->pSlot; + + // Slot aus der Verkettung rausnehmen + while (pSlot->pNextSlot != pInfo->pSlot) + pSlot = (SfxSlot*) pSlot->pNextSlot; + pSlot->pNextSlot = pInfo->pSlot->pNextSlot; + + // Slot selbst kurz schlie\sen + pSlot = pInfo->pSlot; + pSlot->pNextSlot = pSlot; + + // MacroInfo aus Array entfernen, damit sie kein Unheil + // anrichten kann + pImp->aArr.Remove(i); + + // SlotId wieder freigeben + sal_uInt16 nCount = aIdArray.Count(); + for (sal_uInt16 n=0; n<nCount; n++) + { + if (aIdArray[n] == nId) + { + aIdArray.Remove(n); + break; + } + } + + // Falls ein Image belegt wwurde, kann das jetzt wieder frei + // gegeben werden (wenn nicht aus dtor gerufen, da ist der + // ImageManager schon weg) + SfxImageManager *pImgMgr = SFX_IMAGEMANAGER(); + if (pImgMgr) + pImgMgr->ReplaceImage(nId, 0); + + // Sofern nicht die Applikation heruntergefahren wird, mu\s + // der Slot asynchron gel"oscht werden, falls er in seinem + // eigenen Execute abgeschossen wird! + if ( !SFX_APP()->IsDowning() ) + pImp->nEventId = Application::PostUserEvent( LINK(this, SfxMacroConfig, EventHdl_Impl), pInfo ); + else + EventHdl_Impl( pInfo ); + } + return; + } + } + + DBG_ERROR("Macro-SlotId nicht gefunden!"); +} + +//========================================================================== + +void SfxMacroConfig::RegisterSlotId(sal_uInt16 nId) +{ + DBG_ASSERT( IsMacroSlot( nId ), "SlotId ist kein Macro!"); + + sal_uInt16 nCount = pImp->aArr.Count(); + for (sal_uInt16 i=0; i<nCount; i++) + { + if ((pImp->aArr)[i]->nSlotId == nId) + { + (pImp->aArr)[i]->nRefCnt++; + return; + } + } + + DBG_ERROR("Macro-SlotId nicht gefunden!"); +} + +//========================================================================== + +const SfxMacroInfoPtr SfxMacroConfig::GetMacroInfo(sal_uInt16 nId) const +{ + sal_uInt16 nCount = pImp->aArr.Count(); + for (sal_uInt16 i=0; i<nCount; i++) + if ((pImp->aArr)[i]->nSlotId == nId) + return (pImp->aArr)[i]; + + return 0; +} + +//========================================================================== + +const SfxMacroInfoPtr SfxMacroConfig::GetMacroInfo_Impl( const SvxMacro *pMacro ) const +{ + sal_uInt16 nCount = pImp->aArr.Count(); + for (sal_uInt16 i=0; i<nCount; i++) + if ((pImp->aArr)[i]->Compare(*pMacro) ) + return (pImp->aArr)[i]; + return 0; +} + +//========================================================================== + +sal_Bool SfxMacroConfig::ExecuteMacro( sal_uInt16 nId, const String& rArgs ) const +{ + const SfxMacroInfoPtr pInfo = GetMacroInfo( nId ); + if ( !pInfo ) + return sal_False; + + SfxObjectShell* pSh = SfxObjectShell::Current(); + + SvxMacro aMacro( pInfo->GetQualifiedName(), pInfo->GetBasicName(), STARBASIC ); + sal_Bool bRet = ExecuteMacro( pSh, &aMacro, rArgs ); + + // Release, da im Dispatcher-Execute ein Register gemacht wurde + ((SfxMacroConfig*)this)->ReleaseSlotId( nId ); + return bRet; +} + +sal_Bool SfxMacroConfig::ExecuteMacro( SfxObjectShell *pSh, const SvxMacro* pMacro, const String& rArgs ) const +{ + SfxApplication *pApp = SFX_APP(); + + // Name des Macros oder Scripts bzw. ScriptCode + String aCode( pMacro->GetMacName() ); + ErrCode nErr = ERRCODE_NONE; + + // Ist es ein Basic-Macro ? + ScriptType eSType = pMacro->GetScriptType(); + sal_Bool bIsBasic = eSType == STARBASIC; + sal_Bool bIsStarScript = ( eSType == EXTENDED_STYPE && pMacro->GetLibName().SearchAscii( "StarScript" ) != STRING_NOTFOUND ); + sal_Bool bIsBasicLibBased = bIsBasic || bIsStarScript || !pSh; + +#if SUPD<582 + if ( !bIsBasicLibBased && pSh && pApp->GetIniManager()->IsJavaScriptEnabled() ) + { + // AB: #49303# hier muss Window als this gesetzt werden + SfxJS* pJS = pSh->GetMedium()->GetJavaScript(); + SjJScriptWindowObject* pWindow = pJS ? pJS->GetWindowObject() : NULL; + + Link aLink = LINK( this, SfxMacroConfig, CallbackHdl_Impl ); + pImp->bWaitingForCallback = sal_True; + nErr = pSh->CallJavaScript( *pMacro, pWindow, &aLink ); + sal_uInt32 nTicks = Time::GetSystemTicks(); + nTicks += 5000; + while ( pImp->bWaitingForCallback && nTicks > Time::GetSystemTicks() ) + Application::Yield(); + pImp->bWaitingForCallback = sal_False; + return nErr != ERRCODE_NONE; + } + else +#endif + + if ( bIsBasicLibBased ) + { + pApp->EnterBasicCall(); + BasicManager *pAppMgr = SFX_APP()->GetBasicManager(); + if( bIsBasic ) + { + // BasicManager von Document? + BasicManager *pMgr = pSh ? pSh->GetBasicManager() : NULL; + + // Da leider der Name zwischendurch h"aufig gewechselt hat ... + if( SFX_APP()->GetName() == pMacro->GetLibName() || + pMacro->GetLibName().EqualsAscii("StarDesktop") ) + pMgr = pAppMgr; + else if ( pMgr == pAppMgr ) + pMgr = NULL; + + if ( pSh && pMgr && pMgr == pAppMgr ) + { +/* + SfxViewFrame *pFrame = SfxViewFrame::GetFirst( pSh, 0, sal_False ); + SbxVariable *pDocVar = pAppMgr->GetLib(0)->Find( "ThisDocument", SbxCLASS_PROPERTY ); + if ( pDocVar ) + pDocVar->PutObject( pSh->GetSbxObject() ); + + SbxVariable *pWinVar = pAppMgr->GetLib(0)->Find( "ThisWindow", SbxCLASS_PROPERTY ); + if ( pWinVar ) + pWinVar->PutObject( pFrame->GetSbxObject() ); +*/ + SFX_APP()->Get_Impl()->pThisDocument = pSh; + SbxVariable *pCompVar = pAppMgr->GetLib(0)->Find( DEFINE_CONST_UNICODE("ThisComponent"), SbxCLASS_PROPERTY ); + if ( pCompVar ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xInterface ( pSh->GetModel() , ::com::sun::star::uno::UNO_QUERY ); + ::com::sun::star::uno::Any aAny; + aAny <<= xInterface; + pCompVar->PutObject( GetSbUnoObject( DEFINE_CONST_UNICODE("ThisComponent"), aAny ) ); + } + + nErr = Call( 0, aCode, pMgr ); + + SFX_APP()->Get_Impl()->pThisDocument = NULL; +/* + if ( pDocVar ) + pDocVar->PutObject( NULL ); + if ( pWinVar ) + pWinVar->PutObject( NULL ); + */ + if ( pCompVar ) + pCompVar->PutObject( NULL ); + } + else if ( pMgr ) + nErr = Call( 0, aCode, pMgr ); + else + nErr = SbxERR_NO_METHOD; + + } +#if SUPD<582 + else if( bIsStarScript ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xSource; + + // Haben wir eine Shell? + if( pSh ) + { + // dann dort callen + nErr = pSh->CallScript( pMacro->GetLibName(), aCode, xSource, NULL, NULL ); + } + else + { + // ::com::sun::star::script::Engine von der Standard-Bibliothek anfordern + StarBASIC* pStdLib = pAppMgr->GetStdLib(); + ::com::sun::star::uno::Reference< ::com::sun::star::script::XEngine > xEngine= pStdLib->getEngine( pAppMgr ); + SfxMacroConfig::CallStarScript( xEngine, aCode, xSource, NULL, NULL ); + } + } +#endif + pApp->LeaveBasicCall(); + } + else + { + nErr = SbxERR_NO_METHOD; + } + + return ( nErr == ERRCODE_NONE ); +} + +sal_Bool SfxMacroConfig::CheckMacro( SfxObjectShell *pSh, const SvxMacro* pMacro ) const +{ + SfxApplication *pApp = SFX_APP(); + + // Name des Macros oder Scripts bzw. ScriptCode + String aCode( pMacro->GetMacName() ); + ErrCode nErr = ERRCODE_NONE; + +#if SUPD<582 + // Ist es ein Basic-Macro ? + sal_Bool bIsBasic = pMacro->GetScriptType() == STARBASIC; + if ( !bIsBasic ) + return pSh != NULL; +#endif + + // BasicManager von Document oder Application + pApp->EnterBasicCall(); + BasicManager *pAppMgr = SFX_APP()->GetBasicManager(); + BasicManager *pMgr = pSh ? pSh->GetBasicManager() : NULL; + + // Da leider der Name zwischendurch h"aufig gewechselt hat ... + if( SFX_APP()->GetName() == pMacro->GetLibName() || + pMacro->GetLibName().EqualsAscii("StarDesktop") ) + pMgr = pAppMgr; + else if ( pMgr == pAppMgr ) + pMgr = NULL; + + if ( !pMgr || !SfxQueryMacro( pMgr, aCode ) ) + nErr = SbxERR_NO_METHOD; + pApp->LeaveBasicCall(); + return ( nErr == ERRCODE_NONE ); +} + +//========================================================================== + +sal_Bool SfxMacroConfig::CheckMacro( sal_uInt16 nId ) const +{ + const SfxMacroInfoPtr pInfo = GetMacroInfo( nId ); + if ( !pInfo ) + return sal_False; + + // Basic nur initialisieren, wenn default nicht ::com::sun::star::script::JavaScript; dann mu\s + // in IsBasic() sowieso das Basic angelegt werden + SfxObjectShell* pSh = SfxObjectShell::Current(); + + SfxApplication *pApp = SFX_APP(); + pApp->EnterBasicCall(); + + // BasicManager von Document oder Application + BasicManager *pAppMgr = SFX_APP()->GetBasicManager(); + BasicManager *pMgr = pSh ? pSh->GetBasicManager() : NULL; + + if( SFX_APP()->GetName() == pInfo->GetBasicName() ) + pMgr = SFX_APP()->GetBasicManager(); + else if ( pMgr == pAppMgr ) + pMgr = NULL; + + String aFull( pInfo->GetQualifiedName() ); + sal_Bool bIsBasic = pMgr ? IsBasic( 0, aFull, pMgr ) : sal_False; + pApp->LeaveBasicCall(); + return bIsBasic; +} + +//========================================================================== + +IMPL_LINK( SfxMacroConfig, CallbackHdl_Impl, SfxMacroConfig*, pConfig ) +{ + pImp->bWaitingForCallback = sal_False; + return 0; +} + +IMPL_LINK( SfxMacroConfig, EventHdl_Impl, SfxMacroInfo*, pInfo ) +{ + delete pInfo; + pImp->nEventId = 0; + return 0; +} + +sal_Bool SfxMacroConfig::IsBasic( SbxObject* pVCtrl, const String& rCode, BasicManager* pMgr ) +{ + sal_Bool bFound; + SFX_APP()->EnterBasicCall(); + bFound = SfxQueryMacro( pMgr, rCode ) != 0; + SFX_APP()->LeaveBasicCall(); + return bFound; +} + +ErrCode SfxMacroConfig::Call( SbxObject* pVCtrl, + const String& rCode, BasicManager* pMgr, SbxArray *pArgs, SbxValue *pRet ) +{ + SfxApplication *pApp = SFX_APP(); + pApp->EnterBasicCall(); + SbMethod* pMethod = SfxQueryMacro( pMgr, rCode ); + ErrCode nErr = 0; + if( pMethod ) + { + if ( pArgs ) + pMethod->SetParameters( pArgs ); + nErr = pMethod->Call( pRet ); + } + else + nErr = ERRCODE_BASIC_PROC_UNDEFINED; + + pApp->LeaveBasicCall(); + return nErr; +} + +#if SUPD<582 +void SfxMacroConfig::CallStarScript( const ::com::sun::star::uno::Reference< ::com::sun::star::script::XEngine > & rxEngine, const String & rCode, + const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > & rSource, void *pArgs, void *pRet ) +{ + static String aCallPrefix( "();" ); + + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > aArgs; + if( pArgs ) + aArgs = *(::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > *)pArgs; + + // HACK!!! TODO: Klaeren, wie das wirklich laufen soll + String aCode = rCode; + aCode += aCallPrefix; + + ::rtl::OUString aUCode = StringToOUString( aCode, RTL_TEXTENCODING_UTF8 ); + if ( pRet ) + { + *((::com::sun::star::uno::Any*)pRet) = rxEngine->run( aUCode, rSource, aArgs ); + } + else + { + ::com::sun::star::uno::Reference< ::com::sun::star::script::XEngineListener > xCB; + rxEngine->runAsync( aUCode, rSource, aArgs, xCB ); + } +} +#endif + +sal_Bool SfxMacroConfig::IsMacroSlot( sal_uInt16 nId ) +{ + return ( nId >= SID_MACRO_START && nId <= SID_MACRO_END ); +} + + diff --git a/sfx2/source/control/macro.cxx b/sfx2/source/control/macro.cxx new file mode 100644 index 000000000000..8affc5acfa37 --- /dev/null +++ b/sfx2/source/control/macro.cxx @@ -0,0 +1,858 @@ +/************************************************************************* + * + * $RCSfile: macro.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _ARGS_HXX //autogen +#include <svtools/args.hxx> +#endif + +#ifndef _SBXVAR_HXX //autogen +#include <svtools/sbxvar.hxx> +#endif +#pragma hdrstop + +#include <app.hxx> +#include <module.hxx> +#include <shell.hxx> +#include <request.hxx> +#include <objsh.hxx> +#include <viewsh.hxx> +#include <viewfrm.hxx> +#include <msg.hxx> +#include <macro.hxx> +#include <sfxtypes.hxx> + +//==================================================================== + +SV_DECL_PTRARR_DEL( SfxStatements_Impl, SfxMacroStatement*, 16, 8 ); +SV_IMPL_PTRARR( SfxStatements_Impl, SfxMacroStatement* ); +TYPEINIT1(SfxMacroItem,SfxPoolItem); + +//-------------------------------------------------------------------- + +struct SfxMacro_Impl + +/* [Beschreibung] + + Implementations-Struktur der Klasse <SfxMacro>. +*/ + +{ + SfxMacroMode eMode; /* Zweck der <SfxMacro>-Instanz, + Bedeutung siehe enum <SfxMacroMode> */ + SfxStatements_Impl aList; /* Liste von aufgezeichneten Statements */ + USHORT nObjNo; // Durchnumerierung der SbxObjects +}; + +//==================================================================== + +SfxMacroStatement::SfxMacroStatement +( + const SfxShell& rShell, // <SfxShell>, die den Request ausf"uhrte + const String& rTarget, // Name des Zielobjektes vor der Ausf"urhung + BOOL bAbsolute, // obsolet + const SfxSlot& rSlot, // der <SfxSlot>, der das Statement abspielen kann + BOOL bRequestDone, // wurde der Request tats"achlich ausgef"uhrt + SfxArguments* pArguments // aktuelle Parameter (werden "ubernommen) +) + +/* [Beschreibung] + + Dieser Konstruktor der Klasse SfxMacroStatement erzeugt ein Statement, + bei dem ein Objekt angesprochen wird, welches durch 'rShell' angegeben + ist. Dabei erfolgt die Addressierung je nach 'bAbsolute' absolut, + also z.B. als '[mydoc.sdc]' oder relativ, also z.B. 'ActiveDocument'. + + Je nach Art der Subklasse von 'rShell' ergeben sich folgende + Ausdr"ucke: + + |absolut relativ + ----------------------------------------------------------------------- + SfxApplication' | 'StarCalc' 'Application' + SfxViewFrame' |'[mydoc.sdc:1]' 'ActiveWindow' + SfxViewShell' | '[mydoc.sdc:1]' 'AvtiveWindow' + SfxObjectShell' | '[mydoc.sdc]' 'ActiveDocument' + sonstige (Sub-Shells) | '[mydoc.sdc:1]' 'ActiveWindow' + + Dabei sind 'StarCalc' stellvertretend fr den Namen der Applikation + (Application::GetAppName()const). In der absoluten Fassung k"onnte + die Selektion auch deskriptiv z.B. als 'CellSelection("A5-D8")') + angesprochen werden, dazu mu\ jedoch vom Anwendungsprogrammierer der + Konstruktor <SfxMacroStatement::SfxMacroStatement(const String&, + const SfxSlot&,BOOL,SfxArguments*)> verwendet werden. + + F"ur das so bezeichnete Objekt wird dann je nach Typ des Slots + eine Zuweisung an eines seiner Properties oder der Aufruf einer seiner + Methoden ausgedr"uckt. + + + [Beispiele] + + absolut: + SCalc3.OpenDocument( "\docs\mydoc.sdd", "StarDraw Presentation", 0, 0 ) + [mydoc.sdd].Activate() + [mydoc.sdd:1].SwitchToView( 2 ) + [mydoc.sdc:1:1].CellSelection( "A5-D8" ).LineColor = 192357 + + relativ: + ActiveWindow.LineColor = 192357 + + + [Querverweise] + + <SfxMacroStatement::SfxMacroStatement(const String&,const SfxSlot&,BOOL,SfxArguments*)> + <SfxMacroStatement::SfxMacroStatement(const String&)> +*/ + +: nSlotId( rSlot.GetSlotId() ), + pArgs( pArguments ), + bDone( bRequestDone ), + pDummy( 0 ) +{ + // Workaround Recording nicht exportierter Slots (#25386#) + if ( !rSlot.pName ) + return; + + // Objekt-Typ bestimmen + FASTBOOL bIsApp = rShell.ISA(SfxApplication); + FASTBOOL bIsDoc = rShell.ISA(SfxObjectShell); + FASTBOOL bIsWin = !bIsApp && !bIsDoc && + ( rShell.ISA(SfxViewShell) || rShell.ISA(SfxViewFrame) ); + FASTBOOL bIsSel = !bIsApp && !bIsDoc && !bIsWin; + + // Objekt nicht schon im Slot-Namen enthalten? + if ( bIsSel || rSlot.pName[0] == '.' ) + { + // absolutes Aufzeichnen? + if ( rSlot.IsMode( SFX_SLOT_RECORDABSOLUTE ) ) + { + // an der Applikation oder am Modul + if ( rShell.ISA(SfxApplication) || rShell.ISA(SfxModule) ) + aStatement = rTarget; + + // am Dokument? + // '[' = 5Bh + // ']' = 5Dh + else if ( rShell.ISA(SfxObjectShell) ) + { + aStatement = 0x005B; + aStatement += rTarget; + aStatement += 0x005D; + } + + else if ( rShell.ISA(SfxViewFrame) ) + { + aStatement = 0x005B; + aStatement += rShell.GetSbxObject()->GetName(); + aStatement += 0x005D; + } + + else + { + // an der View oder Sub-Shell + SfxViewShell *pViewShell = rShell.GetViewShell(); + aStatement = 0x005B; + aStatement += pViewShell->GetViewFrame()->GetSbxObject()->GetName(); + aStatement += 0x005D; + if ( !rShell.ISA(SfxViewFrame) ) + // an einer Sub-Shell zus"atlich .Selection anh"angen + aStatement += DEFINE_CONST_UNICODE(".Selection"); + } + } + else // relatives Aufzeichnen + { + // an der Application? + if ( rShell.ISA(SfxApplication) ) + aStatement = DEFINE_CONST_UNICODE("Application"); + + // am Modul? + else if ( rShell.ISA(SfxModule) ) + aStatement = DEFINE_CONST_UNICODE("ActiveModule"); + + // am Dokument + else if ( rShell.ISA(SfxObjectShell) ) + aStatement = DEFINE_CONST_UNICODE("ActiveDocument"); + + // am Window + else if ( rShell.ISA(SfxViewShell) || rShell.ISA(SfxViewFrame) ) + aStatement = DEFINE_CONST_UNICODE("ActiveWindow"); + + else + // an einer Sub-Shell + aStatement = DEFINE_CONST_UNICODE("Selection"); + } + } +/* + if ( bIsSel ) + { + // bei Selection ggf. noch den Namen der SubShell anh"angen + const SfxShellObject *pShObj = + (const SfxShellObject*) rShell.GetSbxObject(); + if ( pShObj ) + { + const SfxShellObject *pParentObj = + (const SfxShellObject*) pShObj->GetParent(); + SfxShell *pParentSh = pParentObj->GetShell(); + DBG_ASSERT( pParentSh->ISA(SfxViewFrame), + "parent of SubShell must be a Frame" ); + if ( rSlot.pName[0] == '.' ) + { + aStatement += '.'; + aStatement += rShell.GetSbxObject()->GetName(); + } + } + else + DBG_ASSERT( rSlot.pName[0] != '0', "recording unnamed object" ); + } +*/ + // an diesen Objekt-Ausdruck den Methoden-/Property-Namen und Parameter + GenerateNameAndArgs_Impl( SfxRequest::GetRecordingMacro(), + rSlot, bRequestDone, pArgs); +} + +//-------------------------------------------------------------------- + +SfxMacroStatement::SfxMacroStatement +( + const String& rTarget, // Objekt, was beim Playing angesprochen wird + const SfxSlot& rSlot, // der <SfxSlot>, der das Statement abspielen kann + BOOL bRequestDone, // wurde der Request tats"achlich ausgef"uhrt + SfxArguments* pArguments // aktuelle Parameter (werden "ubernommen) +) + +/* [Beschreibung] + + + [Querverweise] + + <SfxMacroStatement::SfxMacroStatement(const String&)> + <SfxMacroStatement::SfxMacroStatement(const SfxShell&,BOOL,const SfxSlot&,BOOL,SfxArguments*)> +*/ + +: nSlotId( rSlot.GetSlotId() ), + pArgs( pArguments ), + bDone( bRequestDone ), + pDummy( 0 ) +{ + aStatement = rTarget; + aStatement += 0x002E; // '.' = 2Eh + GenerateNameAndArgs_Impl( SfxRequest::GetRecordingMacro(), + rSlot, bRequestDone, pArgs); +} + +//-------------------------------------------------------------------- + +SfxMacroStatement::SfxMacroStatement +( + const String& rStatement // manuell erzeugte(s) Statement(s) +) + +/* [Beschreibung] + + Dieser Konstruktor erzeugt eine SfxMacroStatement-Instanz, deren + Aufbau vollst"andig vom Applikationsentwickler bestimmt wird. Da der + angegebene String auch mehrere mit CR/LF getrennte Statements + enthalten darf, ist damit ein weitgehender Eingriff in das Aufzeichnen + von BASIC-Makros m"oglich, um Spezialf"alle zu behandeln. + + + [Querverweise] + + <SfxMacroStatement::SfxMacroStatement(const String&,const SfxSlot&,BOOL,SfxArguments*)> + <SfxMacroStatement::SfxMacroStatement(const SfxShell&,BOOL,const SfxSlot&,BOOL,SfxArguments*)> +*/ + +: aStatement( rStatement ), + nSlotId( 0 ), + pArgs( 0 ), + bDone( TRUE ), + pDummy( 0 ) +{ +} + +//-------------------------------------------------------------------- + +SfxMacroStatement::SfxMacroStatement +( + const SfxMacroStatement& rOrig // Original, von dem kopiert wird +) + +/* [Beschreibung] + + Copy-Konstruktor der SfxMacroStatement-Klasse. +*/ + +: aStatement( rOrig.aStatement ), + nSlotId( rOrig.nSlotId ), + pArgs( 0 ), + bDone( rOrig.bDone ), + pDummy( 0 ) +{ + if ( rOrig.pArgs ) + pArgs = new SfxArguments( *rOrig.pArgs ); +} + +//-------------------------------------------------------------------- + +SfxMacroStatement::~SfxMacroStatement() + +/* [Beschreibung] + + Destruktor der Klasse SfxMacroStatement. Gibt die Liste der + aktuellen Parameter frei. +*/ + +{ + delete pArgs; +} + +//-------------------------------------------------------------------- + +void SfxMacroStatement::GenerateNameAndArgs_Impl +( + SfxMacro* pMacro, // darin wird aufgezeichnet + const SfxSlot& rSlot, // der Slot, der das Statement abspielen kann + BOOL bRequestDone, // TRUE=wurde ausgef"uhrt, FALSE=abgebrochen + SfxArguments* pArgs // die aktuellen Parameter +) + +/* [Beschreibung] + + Interne Hilfsmethode zum generieren des Funktions-/Property-Names + sowie der Parameter. Diese Methode wird nur verwendet, wenn der + Anwendungsprogrammierer keinen eigenen Source an den <SfxRequest> + geh"angt hat. +*/ + +{ + // . zwsischen Object und Prop/Meth-Name + // '.' = 2Eh + if ( aStatement.Len() && aStatement.GetChar( aStatement.Len() - 1 ) != 0x002E && + rSlot.pName[0] != 0x002E ) + aStatement += 0x002E; + + // der Name des Slots ist der Name der Methode / des Properties + aStatement += String::CreateFromAscii(rSlot.pName); + if ( rSlot.IsMode(SFX_SLOT_METHOD) ) + aStatement += DEFINE_CONST_UNICODE("( "); + else + aStatement += DEFINE_CONST_UNICODE(" = "); + + // alle zusammengesuchten Parameter rausschreiben + if ( pArgs && pArgs->Count() ) // Abfrage doppelt wegen BLC-Bug + for ( USHORT nArg = 0; nArg < pArgs->Count(); ++nArg ) + { + // den Parameter textuell darstellen + String aArg; + const SbxVariable& rVar = pArgs->Get(nArg); + switch ( rVar.GetType() & (2*SbxUSERn+1) ) + { + case SbxEMPTY: + case SbxNULL: + // kein Argument + break; + + case SbxSTRING: + { + // Anf"uhrungszeichen werden verdoppelt + XubString aRecordable( rVar.GetString() ); + USHORT nPos = 0; + while ( TRUE ) + { + nPos = aRecordable.SearchAndReplace( DEFINE_CONST_UNICODE('"'), DEFINE_CONST_UNICODE("\"\""), nPos ); + if ( STRING_NOTFOUND == nPos ) + break; + nPos += 2; + } + + // nicht druckbare Zeichen werden als chr$(...) geschrieben + FASTBOOL bPrevReplaced = FALSE; + for ( USHORT n = 0; n < aRecordable.Len(); ++n ) + { + sal_Unicode cChar = aRecordable.GetChar(n); + if ( !( cChar>=32 && cChar!=127 ) ) // ALS ERSATZ FUER String::IsPrintable()! + { + XubString aReplacement( DEFINE_CONST_UNICODE("+chr$(") ); + aReplacement += cChar; + + if ( bPrevReplaced ) + { + aRecordable.Insert( aReplacement, n - 2 ); + n += aReplacement.Len(); + aRecordable.SetChar((unsigned short) (n-2), 0x0029);// ')' = 29h + aRecordable.Replace( n-1, 2, DEFINE_CONST_UNICODE("+\"") ); + // ++n; + } + else + { + aReplacement += DEFINE_CONST_UNICODE(")+\""); + aRecordable.SetChar(n, 0x0022 );// '"' = 22h + aRecordable.Insert( aReplacement, n + 1 ); + n += aReplacement.Len(); + } + bPrevReplaced = TRUE; + } + else + bPrevReplaced = FALSE; + } + + // Argument in Anf"uhrungszeichen + aArg = 0x0022; // '"' = 22h + aArg += aRecordable; + aArg += 0x0022; + break; + } + + case SbxBOOL: + { + // symbolisch als TRUE und FALSE + aArg = rVar.GetBool() ? DEFINE_CONST_UNICODE("TRUE") : DEFINE_CONST_UNICODE("FALSE"); + break; + } + + case SbxBYTE: + { + // als Zahl darstellen + aArg = (USHORT) rVar.GetByte(); + break; + } + + case SbxOBJECT: + { + HACK(only an experimental implementation) + SbxObjectRef xObj = (SbxObject*) rVar.GetObject(); + + // einen Objektnamen generieren + String aObjectName( 'a' ); + aObjectName += xObj->GetClassName(); + aObjectName += pMacro->NextObjectNo(); + + // das Objekt mit Daten belegen + String aObjectDef( DEFINE_CONST_UNICODE("\nDIM ") ); + aObjectDef += aObjectName; + aObjectDef += DEFINE_CONST_UNICODE(" AS NEW "); + aObjectDef += xObj->GetClassName(); + aObjectDef += DEFINE_CONST_UNICODE("\nWITH "); + aObjectDef += aObjectName; + aObjectDef += DEFINE_CONST_UNICODE("\n"); + aObjectDef += xObj->GenerateSource( DEFINE_CONST_UNICODE("\t"), 0 ); + aObjectDef += DEFINE_CONST_UNICODE("\nEND WITH\n"); + aStatement.Insert( aObjectDef, 0 ); + aObjectDef += DEFINE_CONST_UNICODE("\n\n"); + + // Objektname als Parameter anh"angen + aArg = aObjectName; + break; + } + + default: + // alles andere als String ohne Anf"uhrungszeichen + aArg = rVar.GetString(); + } + + // den Parameter anh"angen + aStatement += aArg; + aStatement += DEFINE_CONST_UNICODE(", "); + } + + // Statement beeden + if ( pArgs && pArgs->Count() ) + aStatement.Erase( aStatement.Len() - 2, 1 ); + else + aStatement.Erase( aStatement.Len() - 1, 1 ); + if ( rSlot.IsMode(SFX_SLOT_METHOD) ) + aStatement += 0x0029; // ')' = 29h + + if ( !bRequestDone ) + // nicht als "Done()" gekennzeichnete Statements auskommentieren + aStatement.InsertAscii( "rem ", 0 ); +} + +//-------------------------------------------------------------------- + +SfxMacro::SfxMacro +( + SfxMacroMode eMode // Zweck der Instanz, siehe <SfxMacroMode> +) + +/* [Beschreibung] + + Konstruktor der Klasse SfxMacro. Instanzen dieser Klasse werden im + SFx zu zwei Zwecken ben"otigt: + + 1. zum Aufzeichnen von Makros + In diesem Fall wird der Konstruktor mit SFX_MACRO_RECORDINGABSOLUTE + oder SFX_MACRO_RECORDINGRELATIVE aufgerufen. Es sollte sich um eine + Instanz einer abgeleiteten Klasse handeln, um in der Ableitung + die Information dar"uber unterzubringen, wo das Makro gespeichert + werden soll. Ein solches Makro solle sich dann in seinem Destruktor + an der vom Benutzer gew"ahlten Stelle speichern. + + 2. zum Zuordnen von exisitierenden Makros + In diesem Fall wird der Konstruktor mit SFX_MACRO_EXISTING aufgerufen. + Eine solche Instanz wird z.B. ben"otigt, wenn Makros auf Events + oder <SfxControllerItem>s konfiguriert werden sollen. +*/ + +: pImp( new SfxMacro_Impl ) + +{ + pImp->eMode = eMode; + pImp->nObjNo = 0; +} + +//-------------------------------------------------------------------- + +SfxMacro::~SfxMacro() + +/* [Beschreibung] + + Virtueller Destruktor der Klasse SfxMacro. Dieser sollte in den + abgeleiteten Klassen "uberladen werden, um in den Modi + SFX_MACRO_RECORDINGABSOLUTE und SFX_MACRO_RECORDINGRELATIVE den + aufgezeichneten Source abzuspeichern. + + + [Querverweise] + + <SfxMacro::GenerateSource()const> +*/ + +{ +#ifdef DBG_UTIL +#ifdef MAC + SvFileStream aStream( DEFINE_CONST_UNICODE("record.bas"), STREAM_STD_WRITE ); +#else + SvFileStream aStream( DEFINE_CONST_UNICODE("/tmp/record.bas"), STREAM_STD_WRITE ); +#endif + aStream.WriteLine( ByteString(U2S(GenerateSource())) ); +#endif + delete pImp; +} + +//-------------------------------------------------------------------- + +SfxMacroMode SfxMacro::GetMode() const + +/* [Beschreibung] + + Liefert den Modus, der besagt zu welchem Zweck das SfxMacro konstruiert + wurde. + + + [Querverweise] + + enum <SfxMacroMode> +*/ + +{ + return pImp->eMode; +} + +//-------------------------------------------------------------------- + +USHORT SfxMacro::NextObjectNo() + +/* [Beschreibung] + + Liefert eine Nummer, die als Namens-Erweiterung f"ur SbxObjects, + die per DIM angelegt werden m"ussen, verwendet werden kann. Bei jedem + Abfragen kommt eine um 1 erh"ohte Nummer zur"uck, die in diesem Makro + einmalig ist. +*/ + +{ + return ++pImp->nObjNo; +} + +//-------------------------------------------------------------------- + +void SfxMacro::Record +( + SfxMacroStatement* pStatement // aufzuzeichnendes <SfxMacroStatement> +) + +/* [Beschreibung] + + Diese Methode zeichnet das als Parameter "ubergeben Statement auf. + Die Instanz auf die der "ubergebe Pointer zeigt, geht in das Eigentum + des SfxMacro "uber. + + Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt, + welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE + konstruiert wirde. + + + [Querverweise] + + <SfxMacro::Replace(SfxMacroStatement*)> + <SfxMacro::Remove()> + <SfxMacro::GetLastStatement()const> +*/ + +{ + DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, + "invalid call to non-recording SfxMacro" ); + pImp->aList.C40_INSERT( SfxMacroStatement, pStatement, pImp->aList.Count() ); +} + +//-------------------------------------------------------------------- + +void SfxMacro::Replace +( + SfxMacroStatement* pStatement // aufzuzeichnendes <SfxMacroStatement> +) + +/* [Beschreibung] + + Diese Methode zeichnet das als Parameter "ubergeben Statement auf. + Dabei wird das jeweils zuletzt aufgezeichnete Statement "uberschrieben. + Die Instanz auf die der "ubergebe Pointer zeigt, geht in das Eigentum + des SfxMacro "uber. + + Mit dieser Methode ist es m"oglich, Statements zusammenzufassen. Z.B. + anstelle f"unfmal hintereinander 'CursorLeft()' aufzurufen, k"onnte + das zu 'CursorLeft(5)' zusammengefa\st werden. Oder anstelle ein Wort + Buchstabe f"ur Buchstabe aufzubauen, k"onnte dies durch ein einziges + Statement 'InsertString("Hallo")' ersetzt werden. + + Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt, + welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE + konstruiert wurde und bereits ein aufgezeichnetes Statement vorhanden + ist. + + + [Anmerkung] + + Diese Methode wird typischerweise aus den Execute-Methoden der + <SfxSlot>s von den Applikationsentwicklern gerufen. + + + [Querverweise] + + <SfxMacro::Record(SfxMacroStatement*)> + <SfxMacro::Remove()> + <SfxMacro::GetLastStatement()const> +*/ + +{ + DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, + "invalid call to non-recording SfxMacro" ); + DBG_ASSERT( pImp->aList.Count(), "no replaceable statement available" ) + pImp->aList.Remove( pImp->aList.Count() - 1 ); + pImp->aList.C40_INSERT( SfxMacroStatement,pStatement, pImp->aList.Count() ); +} + +//-------------------------------------------------------------------- + +void SfxMacro::Remove() + +/* [Beschreibung] + + Diese Methode l"oscht das zuletzt aufgezeichnete <SfxMacroStatement> + und entfernt es aus dem Macro. + + Mit dieser Methode ist es m"oglich, Statements zusammenzufassen. Z.B. + anstelle f"unfmal hintereinander 'CursorLeft()' aufzurufen, k"onnte + das zu 'CursorLeft(5)' zusammengefa\st werden. Oder anstelle ein Wort + Buchstabe f"ur Buchstabe aufzubauen, k"onnte dies durch ein einziges + Statement 'InsertString("Hallo")' ersetzt werden. + + Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt, + welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE + konstruiert wurde und bereits ein aufgezeichnetes Statement vorhanden + ist. + + + [Anmerkung] + + Diese Methode wird typischerweise aus den Execute-Methoden der + <SfxSlot>s von den Applikationsentwicklern gerufen. + + + [Querverweise] + + <SfxMacro::Replace(SfxMacroStatement*)> + <SfxMacro::Record(SfxMacroStatement*)> + <SfxMacro::GetLastStatement()const> +*/ + +{ + DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, + "invalid call to non-recording SfxMacro" ); + DBG_ASSERT( pImp->aList.Count(), "no replaceable statement available" ) + pImp->aList.Remove( pImp->aList.Count() - 1 ); +} + +//-------------------------------------------------------------------- + +const SfxMacroStatement* SfxMacro::GetLastStatement() const + +/* [Beschreibung] + + Mit dieser Methode kann auf das jeweils zuletzt aufgezeichnete Statement + lesend zugegriffen werden. Zusammen mit der Methode + <SfxMacro::Replace(SfxMacroStatement*)> ergibt sich dadurch die + M"oglichkeit, Statements zusammenzufassen. + + Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt, + welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE + konstruiert wurde. + + + [Querverweise] + + <SfxMacro::Record(SfxMacroStatement*)> + <SfxMacro::Replace(SfxMacroStatement*)> +*/ + +{ + DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, + "invalid call to non-recording SfxMacro" ); + if ( pImp->aList.Count() ) + return pImp->aList.GetObject( pImp->aList.Count() - 1 ); + return 0; +} + +//-------------------------------------------------------------------- + +String SfxMacro::GenerateSource() const + +/* [Beschreibung] + + Diese Funktion generiert aus den, seit dem Konstruieren der Instanz + bis zum Zeitpunkt des Aufrufs dieser Methode aufgezeichneten + <SfxMacroStatement>s einen BASIC-Sourcecode, der die Statements, + jedoch nicht den Header ('Sub X') und den Footer ('End Sub') enth"alt. + + + [Querverweise] + + <SfxMacro::Record(SfxMacroStatement*)> + <SfxMacro::Repeat(SfxMacroStatement*)> +*/ + +{ + DBG_ASSERT( pImp->eMode != SFX_MACRO_EXISTING, + "invalid call to non-recording SfxMacro" ); + String aSource; + for ( USHORT n = 0; n < pImp->aList.Count(); ++n ) + { + aSource += pImp->aList.GetObject(n)->GetStatement(); + if ( (n+1) < pImp->aList.Count() ) + aSource += DEFINE_CONST_UNICODE("\n"); + } + + return aSource; +} + +//-------------------------------------------------------------------- + +SbxError SfxMacro::Call +( + SbxArray* pArgs // aktuelle Parameter f"ur den Aufruf +) + +/* [Beschreibung] + + Diese Methode sollte von Suklassen "uberladen werden, damit der + SFx das in der Ableitung beschriebene BASIC-Programm rufen kann, + wenn es an ein Event oder in einem Controller gebunden ist. + + Der Aufruf ist nur g"ultig, wenn es sich um ein SfxMacro handelt, + welches mit SFX_MACRO_RECORDINGABSOLUTE oder SFX_MACRO_RECORDINGRELATIVE + konstruiert wurde. + + Die Basisimplementierung liefert immer SbxERR_NOTIMP zur"uck. + + + [Anmerkung] + + I.d.R. ist pArgs == 0, der Parameter ist f"ur Zuk"unftige Erweiterungen + gedacht. +*/ + +{ + return SbxERR_NOTIMP; +} + +//-------------------------------------------------------------------- + +SfxMacroItem::SfxMacroItem( USHORT nWhich, SfxMacro *pTheMacro ) +: SfxPoolItem( nWhich ), + pMacro( pTheMacro ) +{ +} + +//-------------------------------------------------------------------- + +SfxPoolItem* SfxMacroItem::Clone( SfxItemPool *pPool ) const +{ + return new SfxMacroItem( Which(), pMacro ); +} + +//-------------------------------------------------------------------- + +int SfxMacroItem::operator==( const SfxPoolItem &rOther ) const +{ + return pMacro == ((const SfxMacroItem&)rOther).pMacro; +} + + diff --git a/sfx2/source/control/makefile.mk b/sfx2/source/control/makefile.mk new file mode 100644 index 000000000000..53723b82cebf --- /dev/null +++ b/sfx2/source/control/makefile.mk @@ -0,0 +1,120 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (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.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=sfx2 +TARGET=control +ENABLE_EXCEPTIONS=TRUE +.INCLUDE : $(PRJ)$/util$/makefile.pmk +AUTOSEG=true + + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# w.g. compilerbugs +.IF "$(GUI)"=="WNT" +CFLAGS+=-Od +.ENDIF + +# --- Files -------------------------------------------------------- + +CXXFILES = \ + unoctitm.cxx \ + macro.cxx \ + request.cxx \ + dispatch.cxx \ + ctrlitem.cxx \ + statcach.cxx \ + msgpool.cxx \ + shell.cxx \ + objface.cxx \ + msg.cxx \ + bindings.cxx \ + macrconf.cxx \ + minfitem.cxx \ + srchitem.cxx \ + $(PROJECTPCHSOURCE).cxx + +SLOFILES = \ + $(SLO)$/unoctitm.obj \ + $(SLO)$/request.obj \ + $(SLO)$/dispatch.obj \ + $(SLO)$/msgpool.obj \ + $(SLO)$/objface.obj \ + $(SLO)$/ctrlitem.obj \ + $(SLO)$/statcach.obj \ + $(SLO)$/shell.obj \ + $(SLO)$/msg.obj \ + $(SLO)$/bindings.obj \ + $(SLO)$/minfitem.obj \ + $(SLO)$/srchitem.obj \ + $(SLO)$/macrconf.obj + +# --- Targets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/sfx2/source/control/minfitem.cxx b/sfx2/source/control/minfitem.cxx new file mode 100644 index 000000000000..9a6735d7a9c8 --- /dev/null +++ b/sfx2/source/control/minfitem.cxx @@ -0,0 +1,136 @@ +/************************************************************************* + * + * $RCSfile: minfitem.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +// INCLUDE --------------------------------------------------------------- + +#pragma hdrstop + +#include "minfitem.hxx" + +// STATIC DATA ----------------------------------------------------------- + +TYPEINIT1(SfxMacroInfoItem, SfxPoolItem); + +// ----------------------------------------------------------------------- + +SfxMacroInfoItem::SfxMacroInfoItem(USHORT nWhich, // Slot-ID + const BasicManager* pMgr, + const String &rLibName, + const String &rModuleName, + const String &rMethodName, + const String &rComment) : + SfxPoolItem(nWhich), + pBasicManager(pMgr), + aLibName(rLibName), + aModuleName(rModuleName), + aMethodName(rMethodName), + aCommentText(rComment) +{ +} + +// ----------------------------------------------------------------------- + +// copy ctor + +SfxMacroInfoItem::SfxMacroInfoItem(const SfxMacroInfoItem& rCopy): + SfxPoolItem(rCopy), + pBasicManager(rCopy.pBasicManager), + aLibName(rCopy.aLibName), + aModuleName(rCopy.aModuleName), + aMethodName(rCopy.aMethodName), + aCommentText(rCopy.aCommentText) +{ +} + +// ----------------------------------------------------------------------- + +// op == + +int SfxMacroInfoItem::operator==( const SfxPoolItem& rCmp) const +{ + return SfxPoolItem::operator==(rCmp) && + pBasicManager == ((const SfxMacroInfoItem&)rCmp).pBasicManager && + aLibName == ((const SfxMacroInfoItem&)rCmp).aLibName && + aModuleName == ((const SfxMacroInfoItem&)rCmp).aModuleName && + aMethodName == ((const SfxMacroInfoItem&)rCmp).aMethodName && + aCommentText == ((const SfxMacroInfoItem&)rCmp).aCommentText; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem *SfxMacroInfoItem::Clone( SfxItemPool *) const +{ + return new SfxMacroInfoItem(*this); +} + +// ----------------------------------------------------------------------- + +String SfxMacroInfoItem::GetQualifiedName() const +{ + String aMacroName = aLibName; + aMacroName += '.'; + aMacroName += aModuleName; + aMacroName += '.'; + aMacroName += aMethodName; + return aMacroName; +} + + diff --git a/sfx2/source/control/msg.cxx b/sfx2/source/control/msg.cxx new file mode 100644 index 000000000000..028f05b17a5d --- /dev/null +++ b/sfx2/source/control/msg.cxx @@ -0,0 +1,101 @@ +/************************************************************************* + * + * $RCSfile: msg.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SFXITEMPOOL_HXX //autogen +#include <svtools/itempool.hxx> +#endif +#ifndef _SFXENUMITEM_HXX //autogen +#include <svtools/eitem.hxx> +#endif +#pragma hdrstop + +#include "msg.hxx" + +//==================================================================== + +SfxSlotKind SfxSlot::GetKind() const +{ + if( !nMasterSlotId && !nValue) + return (SfxSlotKind) SFX_KIND_STANDARD; + if ( nMasterSlotId && fnExec==0 && fnState==0 ) + { + if ( pType->Type() == TYPE(SfxBoolItem) ) + return (SfxSlotKind) SFX_KIND_ENUM; + else + { + DBG_ERROR( "invalid slot kind detected" ); + return SFX_KIND_ENUM; + } + } + else + return (SfxSlotKind) SFX_KIND_ATTR; +} + +//-------------------------------------------------------------------- + +USHORT SfxSlot::GetWhich( const SfxItemPool &rPool ) const +{ + if ( !nMasterSlotId || nMasterSlotId == USHRT_MAX ) + ((SfxSlot*) this) -> nMasterSlotId = rPool.GetWhich(nSlotId); + return nMasterSlotId; +} + + diff --git a/sfx2/source/control/msgpool.cxx b/sfx2/source/control/msgpool.cxx new file mode 100644 index 000000000000..6e98f8e9e074 --- /dev/null +++ b/sfx2/source/control/msgpool.cxx @@ -0,0 +1,627 @@ +/************************************************************************* + * + * $RCSfile: msgpool.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _STREAM_HXX //autogen +#include <tools/stream.hxx> +#endif +#ifndef _RSCSFX_HXX //autogen +#include <rsc/rscsfx.hxx> +#endif +#pragma hdrstop + +#include "msgpool.hxx" +#include "minarray.hxx" +#include "msg.hxx" +#include "app.hxx" +#include "objface.hxx" +#include "idpool.hxx" +#include "sfxtypes.hxx" +#include "slotinfo.hxx" +#include "macrconf.hxx" +#include "sfxresid.hxx" +#include "arrdecl.hxx" + +#include "sfx.hrc" + +//==================================================================== + +struct SfxSIDRegistration_Impl +{ + String _aGroup; + String _aName; + USHORT _nSID; +}; + +struct SfxSlotType_Impl +{ + USHORT nId; + TypeId nType; + + SfxSlotType_Impl( USHORT nTheId, TypeId nTheType ): + nId(nTheId), nType(nTheType) + {} +}; + +DECL_2BYTEARRAY(SfxSlotGroupArr_Impl, USHORT, 6, 4); +DECL_PTRARRAY(SfxInterfaceArr_Impl, SfxInterface*, 6, 3); +DECL_PTRARRAY(SfxSlotTypeArr_Impl, SfxSlotType_Impl*, 8, 8); + + +//==================================================================== + +SfxSlotPool::SfxSlotPool( SfxSlotPool *pParent, ResMgr* pResManager ) + : _pParentPool( pParent ) + , _pIdPool(0) + , _pTypes(0) + , _pGroups(0) + , _nCurGroup(0) + , _pInterfaces(0) + , _nCurInterface(0) + , _nCurMsg(0) + , _pResMgr( pResManager ) + , _pUnoSlots( 0 ) +{ + if ( !_pResMgr ) + _pResMgr = Resource::GetResManager(); +} + +//==================================================================== + +SfxSlotPool::~SfxSlotPool() +{ + _pParentPool = 0; + for ( SfxInterface *pIF = FirstInterface(); pIF; pIF = FirstInterface() ) + delete pIF; + delete _pInterfaces; + delete _pGroups; + delete _pUnoSlots; + if ( _pTypes ) + { + for ( USHORT n =_pTypes->Count(); n--; ) + delete _pTypes->GetObject(n); + delete _pTypes; + } + delete _pIdPool; +} + +//==================================================================== + +// registers the availability of the Interface of functions + +void SfxSlotPool::RegisterInterface( SfxInterface& rInterface ) +{ + DBG_MEMTEST(); + + // add to the list of SfxObjectInterface instances + if ( _pInterfaces == 0 ) + _pInterfaces = new SfxInterfaceArr_Impl; + _pInterfaces->Append(&rInterface); + + // bei einem (einzelnen) Null-Slot abbrechen (aus syntaktischen Gr"unden + // enthalten interfaces immer mindestens einen Slot) + if ( rInterface.Count() == 1 && !rInterface[0]->nSlotId ) + return; + + // possibly add Interface-id and group-ids of funcs to the list of groups + if ( !_pGroups ) + { + _pGroups = new SfxSlotGroupArr_Impl; + + if ( _pParentPool ) + { + // Die Groups im parent Slotpool sind auch hier bekannt + SfxSlotGroupArr_Impl& rGroups = *_pParentPool->_pGroups; + for ( USHORT n=0; n<rGroups.Count(); n++ ) + _pGroups->Append( rGroups[n] ); + } + } + + if ( !_pTypes ) + _pTypes = new SfxSlotTypeArr_Impl; + for ( USHORT nFunc = 0; nFunc < rInterface.Count(); ++nFunc ) + { + SfxSlot *pDef = rInterface[nFunc]; + if ( pDef->GetUnoName() ) + { + if ( !_pUnoSlots ) + _pUnoSlots = new SfxSlotArr_Impl; + _pUnoSlots->Insert( pDef, _pUnoSlots->Count() ); + } + + if ( pDef->GetGroupId() && /* pDef->GetGroupId() != GID_INTERN && */ + !_pGroups->Contains(pDef->GetGroupId()) ) + { + if (pDef->GetGroupId() == GID_INTERN) + _pGroups->Insert(0, pDef->GetGroupId()); + else + _pGroups->Append(pDef->GetGroupId()); + } + + const TypeId &rTypeId = pDef->GetType()->Type(); + if ( rTypeId != TYPE(SfxVoidItem) && rTypeId != 0 ) + { + USHORT nPos; + for ( nPos = 0; nPos < _pTypes->Count(); ++nPos ) + { + if ( _pTypes->GetObject(nPos)->nId == pDef->GetSlotId() ) + { + DBG_ASSERT( rTypeId == _pTypes->GetObject(nPos)->nType, + "same slot id with unequal item types" ); + } + else if ( _pTypes->GetObject(nPos)->nId > pDef->GetSlotId() ) + break; + } + if ( nPos >= _pTypes->Count() || + _pTypes->GetObject(nPos)->nId > pDef->GetSlotId() ) + _pTypes->Append( new SfxSlotType_Impl( pDef->GetSlotId(), rTypeId ) ); + } + } +} + +//==================================================================== + +TypeId SfxSlotPool::GetSlotType( USHORT nId ) const +{ + for ( USHORT nPos = 0; nPos < _pTypes->Count(); ++nPos ) + { + if ( _pTypes->GetObject(nPos)->nId == nId ) + return _pTypes->GetObject(nPos)->nType; + } + return _pParentPool ? _pParentPool->GetSlotType( nId ) : 0; +} + +//==================================================================== + +// unregisters the availability of the Interface of functions + +void SfxSlotPool::ReleaseInterface( SfxInterface& rInterface ) +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces, "releasing SfxInterface, but there are none" ); + // remove from the list of SfxInterface instances + _pInterfaces->Remove(&rInterface); +} + +//-------------------------------------------------------------------- + +// get the first SfxMessage for a special Id (e.g. for getting check-mode) + +const SfxSlot* SfxSlotPool::GetSlot( USHORT nId ) +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces != 0, "no Interfaces registered" ); + + // Zun"achst die eigenen Interfaces absuchen + for ( USHORT nInterf = 0; nInterf < _pInterfaces->Count(); ++nInterf ) + { + const SfxSlot *pDef = + _pInterfaces->GetObject(nInterf)->GetSlot(nId); + if ( pDef ) + return pDef; + } + + // Dann beim eventuell vorhandenen parent versuchen + return _pParentPool ? _pParentPool->GetSlot( nId ) : 0; +} + +//-------------------------------------------------------------------- + +// returns the pool of unused ids for macros, menus etc. + +IdPool& SfxSlotPool::GetIdPool() +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces != 0 && _pInterfaces->Count(), + "no Interfaces registered" ); + + if ( !_pIdPool ) + { + _pIdPool = new IdPool(); + + // create a set of all registered function-ids + BitSet aRegIds; + for ( USHORT nInterface = 0; nInterface < _pInterfaces->Count(); ++nInterface ) + { + SfxInterface* pInterface = (*_pInterfaces)[nInterface]; + for ( USHORT nFunc = 0; nFunc < pInterface->Count(); ++nFunc ) + aRegIds |= (*pInterface)[nFunc]->GetGroupId(); + } + + //lock all registered ids + _pIdPool->Lock(aRegIds); + } + + return *_pIdPool; +} + + +//-------------------------------------------------------------------- + +// stores the id persistent to a stream (expand macros-names) + +void SfxSlotPool::StoreId( SvStream& rStream, USHORT nId ) +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces != 0, "no Interfaces registered" ); + + rStream << nId; + //! later: write 0 and macro-lib/name +} + + +//-------------------------------------------------------------------- + +// load a persistent id from a stream (assign id if a macro) + +void SfxSlotPool::LoadId( SvStream& rStream, USHORT &rId ) +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces != 0, "no Interfaces registered" ); + + rStream >> (unsigned short&) rId; +} + + +//-------------------------------------------------------------------- + +// skips to the next group + +String SfxSlotPool::SeekGroup( USHORT nNo ) +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces != 0, "no Interfaces registered" ); + + // if the group exists, use it + if ( _pGroups && nNo < _pGroups->Count() ) + { + _nCurGroup = nNo; + if ( _pParentPool ) + { + // Meistens stimmt die Reihenfolge der Ids "uberein + USHORT nParentCount = _pParentPool->_pGroups->Count(); + if ( nNo < nParentCount && (*_pGroups)[nNo] == (*_pParentPool->_pGroups)[nNo] ) + _pParentPool->_nCurGroup = nNo; + else + { + // Ansonsten mu\s gesucht werden + // Wenn die Gruppe im parent pool nicht gefunden wird, wird + // _nCurGroup au\serhalb des g"ultigen Bereiches gesetzt + USHORT i; + for ( i=1; i<nParentCount; i++ ) + if ( (*_pGroups)[nNo] == (*_pParentPool->_pGroups)[i] ) + break; + _pParentPool->_nCurGroup = i; + } + } + + SfxResId aResId( (*_pGroups)[_nCurGroup] ); + aResId.SetRT(RSC_STRING); + if ( !aResId.GetResMgr()->IsAvailable(aResId) ) + { + DBG_ERROR( "GroupId-Name nicht im SFX definiert!" ); + return String(); + } + + return String( aResId ); + } + + return String(); +} + + +//-------------------------------------------------------------------- + +USHORT SfxSlotPool::GetGroupCount() +{ + return _pGroups->Count(); +} + + +//-------------------------------------------------------------------- + +// internal search loop + +const SfxSlot* SfxSlotPool::SeekSlot( USHORT nStartInterface ) +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces != 0, "no Interfaces registered" ); + + // Die Numerierung der interfaces startet beim parent pool + USHORT nFirstInterface = _pParentPool ? _pParentPool->_pInterfaces->Count() : 0; + + // sind wir am Ende des Parent-Pools angekommen? + if ( nStartInterface < nFirstInterface && + _pParentPool->_nCurGroup >= _pParentPool->_pGroups->Count() ) + nStartInterface = nFirstInterface; + + // liegt das Interface noch im Parent-Pool? + if ( nStartInterface < nFirstInterface ) + { + DBG_ASSERT( _pParentPool, "Kein parent pool!" ); + _nCurInterface = nStartInterface; + return _pParentPool->SeekSlot( nStartInterface ); + } + + // find the first func-def with the current group id + USHORT nCount = _pInterfaces->Count() + nFirstInterface; + for ( _nCurInterface = nStartInterface; + _nCurInterface < nCount; + ++_nCurInterface ) + { + SfxInterface* pInterface = (*_pInterfaces)[_nCurInterface-nFirstInterface]; + for ( _nCurMsg = 0; + _nCurMsg < pInterface->Count(); + ++_nCurMsg ) + { + const SfxSlot* pMsg = (*pInterface)[_nCurMsg]; + if ( pMsg->GetGroupId() == _pGroups->GetObject(_nCurGroup) ) + return pMsg; + } + } + + return 0; +} + +//-------------------------------------------------------------------- + +// skips to the next func in the current group + +const SfxSlot* SfxSlotPool::NextSlot() +{ + DBG_MEMTEST(); + DBG_ASSERT( _pInterfaces != 0, "no Interfaces registered" ); + + // Die Numerierung der interfaces startet beim parent pool + USHORT nFirstInterface = _pParentPool ? _pParentPool->_pInterfaces->Count() : 0; + + if ( _nCurInterface < nFirstInterface && _nCurGroup >= _pParentPool->_pGroups->Count() ) + _nCurInterface = nFirstInterface; + + if ( _nCurInterface < nFirstInterface ) + { + DBG_ASSERT( _pParentPool, "Kein parent pool!" ); + const SfxSlot *pSlot = _pParentPool->NextSlot(); + _nCurInterface = _pParentPool->_nCurInterface; + if ( pSlot ) + return pSlot; + if ( _nCurInterface == nFirstInterface ) + // parent pool ist fertig + return SeekSlot( nFirstInterface ); + } + + USHORT nInterface = _nCurInterface - nFirstInterface; + // possibly we are already at the end + if ( nInterface >= _pInterfaces->Count() ) + return 0; + + // look for further matching func-defs within the same Interface + SfxInterface* pInterface = (*_pInterfaces)[nInterface]; + while ( ++_nCurMsg < pInterface->Count() ) + { + SfxSlot* pMsg = (*pInterface)[_nCurMsg]; + if ( pMsg->GetGroupId() == _pGroups->GetObject(_nCurGroup) ) + return pMsg; + } + + return SeekSlot(++_nCurInterface ); +} + + +//-------------------------------------------------------------------- + +// SlotName erfragen, gfs. mit HilfeText + +String SfxSlotPool::GetSlotName_Impl(USHORT nId, String *pHelpText) const +{ + // ist es eine Makro-SlotId? + if ( SfxMacroConfig::IsMacroSlot( nId ) ) + { + const SfxMacroInfo *pMacro = SFX_APP()->GetMacroConfig()->GetMacroInfo(nId); + if ( pMacro ) + return pMacro->GetMacroName(); + else + return String(); + } + + // Zun"achst den eigenen ResManager testen, dann evtl. den des parent pools + ResId aResId( nId, _pResMgr ); + aResId.SetRT( RSC_SFX_SLOT_INFO ); + if( !Resource::GetResManager()->IsAvailable( aResId ) && _pParentPool ) + aResId.SetResMgr( _pParentPool->_pResMgr ); + if( Resource::GetResManager()->IsAvailable( aResId ) ) + { + SfxSlotInfo aInfo(aResId); + if(pHelpText) + *pHelpText = aInfo.GetHelpText(); + return aInfo.GetName(); + } + +#ifdef DBG_UTIL + String aError(DEFINE_CONST_UNICODE("Slot ohne ConfigName: ")); + aError += String::CreateFromInt32( nId ); +// DBG_ERROR( aError ); + return aError; +#endif + return String(); +} + + +//-------------------------------------------------------------------- + +// SlotName erfragen, gfs. mit HilfeText + +String SfxSlotPool::GetSlotHelpText_Impl(USHORT nId) const +{ + String aHelpText; + GetSlotName_Impl( nId, &aHelpText ); + return aHelpText; +} + +//-------------------------------------------------------------------- +#ifdef STARBASIC + + +// assignes a request-id for a specific macro + +USHORT SfxSlotPool::RegisterMacro( sbToken aToken ) +{ + DBG_MEMTEST(); + DBG_ASSERT( pInterfaces != 0, "no Interfaces registered" ); + DBG_ASSERT( TRUE, "not implemented - call MI" ); + return 0; +} + + +//-------------------------------------------------------------------- + +// frees the request-id of a specific macro + +void SfxSlotPool::ReleaseMacro( sbToken aToken ) +{ + DBG_MEMTEST(); + DBG_ASSERT( pInterfaces != 0, "no Interfaces registered" ); + DBG_ASSERT( TRUE, "not implemented - call MI" ); +} + +#endif + +//-------------------------------------------------------------------- + +SfxInterface* SfxSlotPool::FirstInterface() +{ + _nCurInterface = 0; + if ( !_pInterfaces || !_pInterfaces->Count() ) + return 0; + return _pParentPool ? _pParentPool->FirstInterface() : (*_pInterfaces)[0]; +} + + +//-------------------------------------------------------------------- + +SfxInterface* SfxSlotPool::NextInterface() +{ + _nCurInterface++; + USHORT nFirstInterface = _pParentPool ? _pParentPool->_pInterfaces->Count() : 0; + if ( _nCurInterface < nFirstInterface ) + return (*_pParentPool->_pInterfaces)[_nCurInterface]; + USHORT nInterface = _nCurInterface - nFirstInterface; + return nInterface < _pInterfaces->Count() ? (*_pInterfaces)[nInterface] : 0; +} + +//-------------------------------------------------------------------- + +USHORT SfxSlotPool::RegisterSID( const String &rGroup, const String &rName ) +{ + return 0; +} + +//-------------------------------------------------------------------- + +void SfxSlotPool::ReleaseSID( const String &rGroup, const String &rName ) +{ +} + +const SfxSlot* SfxSlotPool::GetUnoSlot( USHORT nId ) +{ + const SfxSlot *pSlot = NULL; + if ( _pParentPool ) + pSlot = _pParentPool->GetUnoSlot( nId ); + + if ( !pSlot && _pUnoSlots ) + { + USHORT nCount = _pUnoSlots->Count(); + for ( USHORT n=0; n<nCount; n++ ) + { + if ( (*_pUnoSlots)[n]->GetSlotId() == nId ) + { + pSlot = (*_pUnoSlots)[n]; + break; + } + } + } + + return pSlot; +} + +const SfxSlot* SfxSlotPool::GetUnoSlot( const String& rName ) +{ + const SfxSlot *pSlot = NULL; + if ( _pParentPool ) + pSlot = _pParentPool->GetUnoSlot( rName ); + + if ( !pSlot && _pUnoSlots ) + { + USHORT nCount = _pUnoSlots->Count(); + for ( USHORT n=0; n<nCount; n++ ) + { + if ( rName.EqualsAscii((*_pUnoSlots)[n]->GetUnoName()) ) + { + pSlot = (*_pUnoSlots)[n]; + break; + } + } + } + + return pSlot; +} + + + diff --git a/sfx2/source/control/objface.cxx b/sfx2/source/control/objface.cxx new file mode 100644 index 000000000000..15b8d55a2753 --- /dev/null +++ b/sfx2/source/control/objface.cxx @@ -0,0 +1,1427 @@ +/************************************************************************* + * + * $RCSfile: objface.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <stdlib.h> + +#ifndef _TOOLS_RCID_H +#include <tools/rcid.h> +#endif +#pragma hdrstop + +#ifndef _STREAM_HXX //autogen +#include <tools/stream.hxx> +#endif + +#include "module.hxx" +#include "objface.hxx" +#include "msg.hxx" +#include "msgpool.hxx" +#include "cfgitem.hxx" +#include "sfxresid.hxx" +#include "minarray.hxx" +#include "cfgmgr.hxx" +#include "tbxmgr.hxx" +#ifdef _PROXYSHELL_VERWENDEN +#include "bindings.hxx" // fuer ProxyInterface +#include "dispatch.hxx" // fuer ProxyInterface +#endif + +DBG_NAME(SfxInterface); + +static const USHORT nVersion = 5; + +//==================================================================== + +EXTERN_C +#if defined( PM2 ) && (!defined( CSET ) && !defined ( MTW ) && !defined( WTC )) +int _stdcall +#else +#ifdef WNT +int _cdecl +#else +int +#endif +#endif + +SfxCompareSlots_Impl( const void* pSmaller, const void* pBigger ) +{ + DBG_MEMTEST(); + return ( (int) ((SfxSlot*)pSmaller)->GetSlotId() ) - + ( (int) ((SfxSlot*)pBigger)->GetSlotId() ); +} + +//========================================================================= + +struct SfxObjectUI_Impl +{ + USHORT nPos; + USHORT nInterfaceId; + ResId aResId; + BOOL bVisible; + BOOL bContext; + String* pName; + ULONG nFeature; + + SfxObjectUI_Impl(USHORT n, const ResId& rResId, BOOL bVis, ULONG nFeat, + USHORT nClassId=0xFFFF) : + nPos(n), + aResId(rResId.GetId(), rResId.GetResMgr()), + nInterfaceId(nClassId), + bVisible(bVis), + pName(0), + bContext(FALSE), + nFeature(nFeat) + { + aResId.SetRT(rResId.GetRT()); + } + + ~SfxObjectUI_Impl() + { + delete pName; + } +}; + +DECL_PTRARRAY(SfxObjectUIArr_Impl, SfxObjectUI_Impl*, 2, 2); + +struct SfxInterface_Impl +{ + SfxObjectUIArr_Impl* pObjectBars; // registered ObjectBars + SfxObjectUIArr_Impl* pObjectMenues; // registered ObjectMenues + SfxObjectUIArr_Impl* pChildWindows; // registered ChildWindows + ResId aPopupRes; // registered PopupMenu + ResId aStatBarRes; // registered StatusBar + SfxModule* pModule; + + SfxInterface_Impl() : + aPopupRes((USHORT)0), + aStatBarRes((USHORT)0) + { + pObjectBars = new SfxObjectUIArr_Impl; + pObjectMenues = new SfxObjectUIArr_Impl; + pChildWindows = new SfxObjectUIArr_Impl; + } + + ~SfxInterface_Impl() + { + USHORT n; + for (n=0; n<pObjectBars->Count(); n++) + delete (*pObjectBars)[n]; + delete pObjectBars; + + for (n=0; n<pObjectMenues->Count(); n++) + delete (*pObjectMenues)[n]; + delete pObjectMenues; + + for (n=0; n<pChildWindows->Count(); n++) + delete (*pChildWindows)[n]; + delete pChildWindows; + } +}; + +//==================================================================== + +class SfxIFConfig_Impl : public SfxConfigItem +{ +friend class SfxInterface; + USHORT nCount; + SfxInterface* pIFace; + SfxObjectUIArr_Impl* pObjectBars; + +public: + SfxIFConfig_Impl(USHORT nClassId, SfxInterface *pIF); + virtual ~SfxIFConfig_Impl(); + virtual int Load(SvStream&); + virtual BOOL Store(SvStream&); + virtual String GetName() const + { if (pIFace->HasName()) return pIFace->GetName(); + else return String(); } + virtual void UseDefault(); + void SaveDefaults(USHORT); +}; + +//------------------------------------------------------------------------- + +SfxIFConfig_Impl::SfxIFConfig_Impl(USHORT nClassId, SfxInterface *pIF) : + SfxConfigItem(SFX_ITEMTYPE_INTERFACE_START + nClassId), + nCount(0), + pObjectBars(0), + pIFace(pIF) +{ + SetInternal(TRUE); +} + +//------------------------------------------------------------------------- + +void SfxIFConfig_Impl::SaveDefaults(USHORT nClassId) +{ + if ( pObjectBars ) + return; + + pObjectBars = new SfxObjectUIArr_Impl; + + for (nCount=0; nCount < pIFace->pImpData->pObjectBars->Count(); nCount++) + { + SfxObjectUI_Impl* pUI = new SfxObjectUI_Impl( + pIFace->GetObjectBarPos(nCount), + pIFace->GetObjectBarResId(nCount), + pIFace->IsObjectBarVisible(nCount), + pIFace->GetObjectBarFeature(nCount), + nClassId); + + pObjectBars->Append(pUI); + pUI->pName = new String(*pIFace->GetObjectBarName(nCount)); + } +} + +//------------------------------------------------------------------------- + +SfxIFConfig_Impl::~SfxIFConfig_Impl() +{ + if( pObjectBars ) + { + for (USHORT n=0; n<pObjectBars->Count(); n++) + delete (*pObjectBars)[n]; + delete pObjectBars; + } +} + +//------------------------------------------------------------------------- + +int SfxIFConfig_Impl::Load(SvStream& rStream) +{ + for ( ;pIFace->pImpData->pObjectBars->Count(); ) + pIFace->ReleaseObjectBar(pIFace->GetObjectBarResId(0).GetId()); + + USHORT n; + rStream >> n; + + if ( n != nVersion) + return SfxConfigItem::WARNING_VERSION; + + rStream >> n; + for (USHORT i=0; i<n; i++) + { + pIFace->LoadObjectBar(i, rStream); + } + + return SfxConfigItem::ERR_OK; +} + +//------------------------------------------------------------------------- + +BOOL SfxIFConfig_Impl::Store(SvStream& rStream) +{ + rStream << nVersion; + + rStream << pIFace->pImpData->pObjectBars->Count(); + USHORT nIFaceId = GetType() - SFX_ITEMTYPE_INTERFACE_START; + + for (USHORT i=0; i<pIFace->pImpData->pObjectBars->Count(); i++) + { + pIFace->StoreObjectBar(i, rStream); + } + + return TRUE; +} + +//------------------------------------------------------------------------- + +void SfxIFConfig_Impl::UseDefault() +{ + pIFace->UseDefault(); +} + +//==================================================================== +// ctor, registeres a new unit + +SfxInterface::SfxInterface( SfxModule *pMod, + const char *pClassName, + const ResId& rNameResId, + USHORT nId, + const SfxInterface* pParent, + const SfxTypeLibImpl* pLibInfo ): + pName(pClassName), + nClassId(nId), + aNameResId(rNameResId.GetId()), + pGenoType(pParent), + pTypeLibInfo(pLibInfo), + pConfig(NULL), + pImpData(0), + nCount(0) +{ + aNameResId.SetResMgr(rNameResId.GetResMgr()); + Init( ); + pImpData->pModule = pMod; +} + +SfxInterface::SfxInterface( SfxModule *pMod, + const char *pClassName, + const ResId& rNameResId, + USHORT nId, + const SfxInterface* pParent, + const SfxTypeLibImpl* pLibInfo, + SfxSlot &rSlotMap, USHORT nSlotCount ): + pName(pClassName), + nClassId(nId), + aNameResId(rNameResId.GetId()), + pGenoType(pParent), + pTypeLibInfo(pLibInfo), + pConfig(NULL), + pImpData(0) +{ + aNameResId.SetResMgr(rNameResId.GetResMgr()); + Init(); + pImpData->pModule = pMod; + SetSlotMap( rSlotMap, nSlotCount ); + // register the functions at the SfxMessagePool + if ( pMod ) + pMod->GetSlotPool()->RegisterInterface(*this); + else + SFX_APP()->GetAppSlotPool_Impl().RegisterInterface(*this); +} + +void SfxInterface::Init() +{ + DBG_MEMTEST(); + DBG_CTOR(SfxInterface, 0); +// DBG_ASSERT(nCount, "Anzahl der Slot == NULL"); + + if ( nClassId ) + pConfig = new SfxIFConfig_Impl(nClassId, this); + pImpData = new SfxInterface_Impl; +} + + +void SfxInterface::SetSlotMap( SfxSlot& rSlotMap, USHORT nSlotCount ) +{ + pSlots = &rSlotMap; + nCount = nSlotCount; + SfxSlot* pIter = pSlots; + if ( 1 == nCount && !pIter->pNextSlot ) + pIter->pNextSlot = pIter; + + if ( !pIter->pNextSlot ) + { + // sort the SfxSlots by id + qsort( pSlots, nCount, sizeof(SfxSlot), SfxCompareSlots_Impl ); + + // link masters and slaves + USHORT nIter = 1; + for ( pIter = pSlots; nIter <= nCount; ++pIter, ++nIter ) + { + //! hier bitte sinnvoll pruefen + //! DBG_ASSERT(!(pIter->IsMode(SFX_SLOT_CACHABLE) && + //! pIter->IsMode(SFX_SLOT_VOLATILE)), + //! "invalid Flags" ); + DBG_ASSERT( nIter == nCount || + pIter->GetSlotId() != (pIter+1)->GetSlotId(), + "doppelte SID" ); + + // jeder Master verweist auf seinen ersten Slave (ENUM), alle + // Slaves auf ihren Master. + // Slaves verweisen im Ring auf die anderen mit gleichem Master + if ( pIter->GetKind() == SFX_KIND_ENUM ) + { + pIter->pLinkedSlot = GetSlot( pIter->nMasterSlotId ); + DBG_ASSERT( pIter->pLinkedSlot, "slave without master" ); + if ( !pIter->pLinkedSlot->pLinkedSlot ) + ( (SfxSlot*) pIter->pLinkedSlot)->pLinkedSlot = pIter; + + if ( 0 == pIter->GetNextSlot() ) + { + SfxSlot *pLastSlot = pIter; + for ( USHORT n = nIter; n < Count(); ++n ) + { + SfxSlot *pCurSlot = (pSlots+n); + if ( pCurSlot->nMasterSlotId == pIter->nMasterSlotId ) + { + pLastSlot->pNextSlot = pCurSlot; + pLastSlot = pCurSlot; + } + } + pLastSlot->pNextSlot = pIter; + } + } + else if ( 0 == pIter->GetNextSlot() ) + { + // Slots verweisen im Ring auf den n"achten mit derselben Statusmethode + SfxSlot *pLastSlot = pIter; + for ( USHORT n = nIter; n < Count(); ++n ) + { + SfxSlot *pCurSlot = (pSlots+n); + if ( pCurSlot->GetStateFnc() == pIter->GetStateFnc() ) + { + pLastSlot->pNextSlot = pCurSlot; + pLastSlot = pCurSlot; + } + } + pLastSlot->pNextSlot = pIter; + } + } + } +#ifdef DBG_UTIL + else + { + USHORT nIter = 1; + for ( SfxSlot *pNext = pIter+1; nIter < nCount; ++pNext, ++nIter ) + { + + if ( pNext->GetSlotId() <= pIter->GetSlotId() ) + DBG_ERROR ("Falsche Reihenfolge!"); + + if ( pIter->GetKind() == SFX_KIND_ENUM ) + { + const SfxSlot *pMasterSlot = GetSlot(pIter->nMasterSlotId); + const SfxSlot *pFirstSlave = pMasterSlot->pLinkedSlot; + const SfxSlot *pSlave = pFirstSlave; + do + { + if ( pSlave->pLinkedSlot != pMasterSlot ) + { + ByteString aStr("Falsche Master/Slave-Verkettung : "); + aStr += ByteString::CreateFromInt32(pMasterSlot->GetSlotId()); + aStr += " , "; + aStr += ByteString::CreateFromInt32(pSlave->GetSlotId()); + DBG_ERROR(aStr.GetBuffer()); + } + + if ( pSlave->nMasterSlotId != pMasterSlot->GetSlotId() ) + { + ByteString aStr("Falsche Master/Slave-Ids : "); + aStr += ByteString::CreateFromInt32(pMasterSlot->GetSlotId()); + aStr += " , "; + aStr += ByteString::CreateFromInt32(pSlave->GetSlotId()); + DBG_ERROR(aStr.GetBuffer()); + } + + pSlave = pSlave->pNextSlot; + } + while ( pSlave != pFirstSlave ); + } + else + { + if ( pIter->pLinkedSlot ) + { + if ( pIter->pLinkedSlot->GetKind() != SFX_KIND_ENUM ) + { + ByteString aStr("Slave ist kein enum : "); + aStr += ByteString::CreateFromInt32(pIter->GetSlotId()); + aStr += " , "; + aStr += ByteString::CreateFromInt32(pIter->pLinkedSlot->GetSlotId()); + DBG_ERROR(aStr.GetBuffer()); + } + } + + const SfxSlot *pLastSlot = pIter; + const SfxSlot *pCurSlot = pIter; + do + { + pCurSlot = pCurSlot->pNextSlot; + if ( pCurSlot->GetStateFnc() != pIter->GetStateFnc() ) + { + ByteString aStr("Verkettete Slots mit verschiedenen StateMethods : "); + aStr += ByteString::CreateFromInt32(pCurSlot->GetSlotId()); + aStr += " , "; + aStr += ByteString::CreateFromInt32(pIter->GetSlotId()); + DBG_ERROR(aStr.GetBuffer()); + } + } + while ( pCurSlot != pIter ); + } + + pIter = pNext; + } + } +#endif +} + + +//-------------------------------------------------------------------- + + + +SfxInterface::~SfxInterface() +{ + if (pConfig) + delete pConfig; + + SfxModule *pMod = pImpData->pModule; + delete pImpData; + if ( nClassId ) + { + if ( pMod ) + pMod->GetSlotPool()->ReleaseInterface(*this); + else + SFX_APP()->GetAppSlotPool_Impl().ReleaseInterface(*this); + } +} + +//-------------------------------------------------------------------- + +// searches for the specified func + + +const SfxSlot* SfxInterface::GetSlot( USHORT nFuncId ) const +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxInterface, 0); + DBG_ASSERT( this && pSlots && nCount, "" ); + + // find the id using binary search + void* p = bsearch( &nFuncId, pSlots, nCount, sizeof(SfxSlot), + SfxCompareSlots_Impl ); + if ( !p && pGenoType ) + return pGenoType->GetSlot( nFuncId ); + + return p ? (const SfxSlot*)p : 0; +} + +const SfxSlot* SfxInterface::GetSlot( const String& rCommand ) const +{ + SfxSlotPool& rPool = SFX_SLOTPOOL(); + for ( USHORT n=0; n<nCount; n++ ) + { + USHORT nId = (pSlots+n)->GetSlotId(); + if ( rCommand.CompareIgnoreCaseToAscii( rPool.GetSlotName_Impl( nId ) ) == COMPARE_EQUAL ) + return pSlots+n; + } + + return pGenoType ? pGenoType->GetSlot( rCommand ) : NULL; +} + +//-------------------------------------------------------------------- + + +const SfxSlot* SfxInterface::GetRealSlot( const SfxSlot *pSlot ) const +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxInterface, 0); + DBG_ASSERT( this && pSlots && nCount, "" ); + + if ( !ContainsSlot_Impl(pSlot) ) + { + if(pGenoType) + return pGenoType->GetRealSlot(pSlot); + DBG_ERROR("fremder Slot"); + return 0; + } + + return pSlot->pLinkedSlot; +} + +//-------------------------------------------------------------------- + + +const SfxSlot* SfxInterface::GetRealSlot( USHORT nSlotId ) const +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxInterface, 0); + DBG_ASSERT( this && pSlots && nCount, "" ); + + const SfxSlot *pSlot = GetSlot(nSlotId); + if ( !pSlot ) + { + if(pGenoType) + return pGenoType->GetRealSlot(nSlotId); + DBG_ERROR("fremder Slot"); + return 0; + } + + return pSlot->pLinkedSlot; +} + +//-------------------------------------------------------------------- + + +void SfxInterface::RegisterPopupMenu( const ResId& rResId ) +{ + DBG_CHKTHIS(SfxInterface, 0); + pImpData->aPopupRes = rResId; +} + +//-------------------------------------------------------------------- + + +void SfxInterface::LoadConfig() +{ + if ( pConfig ) + { + pConfig->SaveDefaults(nClassId); + + // Wenn die Application schon l"auft, wurde das Interface nachtr"aglich + // erzeugt und mu\s daher explizit initialisiert werden. + if ( Application::IsInExecute() ) + pConfig->Initialize(); + } +} + + +BOOL SfxInterface::IsDefault() +{ + if (pConfig) + return pConfig->IsDefault(); + else + return TRUE; +} + + +void SfxInterface::UseDefault() +{ + if ( !pConfig ) + { + for (USHORT n=0; n<pImpData->pObjectBars->Count(); n++) + delete (*pImpData->pObjectBars)[n]; + pImpData->pObjectBars->Remove(0, pImpData->pObjectBars->Count()); + return; + } + else if ( !pConfig->IsDefault() ) + { + USHORT n; + for (n=0; n<pImpData->pObjectBars->Count(); n++) + delete (*pImpData->pObjectBars)[n]; + pImpData->pObjectBars->Remove(0, pImpData->pObjectBars->Count()); + + for (n=0; n<pConfig->nCount; n++) + { + SfxObjectUI_Impl* pUI = new SfxObjectUI_Impl( + (*pConfig->pObjectBars)[n]->nPos, + (*pConfig->pObjectBars)[n]->aResId, + (*pConfig->pObjectBars)[n]->bVisible, + (*pConfig->pObjectBars)[n]->nFeature, + nClassId); + + pImpData->pObjectBars->Append(pUI); + pUI->pName = new String(*((*pConfig->pObjectBars)[n]->pName)); + } + } +} + +//-------------------------------------------------------------------- + + +void SfxInterface::SetObjectBarName(const String& rName, USHORT nId) +{ + // Objectbar im eigenen Array suchen + USHORT nCount = pImpData->pObjectBars->Count(); + USHORT n; + for ( n=0; n<nCount; n++ ) + if ((*pImpData->pObjectBars)[n]->aResId.GetId() == nId) break; + + if ( n >= nCount ) + { + // Nicht gefunden, in der Superklasse versuchen + BOOL bGenoType = ( pGenoType != 0 && !pGenoType->HasName() ); + if (bGenoType) + ((SfxInterface*)pGenoType)->SetObjectBarName ( rName, nId ); + else + DBG_ERROR("Objectbar ist unbekannt!"); + } + else + { + SfxObjectUI_Impl *pUI = (*pImpData->pObjectBars)[n]; + delete pUI->pName; + pUI->pName = new String( rName ); + if ( pConfig ) + pConfig->SetDefault(FALSE); + } +} + + +void SfxInterface::SetObjectBarPos(USHORT nPos, USHORT nId) +{ + // Objectbar im eigenen Array suchen + USHORT nCount = pImpData->pObjectBars->Count(); + USHORT n; + for ( n=0; n<nCount; n++ ) + if ((*pImpData->pObjectBars)[n]->aResId.GetId() == nId) break; + + if ( n >= nCount ) + { + // Nicht gefunden, in der Superklasse versuchen + BOOL bGenoType = ( pGenoType != 0 && !pGenoType->HasName() ); + if (bGenoType) + ((SfxInterface*)pGenoType)->SetObjectBarPos ( nPos, nId ); + else + DBG_ERROR("Objectbar ist unbekannt!"); + } + else + { + (*pImpData->pObjectBars)[n]->nPos = nPos; + if (pConfig) + pConfig->SetDefault(FALSE); + } +} + +//------------------------------------------------------------------------- + +void SfxInterface::RegisterObjectBar( USHORT nPos, const ResId& rResId, + const String *pStr ) +{ + RegisterObjectBar( nPos, rResId, 0UL, pStr ); +} + + +void SfxInterface::RegisterObjectBar( USHORT nPos, const ResId& rResId, + ULONG nFeature, const String *pStr ) +{ + if ((nPos & SFX_VISIBILITY_MASK) == 0) + { + if ((nPos & SFX_POSITION_MASK) == 0 ) + nPos |= SFX_VISIBILITY_CLIENT | SFX_VISIBILITY_STANDARD; + else + nPos |= (SFX_VISIBILITY_STANDARD | SFX_VISIBILITY_SERVER); + } + + // App-Leiste? + if ( SFX_OBJECTBAR_APPLICATION == ( nPos & SFX_POSITION_MASK ) ) + // je nach Desktop oder Einzelapp nur die richtige registrieren + if ( !( SFX_VISIBILITY_DESKTOP == ( nPos & SFX_VISIBILITY_DESKTOP ) ) ) + return; + nPos &= ~(USHORT)SFX_VISIBILITY_DESKTOP; + + if( nPos & SFX_VISIBILITY_SERVER ) + nPos |= SFX_VISIBILITY_PLUGSERVER; + if( nPos & SFX_VISIBILITY_CLIENT ) + nPos |= SFX_VISIBILITY_PLUGCLIENT; + + SfxObjectUI_Impl* pUI = new SfxObjectUI_Impl(nPos, rResId, TRUE, nFeature, nClassId); + + pImpData->pObjectBars->Append(pUI); + + if (pStr == 0) + { + ResId aResId(rResId); + aResId.SetRT(RSC_STRING); + aResId.SetResMgr(rResId.GetResMgr()); + if ( !Resource::GetResManager()->IsAvailable(aResId) ) + { + DBG_ERROR("Der Objectbar-Name fehlt in der Resource!"); + pUI->pName = new String (DEFINE_CONST_UNICODE("NoName")); + } + else + pUI->pName = new String(aResId); + } + else + pUI->pName = new String(*pStr); +} + + +void SfxInterface::TransferObjectBar( USHORT nPos, USHORT nId, SfxInterface *pIFace, + const String *pStr) +{ + if ( !pIFace ) + { + RegisterObjectBar( nPos, nId, pStr ); + if (pConfig) + pConfig->SetDefault(FALSE); + return; + } + + // Suche den ObjectBar im Quellen-Interface ( GenoType ?? ) + USHORT n; + for (n=0; n<pIFace->pImpData->pObjectBars->Count(); n++) + if ((*pIFace->pImpData->pObjectBars)[n]->aResId.GetId() == nId) break; + + DBG_ASSERT(n<pIFace->pImpData->pObjectBars->Count(),"Objectbar ist unbekannt!"); + + // Uebernimm ResId und Interface-Id + SfxObjectUI_Impl* pUI = new SfxObjectUI_Impl(nPos, + (*pIFace->pImpData->pObjectBars)[n]->aResId, + (*pIFace->pImpData->pObjectBars)[n]->bVisible, + (*pIFace->pImpData->pObjectBars)[n]->nFeature, + (*pIFace->pImpData->pObjectBars)[n]->nInterfaceId); + pImpData->pObjectBars->Append(pUI); + + if (pStr == 0) + { + pUI->pName = new String( *(pIFace->GetObjectBarName(n))); + } + else + pUI->pName = new String(*pStr); + + if (pConfig) + pConfig->SetDefault(FALSE); + + pIFace->ReleaseObjectBar(nId); +} + + + +void SfxInterface::ReleaseObjectBar( USHORT nId ) +{ + // Objectbar im eigenen Array suchen + USHORT nCount = pImpData->pObjectBars->Count(); + USHORT n; + for ( n=0; n<nCount; n++ ) + if ((*pImpData->pObjectBars)[n]->aResId.GetId() == nId) break; + + if ( n >= nCount ) + { + // Nicht gefunden, in der Superklasse versuchen + BOOL bGenoType = ( pGenoType != 0 && !pGenoType->HasName() ); + if (bGenoType) + ((SfxInterface*)pGenoType)->ReleaseObjectBar( nId ); + else + DBG_ERROR("Objectbar ist unbekannt!"); + } + else + { + delete (*pImpData->pObjectBars)[n]; + pImpData->pObjectBars->Remove(n); + if (pConfig) + pConfig->SetDefault(FALSE); + } +} + +//-------------------------------------------------------------------- + + +const ResId& SfxInterface::GetObjectBarResId( USHORT nNo ) const +{ + BOOL bGenoType = (pGenoType != 0 && !pGenoType->HasName()); + if ( bGenoType ) + { + // Gibt es Toolbars in der Superklasse ? + USHORT nBaseCount = pGenoType->GetObjectBarCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->GetObjectBarResId( nNo ); + else + nNo -= nBaseCount; + } + + USHORT nCount = pImpData->pObjectBars->Count(); + DBG_ASSERT( nNo<nCount,"Objectbar ist unbekannt!" ); + return (*pImpData->pObjectBars)[nNo]->aResId; +} + +//-------------------------------------------------------------------- + + +USHORT SfxInterface::GetObjectBarPos( USHORT nNo ) const +{ + BOOL bGenoType = (pGenoType != 0 && !pGenoType->HasName()); + if ( bGenoType ) + { + // Gibt es Toolbars in der Superklasse ? + USHORT nBaseCount = pGenoType->GetObjectBarCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->GetObjectBarPos( nNo ); + else + nNo -= nBaseCount; + } + + USHORT nCount = pImpData->pObjectBars->Count(); + DBG_ASSERT( nNo<nCount,"Objectbar ist unbekannt!" ); + return (*pImpData->pObjectBars)[nNo]->nPos; +} + +//-------------------------------------------------------------------- + + +USHORT SfxInterface::GetObjectBarCount() const +{ + if (pGenoType && ! pGenoType->HasName()) + return pImpData->pObjectBars->Count() + pGenoType->GetObjectBarCount(); + else + return pImpData->pObjectBars->Count(); +} + +//-------------------------------------------------------------------- + + +const ResId& SfxInterface::GetObjectMenuResId( USHORT nNo ) const +{ + DBG_ASSERT(nNo<pImpData->pObjectMenues->Count(),"ObjectMenue ist unbekannt!"); + return (*pImpData->pObjectMenues)[nNo]->aResId; +} + +//-------------------------------------------------------------------- + + +USHORT SfxInterface::GetObjectMenuPos( USHORT nNo ) const +{ + DBG_ASSERT(nNo<pImpData->pObjectMenues->Count(),"ObjectMenue ist unbekannt!"); + return (*pImpData->pObjectMenues)[nNo]->nPos; +} + +//-------------------------------------------------------------------- + + +USHORT SfxInterface::GetObjectMenuCount() const +{ + return pImpData->pObjectMenues->Count(); +} + +void SfxInterface::ClearObjectMenus() +{ + for (USHORT n = pImpData->pObjectMenues->Count(); n; ) + { + delete pImpData->pObjectMenues->GetObject( --n ); + pImpData->pObjectMenues->Remove( n ); + } +} + +void SfxInterface::RemoveObjectMenu( USHORT nPos ) +{ + for (USHORT n = pImpData->pObjectMenues->Count(); n; ) + if( pImpData->pObjectMenues->GetObject(--n)->nPos == nPos ) + { + delete pImpData->pObjectMenues->GetObject( n ); + pImpData->pObjectMenues->Remove( n ); + } +} +//-------------------------------------------------------------------- + + +void SfxInterface::RegisterObjectMenu( USHORT nPos, const ResId& rResId ) +{ + SfxObjectUI_Impl* pUI = new SfxObjectUI_Impl(nPos, rResId, TRUE, 0, nClassId); + pImpData->pObjectMenues->Append(pUI); +} + +//-------------------------------------------------------------------- + + +BOOL SfxInterface::StoreObjectBar(USHORT n, SvStream& rStream) +{ + rStream << ((*pImpData->pObjectBars)[n]->nPos) + << (*pImpData->pObjectBars)[n]->aResId.GetId() + << (*pImpData->pObjectBars)[n]->nInterfaceId + << (USHORT) (*pImpData->pObjectBars)[n]->bVisible; + rStream.WriteByteString(*(*pImpData->pObjectBars)[n]->pName); + rStream << (*pImpData->pObjectBars)[n]->nFeature; + return TRUE; +} + +//-------------------------------------------------------------------- + + +int SfxInterface::LoadObjectBar(USHORT n, SvStream& rStream) +{ + DBG_ASSERT( pConfig, "LoadObjectBar ohne Config!" ); + + USHORT nId, nPos, nIFaceId, nVisible; + ULONG nFeature; + String aName; + + rStream >> nPos >> nId >> nIFaceId >> nVisible; + rStream.ReadByteString(aName); + + if ( nVersion > 4 ) + rStream >> nFeature; + + ResId aResId(nId); + RegisterObjectBar(nPos, aResId, nFeature, &aName ); + (*pImpData->pObjectBars)[n]->nInterfaceId = nIFaceId; + (*pImpData->pObjectBars)[n]->bVisible = (BOOL) nVisible; + + SfxIFConfig_Impl *pCfg = pConfig; + + if (nIFaceId != nClassId) // pConfig von anderem Interface holen + { + SfxInterface *pIFace = + SFX_APP()->GetInterfaceByIdImpl(SfxInterfaceId(nIFaceId)); + if (pIFace) + pCfg = pIFace->pConfig; + } + + ResMgr *pResMgr=0; // falls selbstdefiniert! + if (pCfg->pObjectBars->Count()) + pResMgr = (*pCfg->pObjectBars)[0]->aResId.GetResMgr(); + + (*pImpData->pObjectBars)[n]->aResId.SetResMgr(pResMgr); + + return SfxConfigItem::ERR_OK; +} + + +void SfxInterface::RegisterChildWindow(USHORT nId, BOOL bContext, const String* pName) +{ + RegisterChildWindow( nId, bContext, 0UL, pName ); +} + +void SfxInterface::RegisterChildWindow(USHORT nId, BOOL bContext, ULONG nFeature, const String*) +{ + SfxObjectUI_Impl* pUI = new SfxObjectUI_Impl(0, nId, TRUE, nFeature, 0); + pUI->bContext = bContext; + pImpData->pChildWindows->Append(pUI); +} + +void SfxInterface::ReleaseChildWindow( USHORT nId ) +{ + USHORT nCount = pImpData->pChildWindows->Count(); + USHORT n; + for ( n=0; n<nCount; n++ ) + if ((*pImpData->pChildWindows)[n]->aResId.GetId() == nId) break; + + if ( n >= nCount ) + { + // Nicht gefunden, in der Superklasse versuchen + BOOL bGenoType = ( pGenoType != 0 && !pGenoType->HasName() ); + if (bGenoType) + ((SfxInterface*)pGenoType)->ReleaseChildWindow( nId ); + else + DBG_ERROR("ChildWindow ist unbekannt!"); + } + else + { + delete (*pImpData->pChildWindows)[n]; + pImpData->pChildWindows->Remove(n); + if (pConfig) + pConfig->SetDefault(FALSE); + } +} + +void SfxInterface::RegisterStatusBar(const ResId& rResId) +{ + pImpData->aStatBarRes = rResId; +} + + +ULONG SfxInterface::GetChildWindowId (USHORT nNo) const +{ + if ( pGenoType ) + { + // Gibt es ChildWindows in der Superklasse ? + USHORT nBaseCount = pGenoType->GetChildWindowCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->GetChildWindowId( nNo ); + else + nNo -= nBaseCount; + } + + USHORT nCount = pImpData->pChildWindows->Count(); + DBG_ASSERT( nNo<nCount,"ChildWindow ist unbekannt!" ); + ULONG nRet = (ULONG) (*pImpData->pChildWindows)[nNo]->aResId.GetId(); + if ( (*pImpData->pChildWindows)[nNo]->bContext ) + nRet += ( (ULONG) nClassId ) << 16; + return nRet; +} + +ULONG SfxInterface::GetChildWindowFeature (USHORT nNo) const +{ + if ( pGenoType ) + { + // Gibt es ChildWindows in der Superklasse ? + USHORT nBaseCount = pGenoType->GetChildWindowCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->GetChildWindowFeature( nNo ); + else + nNo -= nBaseCount; + } + + USHORT nCount = pImpData->pChildWindows->Count(); + DBG_ASSERT( nNo<nCount,"ChildWindow ist unbekannt!" ); + ULONG nRet = (ULONG) (*pImpData->pChildWindows)[nNo]->nFeature; + return nRet; +} + +//-------------------------------------------------------------------- + + +USHORT SfxInterface::GetChildWindowCount() const +{ + if (pGenoType) + return pImpData->pChildWindows->Count() + pGenoType->GetChildWindowCount(); + else + return pImpData->pChildWindows->Count(); +} + + +const ResId& SfxInterface::GetPopupMenuResId() const +{ + return pImpData->aPopupRes; +} + + +const ResId& SfxInterface::GetStatusBarResId() const +{ + if (pImpData->aStatBarRes.GetId() == 0 && pGenoType) + return pGenoType->GetStatusBarResId(); + else + return pImpData->aStatBarRes; +} + + + +const String* SfxInterface::GetObjectBarName ( USHORT nNo ) const +{ + BOOL bGenoType = (pGenoType != 0 && !pGenoType->HasName()); + if ( bGenoType ) + { + // Gibt es Toolbars in der Superklasse ? + USHORT nBaseCount = pGenoType->GetObjectBarCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->GetObjectBarName( nNo ); + else + nNo -= nBaseCount; + } + + USHORT nCount = pImpData->pObjectBars->Count(); + DBG_ASSERT( nNo<nCount,"Objectbar ist unbekannt!" ); + return (*pImpData->pObjectBars)[nNo]->pName; +} + +ULONG SfxInterface::GetObjectBarFeature ( USHORT nNo ) const +{ + BOOL bGenoType = (pGenoType != 0 && !pGenoType->HasName()); + if ( bGenoType ) + { + // Gibt es Toolbars in der Superklasse ? + USHORT nBaseCount = pGenoType->GetObjectBarCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->GetObjectBarFeature( nNo ); + else + nNo -= nBaseCount; + } + + USHORT nCount = pImpData->pObjectBars->Count(); + DBG_ASSERT( nNo<nCount,"Objectbar ist unbekannt!" ); + return (*pImpData->pObjectBars)[nNo]->nFeature; +} + + +BOOL SfxInterface::IsObjectBarVisible(USHORT nNo) const +{ + BOOL bGenoType = (pGenoType != 0 && !pGenoType->HasName()); + if ( bGenoType ) + { + // Gibt es Toolbars in der Superklasse ? + USHORT nBaseCount = pGenoType->GetObjectBarCount(); + if ( nNo < nBaseCount ) + // Die der Superklasse kommen zuerst + return pGenoType->IsObjectBarVisible( nNo ); + else + nNo -= nBaseCount; + } + + USHORT nCount = pImpData->pObjectBars->Count(); + DBG_ASSERT( nNo<nCount,"Objectbar ist unbekannt!" ); + return (*pImpData->pObjectBars)[nNo]->bVisible; +} + + +void SfxInterface::SetObjectBarVisible(BOOL bVis, USHORT nId) +{ + // Objectbar im eigenen Array suchen + USHORT nCount = pImpData->pObjectBars->Count(); + USHORT n; + for ( n=0; n<nCount; n++ ) + if ( (*pImpData->pObjectBars)[n]->aResId.GetId() == nId ) break; + + if ( n >= nCount ) + { + // Nicht gefunden, in der Superklasse versuchen + BOOL bGenoType = (pGenoType != 0 && !pGenoType->HasName()); + if (bGenoType) + ((SfxInterface*)pGenoType)->SetObjectBarVisible(bVis,nId); + else + DBG_ERROR("Objectbar ist unbekannt!"); + } + else + { + (*pImpData->pObjectBars)[n]->bVisible = bVis; + if (pConfig) + pConfig->SetDefault(FALSE); + } +} + + +void SfxInterface::ReInitialize(SfxConfigManager *pCfgMgr) +{ + DBG_ASSERT( pConfig, "ReInitialize ohne Config!" ); + + SfxConfigManager *pOld = pConfig->GetConfigManager_Impl(); + if (pCfgMgr == pOld) + return; + pConfig->ReInitialize(pCfgMgr); + + pCfgMgr->RemoveConfigItem(pConfig); + pOld->AddConfigItem(pConfig); + + pConfig->SetDefault(FALSE); + + for (USHORT n=0; n<pImpData->pObjectBars->Count(); n++) + { + USHORT nId = (*pImpData->pObjectBars)[n]->aResId.GetId(); + if ( SfxToolBoxManager::IsUserDefToolBox_Impl(nId)) + { + if (!pOld->HasConfigItem(nId)) + pOld->InsertConfigItem(nId); + } + } +} + + +void SfxInterface::SaveConfig() +{ + if ( pConfig ) + pConfig->StoreConfig(); +} + + +USHORT SfxInterface::GetConfigId() const +{ + return SFX_ITEMTYPE_INTERFACE_START + nClassId; +} + + +SfxObjectUIArr_Impl* SfxInterface::GetObjectBarArr_Impl() const +{ + return pImpData->pObjectBars; +} + + +USHORT SfxInterface::RegisterUserDefToolBox(USHORT nId, const String *pName, + SfxConfigManager *pCfgMgr) +{ + // Zuerst "uber den Namen die ToolBox suchen + SfxInterface *pIFace; + for (pIFace = SFX_SLOTPOOL().FirstInterface(); pIFace != 0; + pIFace = SFX_SLOTPOOL().NextInterface()) + { + // Nur Interfaces mit Namen d"urfen welche bekommen + if (pIFace->HasName()) + { + // Zugriff auf ObjectBars + SfxObjectUIArr_Impl *pArr = pIFace->GetObjectBarArr_Impl(); + for (USHORT nNo=0; nNo<pArr->Count(); nNo++) + { + if ( *pName == *(*pArr)[nNo]->pName) + return (*pArr)[nNo]->aResId.GetId(); + } + } + } + + // Ansonsten n"achste freie Id besorgen + USHORT nFreeId = SfxToolBoxManager::GetUserDefToolBoxId_Impl(); + BOOL bFound = FALSE; + + // Alle Interfaces durchprobieren, ob sie noch eine UserDefToolBox + // aufnehmen k"onnen + USHORT nPos; + for (pIFace = SFX_SLOTPOOL().FirstInterface(); pIFace != 0; + pIFace = SFX_SLOTPOOL().NextInterface()) + { + BOOL bFound = FALSE; + + // Nur Interfaces mit Namen d"urfen welche bekommen + if (pIFace->HasName()) + { + // Zugriff auf ObjectBars + SfxObjectUIArr_Impl *pArr = pIFace->GetObjectBarArr_Impl(); + + for ( nPos=SFX_OBJECTBAR_USERDEF1; nPos<=SFX_OBJECTBAR_USERDEF3; nPos++ ) + { + // Nach freier Position suchen + bFound = TRUE; + for (USHORT nNo=0; nNo<pArr->Count(); nNo++) + { + if ( nPos == (*pArr)[nNo]->nPos) + { + // Diese Position ist schon besetzt, n"achste versuchen + bFound = FALSE; + break; + } + } + + // Wurde eine noch freie Position gefunden ? + if ( bFound ) + break; + } + } + + // Wurde am Interface etwas gefunden ? + if ( bFound ) + break; + } + + if ( pIFace ) + { + // Am gefundenen Interface mu\s die Konfiguration ver"andert werden + SfxConfigItem *pCfgItem = pIFace->GetConfig_Impl(); + SfxConfigManager *pOldCfgMgr = pCfgItem->GetConfigManager_Impl(); + + if ( pOldCfgMgr != pCfgMgr ) + { + // Wenn das Interface bisher von einem anderen ConfigManager + // bedient wird, wird dessen Config gesichert + pCfgItem->StoreConfig(); + + // Der Ziel-Configmanager mu\s die Konfiguration aufnehmen k"onnen + if ( !pCfgMgr->HasConfigItem(pIFace->GetConfigId()) ) + pCfgMgr->InsertConfigItem(pIFace->GetConfigId()); + + // Verbindung mit dem ConfigItem herstellen und Config "ubernehmen + pCfgMgr->AddConfigItem(pCfgItem); + pCfgItem->Initialize(); + } + + // Jetzt wird das Interface umkonfiguriert + pIFace->RegisterObjectBar(nPos, nFreeId, pName); + pIFace->SetObjectBarVisible(TRUE, nFreeId); + + // Konfiguration sichern und aktuellen Stand der Config restaurieren + if ( pCfgMgr != pOldCfgMgr && pCfgMgr != SFX_CFGMANAGER() ) + { + pCfgItem->StoreConfig(); + pCfgMgr->RemoveConfigItem(pCfgItem); + pCfgItem->Connect(pOldCfgMgr); + pCfgItem->Initialize(); + } + } + + return nFreeId; +} + + +void SfxInterface::ReleaseUserDefToolBox(USHORT nId, SfxConfigManager *pCfgMgr) + +{ + BOOL bDone = FALSE; + + // Alle Interfaces durchprobieren, ob sie diese UserDefToolBox haben + for (SfxInterface *pIFace = SFX_SLOTPOOL().FirstInterface(); pIFace != 0; + pIFace = SFX_SLOTPOOL().NextInterface()) + { + // Nur Interfaces mit Namen k"onnen welche haben + if (pIFace->HasName()) + { + // Die Konfiguration vom "ubergebenen Manager interessiert + SfxConfigItem *pCfgItem = pIFace->GetConfig_Impl(); + SfxConfigManager *pOldCfgMgr = pCfgItem->GetConfigManager_Impl(); + + if ( pOldCfgMgr != pCfgMgr ) + { + // Wenn das Interface bisher von einem anderen ConfigManager + // bedient wird, wird dessen Config gesichert + pCfgItem->StoreConfig(); + + // Verbindung mit dem ConfigItem herstellen und Config "ubernehmen + pCfgMgr->AddConfigItem(pCfgItem); + pCfgItem->Initialize(); + } + + if ( pIFace->HasObjectBar(nId) ) + { + pIFace->ReleaseObjectBar(nId); + BOOL bDone = TRUE; + } + + // Konfiguration sichern und aktuellen Stand der Config restaurieren + if ( pCfgMgr != pOldCfgMgr ) + { + pCfgItem->StoreConfig(); + pCfgMgr->RemoveConfigItem(pCfgItem); + pCfgItem->Connect(pOldCfgMgr); + pCfgItem->Initialize(); + } + } + + if ( bDone ) + { + break; + } + } +} + + +BOOL SfxInterface::HasObjectBar( USHORT nId ) const +{ + for (USHORT n=0; n<pImpData->pObjectBars->Count(); n++) + if ((*pImpData->pObjectBars)[n]->aResId.GetId() == nId) return TRUE; + return FALSE; +} + +SfxModule* SfxInterface::GetModule() const +{ + return pImpData->pModule; +} + +const SfxInterface* SfxInterface::GetRealInterfaceForSlot( const SfxSlot *pRealSlot ) const +{ + const SfxInterface* pInterface = this; + + // Der Slot k"onnte auch aus dem Interface einer Shell-Basisklasse stammen + do + { + const SfxSlot *pLastSlot = (*pInterface)[pInterface->Count()-1]; + const SfxSlot *pFirstSlot = (*pInterface)[0]; + + // Ist pInterface der Owner von pRealSlot ? + if ( pFirstSlot <= pRealSlot && pRealSlot <= pLastSlot ) + break; + + // Sonst Interface der Superklasse probieren + pInterface = pInterface->pGenoType; + } + while ( pInterface ); + + return pInterface; +} + + diff --git a/sfx2/source/control/request.cxx b/sfx2/source/control/request.cxx new file mode 100644 index 000000000000..f03edd48cc6d --- /dev/null +++ b/sfx2/source/control/request.cxx @@ -0,0 +1,576 @@ +/************************************************************************* + * + * $RCSfile: request.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SFXITEMITER_HXX //autogen +#include <svtools/itemiter.hxx> +#endif + +#ifndef _ARGS_HXX //autogen +#include <svtools/args.hxx> +#endif + +#ifndef _SVTOOLS_ITEMDEL_HXX +#include <svtools/itemdel.hxx> +#endif + +#include <svtools/itempool.hxx> + +#pragma hdrstop + +#include "request.hxx" +#include "dispatch.hxx" +#include "sfxtypes.hxx" +#include "msg.hxx" +#include "objsh.hxx" +#include "saveopt.hxx" +#include "viewfrm.hxx" +#include "viewsh.hxx" +#include "app.hxx" +#include "objface.hxx" + +//=================================================================== + +struct SfxRequest_Impl: public SfxListener + +/* [Beschreibung] + + Implementations-Struktur der Klasse <SfxRequest>. +*/ + +{ + SfxRequest* pAnti; // Owner wegen sterbendem Pool + SfxItemPool* pPool; // ItemSet mit diesem Pool bauen + SfxPoolItem* pRetVal; // R"uckgabewert geh"ort sich selbst + const SfxShell* pShell; // ausgef"uhrt an dieser Shell + const SfxSlot* pSlot; // ausgef"uhrter Slot + USHORT nModifier; // welche Modifier waren gedrueckt? + BOOL bDone; // "uberhaupt ausgef"uhrt + BOOL bIgnored; // vom User abgebrochen + BOOL bCancelled; // nicht mehr zustellen + USHORT nCallMode; // Synch/Asynch/API/Record + SfxAllItemSet* pInternalArgs; + + SfxRequest_Impl( SfxRequest *pOwner ) + : pAnti( pOwner), bCancelled(FALSE), + nCallMode( SFX_CALLMODE_SYNCHRON ), nModifier(0), + pPool(0), pInternalArgs( 0 ) + {} + ~SfxRequest_Impl() { delete pInternalArgs; } + + + void SetPool( SfxItemPool *pNewPool ); + virtual void Notify( SfxBroadcaster &rBC, const SfxHint &rHint ); +}; + + +//==================================================================== + +void SfxRequest_Impl::Notify( SfxBroadcaster &rBC, const SfxHint &rHint ) +{ + SfxSimpleHint *pSimpleHint = PTR_CAST(SfxSimpleHint, &rHint); + if ( pSimpleHint && pSimpleHint->GetId() == SFX_HINT_DYING ) + pAnti->Cancel(); +} + +//==================================================================== + +void SfxRequest_Impl::SetPool( SfxItemPool *pNewPool ) +{ + if ( pNewPool != pPool ) + { + if ( pPool ) + EndListening( pPool->BC() ); + pPool = pNewPool; + if ( pNewPool ) + StartListening( pNewPool->BC() ); + } +} + +//==================================================================== + + +SfxRequest::~SfxRequest() +{ + DBG_MEMTEST(); + // nicht mit Done() marktierte Requests mit 'rem' rausschreiben + + // Objekt abr"aumen + delete pArgs; + if ( pImp->pRetVal ) + DeleteItemOnIdle(pImp->pRetVal); + delete pImp; +} +//-------------------------------------------------------------------- + + +SfxRequest::SfxRequest +( + const SfxRequest& rOrig +) +: nSlot(rOrig.nSlot), + pArgs(rOrig.pArgs? new SfxAllItemSet(*rOrig.pArgs): 0), + pImp( new SfxRequest_Impl(this) ) +{ + DBG_MEMTEST(); + + pImp->bDone = FALSE; + pImp->bIgnored = FALSE; + pImp->pRetVal = 0; + pImp->pShell = 0; + pImp->pSlot = 0; + pImp->nCallMode = rOrig.pImp->nCallMode; + pImp->nModifier = rOrig.pImp->nModifier; + + if ( pArgs ) + pImp->SetPool( pArgs->GetPool() ); + else + pImp->SetPool( rOrig.pImp->pPool ); +} + +SfxRequest::SfxRequest +( + USHORT nSlotId, // auszuf"uhrende <Slot-Id> + SfxCallMode nMode, // Synch/API/... + SfxItemPool& rPool // ggf. f"ur das SfxItemSet f"ur Parameter +) + +// creates a SfxRequest without arguments + +: nSlot(nSlotId), + pArgs(0), + pImp( new SfxRequest_Impl(this) ) +{ + DBG_MEMTEST(); + + pImp->bDone = FALSE; + pImp->bIgnored = FALSE; + pImp->SetPool( &rPool ); + pImp->pRetVal = 0; + pImp->pShell = 0; + pImp->pSlot = 0; + pImp->nCallMode = nMode; +} + +//----------------------------------------------------------------------- + +SfxRequest::SfxRequest +( + USHORT nSlotId, + USHORT nMode, + const SfxAllItemSet& rSfxArgs +) + +// creates a SfxRequest with arguments + +: nSlot(nSlotId), + pArgs(new SfxAllItemSet(rSfxArgs)), + pImp( new SfxRequest_Impl(this) ) +{ + DBG_MEMTEST(); + + pImp->bDone = FALSE; + pImp->bIgnored = FALSE; + pImp->SetPool( rSfxArgs.GetPool() ); + pImp->pRetVal = 0; + pImp->pShell = 0; + pImp->pSlot = 0; + pImp->nCallMode = nMode; +} +//-------------------------------------------------------------------- + +USHORT SfxRequest::GetCallMode() const +{ + return pImp->nCallMode; +} + +//-------------------------------------------------------------------- + +BOOL SfxRequest::IsSynchronCall() const +{ + return SFX_CALLMODE_SYNCHRON == ( SFX_CALLMODE_SYNCHRON & pImp->nCallMode ); +} + +//-------------------------------------------------------------------- + +void SfxRequest::SetSynchronCall( BOOL bSynchron ) +{ + if ( bSynchron ) + pImp->nCallMode |= SFX_CALLMODE_SYNCHRON; + else + pImp->nCallMode &= ~(USHORT) SFX_CALLMODE_SYNCHRON; +} + +void SfxRequest::SetInternalArgs_Impl( const SfxAllItemSet& rArgs ) +{ + delete pImp->pInternalArgs; + pImp->pInternalArgs = new SfxAllItemSet( rArgs ); +} + +const SfxItemSet* SfxRequest::GetInternalArgs_Impl() const +{ + return pImp->pInternalArgs; +} + +//-------------------------------------------------------------------- + +void SfxRequest::SetArgs( const SfxAllItemSet& rArgs ) +{ + delete pArgs; + pArgs = new SfxAllItemSet(rArgs); + pImp->SetPool( pArgs->GetPool() ); +} + +//-------------------------------------------------------------------- + +void SfxRequest::AppendItem(const SfxPoolItem &rItem) +{ + if(!pArgs) + pArgs = new SfxAllItemSet(*pImp->pPool); + pArgs->Put(rItem, rItem.Which()); +} + +//-------------------------------------------------------------------- + +void SfxRequest::RemoveItem( USHORT nID ) +{ + if (pArgs) + { + pArgs->ClearItem(nID); + if ( !pArgs->Count() ) + DELETEZ(pArgs); + } +} + +//-------------------------------------------------------------------- + +const SfxPoolItem* SfxRequest::GetArg +( + USHORT nSlotId, // Slot-Id oder Which-Id des Parameters + FASTBOOL bDeep, // FALSE: nicht in Parent-ItemSets suchen + TypeId aType // != 0: RTTI Pruefung mit Assertion +) const +{ + return GetItem( pArgs, nSlotId, bDeep, aType ); +} + + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxRequest::GetItem +( + const SfxItemSet* pArgs, + USHORT nSlotId, // Slot-Id oder Which-Id des Parameters + FASTBOOL bDeep, // FALSE: nicht in Parent-ItemSets suchen + TypeId aType // != 0: RTTI Pruefung mit Assertion +) + +/* [Beschreibung] + + Mit dieser Methode wird der Zugriff auf einzelne Parameter im + SfxRequest wesentlich vereinfacht. Insbesondere wird die Typpr"ufung + (per Assertion) durchgef"uhrt, wodurch die Applikations-Sourcen + wesentlich "ubersichtlicher werden. In der PRODUCT-Version wird + eine 0 zur"uckgegeben, wenn das gefundene Item nicht von der + angegebenen Klasse ist. + + + [Beispiel] + + void MyShell::Execute( SfxRequest &rReq ) + { + switch ( rReq.GetSlot() ) + { + case SID_MY: + { + ... + // ein Beispiel ohne Verwendung des Makros + const SfxInt32Item *pPosItem = (const SfxUInt32Item*) + rReq.GetArg( SID_POS, FALSE, TYPE(SfxInt32Item) ); + USHORT nPos = pPosItem ? pPosItem->GetValue() : 0; + + // ein Beispiel mit Verwendung des Makros + SFX_REQUEST_ARG(rReq, pSizeItem, SfxInt32Item, SID_SIZE, FALSE); + USHORT nSize = pSizeItem ? pPosItem->GetValue() : 0; + + ... + } + + ... + } + } +*/ + +{ + if ( pArgs ) + { + // ggf. in Which-Id umrechnen + USHORT nWhich = pArgs->GetPool()->GetWhich(nSlotId); + + // ist das Item gesetzt oder bei bDeep==TRUE verf"ugbar? + const SfxPoolItem *pItem = 0; + if ( ( bDeep ? SFX_ITEM_AVAILABLE : SFX_ITEM_SET ) + <= pArgs->GetItemState( nWhich, bDeep, &pItem ) ) + { + // stimmt der Typ "uberein? + if ( !pItem || pItem->IsA(aType) ) + return pItem; + + // Item da aber falsch => Programmierfehler + DBG_ERROR( "invalid argument type" ); + } + } + + // keine Parameter, nicht gefunden oder falschen Typ gefunden + return 0; +} + +//-------------------------------------------------------------------- + +void SfxRequest::SetReturnValue(const SfxPoolItem &rItem) +{ + DBG_ASSERT(!pImp->pRetVal, "Returnwert mehrfach setzen?"); + if(pImp->pRetVal) + delete pImp->pRetVal; + pImp->pRetVal = rItem.Clone(); +} + +//-------------------------------------------------------------------- + +const SfxPoolItem* SfxRequest::GetReturnValue() const +{ + return pImp->pRetVal; +} + +//-------------------------------------------------------------------- + +void SfxRequest::Done +( + const SfxItemSet& rSet, /* von der Applikation mitgeteilte Parameter, + die z.B. in einem Dialog vom Benuter + erfragt wurden, ggf. 0 falls keine + Parameter gesetzt wurden */ + + FASTBOOL bKeep /* TRUE (default) + 'rSet' wird gepeichert und ist "uber + GetArgs() abfragbar + + FALSE + 'rSet' wird nicht kopiert (schneller) */ +) + +/* [Beschreibung] + + Diese Methode mu\s in der <Execute-Methode> des <SfxSlot>s gerufen + werden, der den SfxRequest ausgef"uhrt hat, wenn die Ausf"uhrung + tats"achlich stattgefunden hat. Wird 'Done()' nicht gerufen, gilt + der SfxRequest als abgebrochen. + + Etwaige Returnwerte werden nur durchgereicht, wenn 'Done()' gerufen + wurde. Ebenso werden beim Aufzeichnen von Makros nur echte + Statements erzeugt, wenn 'Done()' gerufen wurde; f"ur SfxRequests, + die nicht derart gekennzeichnet wurden, wird anstelle dessen eine + auf die abgebrochene Funktion hinweisende Bemerkung ('rem') eingf"ugt. + + + [Anmerkung] + + 'Done()' wird z.B. nicht gerufen, wenn ein durch die Funktion gestarteter + Dialog vom Benutzer abgebrochen wurde oder das Ausf"uhren aufgrund + eines falschen Kontextes (ohne Verwendung separater <SfxShell>s) + nicht durchgef"uhrt werden konnte. 'Done()' mu\s sehr wohl gerufen + werden, wenn das Ausf"uhren der Funktion zu einem regul"aren Fehler + f"uhrte (z.B. Datei konnte nicht ge"offnet werden). +*/ + +{ + pImp->bDone = TRUE; + + // ggf. Items merken, damit StarDraw sie abfragen kann + if ( bKeep ) + { + if ( !pArgs ) + { + pArgs = new SfxAllItemSet( rSet ); + pImp->SetPool( pArgs->GetPool() ); + } + else + { + SfxItemIter aIter(rSet); + const SfxPoolItem* pItem = aIter.FirstItem(); + while(pItem) + { + if(!IsInvalidItem(pItem)) + pArgs->Put(*pItem,pItem->Which()); + pItem = aIter.NextItem(); + } + } + } +} + +//-------------------------------------------------------------------- + + +void SfxRequest::Done( BOOL bRelease ) +// [<SfxRequest::Done(SfxItemSet&)>] +{ + pImp->bDone = TRUE; + if( bRelease ) + DELETEZ( pArgs ); +} + +//-------------------------------------------------------------------- + +BOOL SfxRequest::IsCancelled() const +{ + return pImp->bCancelled; +} + +//-------------------------------------------------------------------- + +void SfxRequest::Cancel() + +/* [Beschreibung] + + Markiert diesen Request als nicht mehr auszufuehren. Wird z.B. gerufen, + wenn das Ziel (genauer dessen Pool) stirbt. +*/ + +{ + pImp->bCancelled = TRUE; + pImp->SetPool( 0 ); + DELETEZ( pArgs ); +} + +//-------------------------------------------------------------------- + + +void SfxRequest::Ignore() + +/* [Beschreibung] + + Wird diese Methode anstelle von <SfxRequest::Done()> gerufen, dann + wird dieser Request nicht recorded. + + + [Bespiel] + + Das Selektieren von Tools im StarDraw soll nicht aufgezeichnet werden, + dieselben Slots sollen aber zum erzeugen der von den Tools zu + erzeugenden Objekte verwendet werde. Also kann nicht NoRecord + angegeben werden, dennoch soll u.U. nicht aufgezeichnet werden. +*/ + +{ + // als tats"achlich ausgef"uhrt markieren + pImp->bIgnored = TRUE; +} + +//-------------------------------------------------------------------- + +BOOL SfxRequest::IsDone() const + +/* [Beschreibung] + + Mit dieser Methode kann abgefragt werden, ob der SfxRequest tats"achlich + ausgef"uhrt wurde oder nicht. Wurde ein SfxRequest nicht ausgef"uhrt, + liegt dies z.B. daran, da\s der Benutzer abgebrochen hat oder + der Kontext f"ur diesen Request falsch war, dieses aber nicht "uber + eine separate <SfxShell> realisiert wurde. + + SfxRequest-Instanzen, die hier FALSE liefern, werden nicht recorded. + + + [Querverweise] + + <SfxRequest::Done(const SfxItemSet&)> + <SfxRequest::Done()> +*/ + +{ + return pImp->bDone; +} + +//-------------------------------------------------------------------- + +BOOL SfxRequest::IsAPI() const + +/* [Beschreibung] + + Liefert TRUE, wenn dieser SfxRequest von einer API (z.B. BASIC) + erzeugt wurde, sonst FALSE. +*/ + +{ + return SFX_CALLMODE_API == ( SFX_CALLMODE_API & pImp->nCallMode ); +} + +//-------------------------------------------------------------------- +void SfxRequest::SetModifier( USHORT nModi ) +{ + pImp->nModifier = nModi; +} + +//-------------------------------------------------------------------- +USHORT SfxRequest::GetModifier() const +{ + return pImp->nModifier; +} + + diff --git a/sfx2/source/control/shell.cxx b/sfx2/source/control/shell.cxx new file mode 100644 index 000000000000..b73b804f5a45 --- /dev/null +++ b/sfx2/source/control/shell.cxx @@ -0,0 +1,1524 @@ +/************************************************************************* + * + * $RCSfile: shell.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SB_SBSTAR_HXX //autogen +#include <basic/sbstar.hxx> +#endif +#ifndef _PSEUDO_HXX //autogen +#include <so3/pseudo.hxx> +#endif +#ifndef _SFXITEMPOOL_HXX //autogen +#include <svtools/itempool.hxx> +#endif +#ifndef _UNDO_HXX //autogen +#include <svtools/undo.hxx> +#endif +#ifndef _SVTOOLS_ITEMDEL_HXX +#include <svtools/itemdel.hxx> +#endif + +#ifndef _SBXCLASS_HXX //autogen +#include <svtools/sbx.hxx> +#endif + +#pragma hdrstop + +#include "shell.hxx" +#include "bindings.hxx" +#include "dispatch.hxx" +#include "viewfrm.hxx" +#include "sfxbasic.hxx" +#include "objface.hxx" +#include "objsh.hxx" +#include "viewsh.hxx" +#include "dispatch.hxx" +#include "sfxtypes.hxx" +#include "request.hxx" +#include "mnumgr.hxx" +#include "saveopt.hxx" +#include "statcach.hxx" + +//==================================================================== + +DBG_NAME(SfxShell); + +//==================================================================== + +TYPEINIT0(SfxShell); + +//==================================================================== +typedef SfxSlot* SfxSlotPtr; +SV_DECL_PTRARR_DEL( SfxVerbSlotArr_Impl, SfxSlotPtr, 4, 4); +SV_IMPL_PTRARR( SfxVerbSlotArr_Impl, SfxSlotPtr); + +struct SfxVerbList +{ + SfxVerbSlotArr_Impl aSlotArr; + SvVerbList aVerbList; +}; + +struct SfxShell_Impl: public SfxBroadcaster +{ + String aObjectName;// Name des Sbx-Objects + SfxItemArray_Impl aItems; // Datenaustausch auf Item-Basis + SfxViewShell* pViewSh; // SfxViewShell falls Shell ViewFrame/ViewShell/SubShell ist + SfxViewFrame* pFrame; // Frame, falls <UI-aktiv> + SfxVerbList* pVerbs; + SfxRepeatTarget* pRepeatTarget; +// SbxObjectRef xParent; + BOOL bInAppBASIC; + BOOL bActive; + ULONG nDisableFlags; + ULONG nHelpId; + AsynchronLink* pExecuter; + AsynchronLink* pUpdater; + SfxShell_Impl() : pExecuter( 0 ), pUpdater( 0 ) {} + ~SfxShell_Impl() { delete pExecuter; delete pUpdater;} +}; + +//==================================================================== +#ifdef DBG_UTIL + +String SfxShellIdent_Impl( const SfxShell *pSh ) + +/* [Beschreibung] + + Interne Hilfesfunktion. Liefert einen die SfxShell 'pSh' beschreibenden + String zur"uck. Z.B.: SfxApplication[StarWriter] +*/ + +{ + String aIdent( pSh->ISA(SfxApplication) ? DEFINE_CONST_UNICODE("SfxApplication") : + pSh->ISA(SfxViewFrame) ? DEFINE_CONST_UNICODE("SfxViewFrame") : + pSh->ISA(SfxViewShell) ? DEFINE_CONST_UNICODE("SfxViewShell") : + pSh->ISA(SfxObjectShell) ? DEFINE_CONST_UNICODE("SfxObjectShell") : DEFINE_CONST_UNICODE("SfxShell") ); + aIdent += 0x005B; // '[' = 5Bh + aIdent += pSh->GetName(); + aIdent += 0x005D; // ']' = 5Dh + return aIdent; +} + +#endif +//==================================================================== + +void __EXPORT SfxShell::EmptyExecStub(SfxShell *, SfxRequest &) +{ +} + +void __EXPORT SfxShell::EmptyStateStub(SfxShell *, SfxItemSet &) +{ +} + +SfxShell::SfxShell() + +/* [Beschreibung] + + Der Konstruktor der Klasse SfxShell initialisierung nur einfache + Typen, das dazugeh"orige SbxObject wird erst on-demand erzeugt. + Daher ist das Anlegen einer SfxShell Instanz sehr billig. +*/ + +: pPool(0), + pUndoMgr(0), + pImp(0) +{ + DBG_CTOR(SfxShell, 0); + pImp = new SfxShell_Impl; + pImp->pViewSh = 0; + pImp->pFrame = 0; + pImp->pVerbs = 0; + pImp->pRepeatTarget = 0; + pImp->bInAppBASIC = FALSE; + pImp->nHelpId = 0L; + pImp->bActive = FALSE; + pImp->nDisableFlags = 0; +} + +//------------------------------------------------------------------------- + +SfxShell::SfxShell( SfxViewShell *pViewSh ) + +/* [Beschreibung] + + Der Konstruktor der Klasse SfxShell initialisierung nur einfache + Typen, das dazugeh"orige SbxObject wird erst on-demand erzeugt. + Daher ist das Anlegen einer SfxShell Instanz sehr billig. +*/ + +: pPool(0), + pUndoMgr(0), + pImp(0) +{ + DBG_CTOR(SfxShell, 0); + pImp = new SfxShell_Impl; + pImp->pViewSh = pViewSh; + pImp->pFrame = 0; + pImp->pVerbs = 0; + pImp->pRepeatTarget = 0; + pImp->bInAppBASIC = FALSE; + pImp->nHelpId = 0L; + pImp->bActive = FALSE; +} + +//-------------------------------------------------------------------- + +SfxShell::~SfxShell() + +/* [Beschreibung] + + Die Verbindungs zu einem ggf. zugeh"origen SbxObject wird gel"ost. + Das SbxObject existiert ggf. weiter, kann aber keine Funktionen + mehr ausf"uhren und keine Properties mehr bereitstellen. +*/ + +{ + DBG_DTOR(SfxShell, 0); + delete pImp->pVerbs; + delete pImp; +} + +//-------------------------------------------------------------------- + +void SfxShell::SetName( const String &rName ) + +/* [Beschreibung] + + Setzt den Namen des Shell-Objekts. Mit diesem Namen kann die + SfxShell-Instanz vom BASIC aus angesprochen werden. +*/ + +{ + pImp->aObjectName = rName; +} + +//-------------------------------------------------------------------- + +const String& SfxShell::GetName() const + +/* [Beschreibung] + + Liefert den Namen des Shell-Objekts. Mit diesem Namen kann die + SfxShell-Instanz vom BASIC aus angesprochen werden. +*/ + +{ + return pImp->aObjectName; +} + +//-------------------------------------------------------------------- + +SvGlobalName SfxShell::GetGlobalName() const + +/* [Beschreibung] + + Liefert den Global Unique Identifier des Shell-Objekts. Mit diesem + Namen kann die SfxShell-Instanz z.B. via OLE Automation angesprochen + werden, bzw. in der Registration-Database gefunden werden. +*/ + +{ + return SvGlobalName(); +} + +//-------------------------------------------------------------------- + +SfxDispatcher* SfxShell::GetDispatcher() const + +/* [Beschreibung] + + Diese Methode liefert einen Pointer auf den <SfxDispatcher>, in + dem die SfxShell gerade <UI-aktiv> ist bzw. einen 0-Pointer, wenn + sie gerade nicht UI-aktiv ist. + + Der zur"uckgegebene Pointer ist nur im unmittelbaren Kontext des + Methodenaufrufs g"ultig. +*/ + +{ + return pImp->pFrame ? pImp->pFrame->GetDispatcher() : 0; +} + +//-------------------------------------------------------------------- + +SfxViewShell* SfxShell::GetViewShell() const + +/* [Beschreibung] + + Liefert bei SubShells die SfxViewShell, in der sie liegen. Sonst und + falls nicht vom App-Entwickler angegeben liefert diese Methode 0. +*/ + +{ + return pImp->pViewSh; +} + +//-------------------------------------------------------------------- + +SfxViewFrame* SfxShell::GetFrame() const + +/* [Beschreibung] + + Diese Methode liefert einen Pointer auf den <SfxViewFrame>, dem diese + SfxShell-Instanz zugeordnet ist oder in dem sie zur Zeit <UI-aktiv> ist. + Ein 0-Pointer wird geliefert, wenn diese SfxShell-OInstanz gerade nicht + UI-aktiv ist und auch keinem SfxViewFrame fest zugeordnet ist. + + Der zur"uckgegebene Pointer ist nur im unmittelbaren Kontext des + Methodenaufrufs g"ultig. + + + [Anmerkung] + + Nur Instanzen von Subklasse von SfxApplication und SfxObjectShell sollten + hier einen 0-Pointer liefern. Ansonsten liegt ein Fehler im Anwendungs- + programm vor (falscher Ctor von SfxShell gerufen). + + + [Querverweise] + + <SfxViewShell::GetViewFrame()const> +*/ + +{ + if ( pImp->pFrame ) + return pImp->pFrame; + if ( pImp->pViewSh ) + return pImp->pViewSh->GetViewFrame(); + return 0; +} + +//-------------------------------------------------------------------- + +const SfxPoolItem* SfxShell::GetItem +( + USHORT nSlotId // Slot-Id des zu erfragenden <SfxPoolItem>s +) const + +/* [Beschreibung] + + Mit dieser Methode kann auf beliebige Objekte von Subklassen von + <SfxPoolItem> zugegriffen werden. Diese Austauschtechnik wird ben"otigt, + wenn z.B. spezielle <SfxToolBoxControl> Subklassen Zugriff auf + bestimmte Daten z.B. der <SfxObjectShell> ben"otigen. + + Die zur"uckgelieferte Instanz geh"ort der jeweilige SfxShell und + darf nur im unmittelbaren Kontext des Methodenaufrufs verwendet werden. + + + [Querverweise] + + <SfxShell::PutItem(const SfxPoolItem&)> + <SfxShell::RemoveItem(USHORT)> +*/ + +{ + for ( USHORT nPos = 0; nPos < pImp->aItems.Count(); ++nPos ) + if ( pImp->aItems.GetObject(nPos)->Which() == nSlotId ) + return pImp->aItems.GetObject(nPos); + return 0; +} + +//-------------------------------------------------------------------- + +void SfxShell::RemoveItem +( + USHORT nSlotId // Slot-Id des zu l"oschenden <SfxPoolItem>s +) + +/* [Beschreibung] + + Mit dieser Methode k"onnen die allgemein zur Verf"ugung gestellten + Instanzen von Subklassen von <SfxPoolItem> aus der SfxShell entfernt + werden. + + Die gespeicherte Instanz wird gel"oscht. + + + [Querverweise] + + <SfxShell::PutItem(const SfxPoolItem&)> + <SfxShell::GetItem(USHORT)> +*/ + +{ + for ( USHORT nPos = 0; nPos < pImp->aItems.Count(); ++nPos ) + if ( pImp->aItems.GetObject(nPos)->Which() == nSlotId ) + { + // Item entfernen und l"oschen + SfxPoolItem *pItem = pImp->aItems.GetObject(nPos); + delete pItem; + pImp->aItems.Remove(nPos); + + // falls aktiv Bindings benachrichtigen + SfxDispatcher *pDispat = GetDispatcher(); + if ( pDispat ) + { + SfxVoidItem aVoid( nSlotId ); + pDispat->GetBindings()->Broadcast( SfxPoolItemHint( &aVoid ) ); + } + } +} + +//-------------------------------------------------------------------- + +void SfxShell::PutItem +( + const SfxPoolItem& rItem /* Instanz, von der eine Kopie erstellt wird, + die in der SfxShell in einer Liste + gespeichert wird. */ +) + +/* [Beschreibung] + + Mit dieser Methode k"onnen beliebige Objekte von Subklassen von + <SfxPoolItem> zur Verf"ugung gestellt werden. Diese Austauschtechnik + wird ben"otigt, wenn z.B. spezielle <SfxToolBoxControl> Subklassen + Zugriff auf bestimmte Daten z.B. der <SfxObjectShell> ben"otigen. + + Falls ein SfxPoolItem mit derselben Slot-Id exisitert, wird dieses + automatisch gel"oscht. + + + [Querverweise] + + <SfxShell::RemoveItem(USHORT)> + <SfxShell::GetItem(USHORT)> +*/ + +{ + DBG_ASSERT( !rItem.ISA(SfxSetItem), "SetItems aren't allowed here" ); + DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ), + "items with Which-Ids aren't allowed here" ); + + // MSC auf WNT/W95 machte hier Mist, Vorsicht bei Umstellungen + const SfxPoolItem *pItem = rItem.Clone(); + SfxPoolItemHint aItemHint( (SfxPoolItem*) pItem ); + const USHORT nWhich = rItem.Which(); + SfxPoolItem **ppLoopItem = (SfxPoolItem**) pImp->aItems.GetData(); + USHORT nPos; + for ( nPos = 0; nPos < pImp->aItems.Count(); ++nPos, ++ppLoopItem ) + { + if ( (*ppLoopItem)->Which() == nWhich ) + { + // Item austauschen + delete *ppLoopItem; + pImp->aItems.Remove(nPos); + pImp->aItems.Insert( (SfxPoolItemPtr) pItem, nPos ); + + // falls aktiv Bindings benachrichtigen + SfxDispatcher *pDispat = GetDispatcher(); + if ( pDispat ) + pDispat->GetBindings()->Broadcast( aItemHint ); + return; + } + } + + Broadcast( aItemHint ); + pImp->aItems.Insert((SfxPoolItemPtr)pItem, nPos ); +} + +//-------------------------------------------------------------------- + +SfxInterface* SfxShell::GetInterface() const + +/* [Beschreibung] + + Mit dieser virtuellen Methode, die durch das Makro <SFX_DECL_INTERFACE> + von jeder Subclass mit eigenen Slots automatisch "uberladen wird, kann + auf die zu der Subklasse geh"orende <SfxInterface>-Instanz zugegriffen + werden. + + Die Klasse SfxShell selbst hat noch kein eigenes SfxInterface + (keine Slots), daher wird ein 0-Pointer zur"uckgeliefert. +*/ + +{ + return 0; +} + +//-------------------------------------------------------------------- + +SfxBroadcaster* SfxShell::GetBroadcaster() + +/* [Beschreibung] + + Liefert einen SfxBroadcaster f"ur diese SfxShell-Instanz bis die + Klasse SfxShell von SfxBroadcaster abgeleitet ist. +*/ + +{ + return pImp; +} + +//-------------------------------------------------------------------- + +SfxUndoManager* SfxShell::GetUndoManager() + +/* [Beschreibung] + + Jede Subclass von SfxShell kann "uber einen <SfxUndoManager> verf"ugen. + Dieser kann in den abgeleiteten Klasse mit <SfxShell:SetUndoManager()> + gesetzt werden. + + Die Klasse SfxShell selbst hat noch keinen SfxUndoManager, es wird + daher ein 0-Pointer zur"uckgeliefert. +*/ + +{ + return pUndoMgr; +} + +//-------------------------------------------------------------------- + +void SfxShell::SetUndoManager( SfxUndoManager *pNewUndoMgr ) + +/* [Beschreibung] + + Setzt einen <SfxUndoManager> f"ur diese <SfxShell> Instanz. F"ur das + Undo wird immer nur der Undo-Manager an der jeweils oben auf dem + Stack des <SfxDispatcher> liegenden SfxShell verwendet. + + Am "ubergebenen <SfxUndoManager> wird automatisch die aktuelle + Max-Undo-Action-Count Einstellung aus den Optionen gesetzt. + + 'pNewUndoMgr' mu\s bis zum Dtor dieser SfxShell-Instanz oder bis + zum n"achsten 'SetUndoManager()' existieren. +*/ + +{ + pUndoMgr = pNewUndoMgr; + if ( pUndoMgr ) + pUndoMgr->SetMaxUndoActionCount( SFX_APP()->GetOptions().GetUndoCount() ); +} + +//-------------------------------------------------------------------- + +SfxRepeatTarget* SfxShell::GetRepeatTarget() const + +/* [Beschreibung] + + Liefert einen Pointer auf die <SfxRepeatTarget>-Instanz, die + als RepeatTarget bei SID_REPEAT verwendet wird, wenn der + von dieser SfxShell gelieferte <SfxUndoManager> angesprochen wird. + Der R"uckgabewert kann 0 sein. + + + [Anmerkung] + + Eine Ableitung von <SfxShell> oder einer ihrer Subklassen von + <SfxRepeatTarget> ist nicht zu empfehlen, da Compiler-Fehler + provoziert werden (wegen Call-to-Pointer-to-Member-Function to + subclass). +*/ + +{ + return pImp->pRepeatTarget; +} + +//-------------------------------------------------------------------- + +void SfxShell::SetRepeatTarget( SfxRepeatTarget *pTarget ) + +/* [Beschreibung] + + Setzt den die <SfxRepeatTarget>-Instanz, die bei SID_REPEAT als + RepeatTarget verwendet wird, wenn der von dieser SfxShell gelieferte + <SfxUndoManager> angesprochen wird. Durch 'pTarget==0' wird SID_REPEAT + f"ur diese SfxShell disabled. Die Instanz '*pTarget' mu\s so lange + leben, wie sie angemeldet ist. + + + [Anmerkung] + + Eine Ableitung von <SfxShell> oder einer ihrer Subklassen von + <SfxRepeatTarget> ist nicht zu empfehlen, da Compiler-Fehler + provoziert werden (wegen Call-to-Pointer-to-Member-Function to + subclass). +*/ + +{ + pImp->pRepeatTarget = pTarget; +} + +//-------------------------------------------------------------------- + +void SfxShell::Invalidate +( + USHORT nId /* Zu invalidierende Slot-Id oder Which-Id. + Falls diese 0 ist (default), werden + alle z.Zt. von dieser Shell bedienten + Slot-Ids invalidiert. */ +) + +/* [Beschreibung] + + Mit dieser Methode k"onnen Slots der Subclasses "uber die Slot-Id + oder alternativ "uber die Which-Id invalidiert werden. Slot-Ids, + die von der Subclass ererbt sind, werden ebenfalls invalidert. + + [Querverweise] + <SfxBindings::Invalidate(USHORT)> + <SfxBindings::InvalidateAll(BOOL)> +*/ + +{ + if ( !GetViewShell() ) + { +#if SUPD>603 + DBG_ERROR( "wrong Invalidate method called!" ); +#endif + return; + } + + Invalidate_Impl( GetViewShell()->GetViewFrame()->GetBindings(), nId ); +} + +void SfxShell::Invalidate_Impl( SfxBindings& rBindings, USHORT nId ) +{ + if ( nId == 0 ) + { + rBindings.InvalidateShell( *this, FALSE ); + } + else + { + const SfxInterface *pIF = GetInterface(); + do + { + const SfxSlot *pSlot = pIF->GetSlot(nId); + if ( pSlot ) + { + // bei Enum-Slots ist der Master-Slot zu invalidieren + if ( SFX_KIND_ENUM == pSlot->GetKind() ) + pSlot = pSlot->GetLinkedSlot(); + + // den Slot selbst und ggf. auch alle Slave-Slots invalidieren + rBindings.Invalidate( pSlot->GetSlotId() ); + for ( const SfxSlot *pSlave = pSlot->GetLinkedSlot(); + pSlave && pIF->ContainsSlot_Impl( pSlave ) && + pSlave->GetLinkedSlot() == pSlot; + ++pSlave ) + rBindings.Invalidate( pSlave->GetSlotId() ); + + return; + } + + pIF = pIF->GetGenoType(); + } + + while ( pIF ); + + DBG_WARNING( "W3: invalidating slot-id unknown in shell" ); + } +} + +//-------------------------------------------------------------------- + +void SfxShell::DoActivate( SfxViewFrame *pFrame, BOOL bMDI ) + +/* [Beschreibung] + + Diese Methode steuert die Aktivierung der SfxShell-Instanz. Zun"achst + wird durch Aufruf der virtuellen Methode <SfxShell::Activate(BOOL)> + der Subclass die M"oglichkeit gegeben, auf das Event zu reagieren. + + Bei bMDI == TRUE wird das zugeh"orige SbxObject 'scharfgeschaltet', + so da\s Methoden des Objekts unqualifiziert (ohne den Namen des Objekts) + vom BASIC gefunden werden. +*/ + +{ +#ifndef PRODUCT + const SfxInterface *p_IF = GetInterface(); + if ( !p_IF ) + return; +#endif +#ifdef DBG_UTIL_VB + String aMsg("SfxShell::DoActivate() "); + aMsg += (long)this; + aMsg += " "; + aMsg += GetInterface()->GetName(); + aMsg += " bMDI "; + if ( bMDI ) aMsg += "MDI"; + DbgTrace( aMsg.GetBuffer() ); +#endif + + if ( bMDI ) + { + // Frame merken, in dem aktiviert wird + pImp->pFrame = pFrame; + pImp->bActive = TRUE; + } + + // Subklasse benachrichtigen + Activate(bMDI); +} + +//-------------------------------------------------------------------- + +void SfxShell::DoDeactivate( SfxViewFrame *pFrame, BOOL bMDI ) + +/* [Beschreibung] + + Diese Methode steuert die Deaktivierung der SfxShell-Instanz. Bei + bMDI == TRUE wird zun"achst das SbxObject in einen Status versetzt, + so da\s Methoden vom BASIC aus nur noch qualifiziert gerufen werden + k"onnen. + + Dann erh"alt in jedem Fall die Subclass durch Aufruf der virtuellen + Methode <SfxShell::Deactivate(BOOL)> die M"oglichkeit auf das Event + zu reagieren. +*/ + +{ +#ifndef PRODUCT + const SfxInterface *p_IF = GetInterface(); + if ( !p_IF ) + return; +#endif +#ifdef DBG_UTIL_VB + String aMsg("SfxShell::DoDeactivate()"); + aMsg += (long)this; + aMsg += " "; + aMsg += GetInterface()->GetName(); + aMsg += " bMDI "; + if ( bMDI ) aMsg += "MDI"; + DbgTrace( aMsg.GetBuffer() ); +#endif + + // nur wenn er vom Frame kommt (nicht z.B. pop der BASIC-IDE vom AppDisp) + if ( bMDI && pImp->pFrame == pFrame ) + { + // austragen + pImp->pFrame = 0; + pImp->bActive = FALSE; + } + + // Subklasse benachrichtigen + Deactivate(bMDI); +} + +//-------------------------------------------------------------------- + +BOOL SfxShell::IsActive() const +{ + return pImp->bActive; +} + +//-------------------------------------------------------------------- + +void SfxShell::Activate +( + BOOL bMDI /* TRUE + der <SfxDispatcher>, auf dem die SfxShell sich + befindet, ist aktiv geworden oder die SfxShell + Instanz wurde auf einen aktiven SfxDispatcher + gepusht. (vergl. SystemWindow::IsMDIActivate()) + + FALSE + das zum <SfxViewFrame>, auf dessen SfxDispatcher + sich die SfxShell Instanz befindet, wurde + aktiviert. + (z.B. durch einen geschlossenen Dialog) */ +) + +/* [Beschreibung] + + Virtuelle Methode, die beim Aktivieren der SfxShell Instanz gerufen + wird, um den Subclasses die Gelegenheit zu geben, auf das Aktivieren + zu reagieren. + + Die Basisimplementation ist leer und braucht nicht gerufen zu werden. + + + [Querverweise] + StarView SystemWindow::Activate(BOOL) +*/ + +{ +} + +//-------------------------------------------------------------------- + +void SfxShell::Deactivate +( + BOOL bMDI /* TRUE + der <SfxDispatcher>, auf dem die SfxShell sich + befindet, ist inaktiv geworden oder die SfxShell + Instanz wurde auf einen aktiven SfxDispatcher + gepoppt. (vergl. SystemWindow::IsMDIActivate()) + + FALSE + das zum <SfxViewFrame>, auf dessen SfxDispatcher + sich die SfxShell Instanz befindet, wurde + deaktiviert. (z.B. durch einen Dialog) */ + +) + +/* [Beschreibung] + + Virtuelle Methode, die beim Deaktivieren der SfxShell Instanz gerufen + wird, um den Subclasses die Gelegenheit zu geben, auf das Deaktivieren + zu reagieren. + + Die Basisimplementation ist leer und braucht nicht gerufen zu werden. + + + [Querverweise] + StarView SystemWindow::Dectivate(BOOL) +*/ + +{ +} + +void SfxShell::ParentActivate +( +) + +/* [Beschreibung] + + Ein Parent des <SfxDispatcher>, auf dem die SfxShell sich befindet, + ist aktiv geworden, oder die SfxShell Instanz wurde auf einen + <SfxDispatcher> gepusht, dessen parent aktiv ist. + + Die Basisimplementation ist leer und braucht nicht gerufen zu werden. + + [Querverweise] + SfxShell::Activate() +*/ +{ +} + +//-------------------------------------------------------------------- + +void SfxShell::ParentDeactivate +( +) + +/* [Beschreibung] + + Der aktive Parent des <SfxDispatcher>, auf dem die SfxShell sich befindet, + ist deaktiviert worden. + + Die Basisimplementation ist leer und braucht nicht gerufen zu werden. + + [Querverweise] + SfxShell::Deactivate() +*/ +{ +} + +//-------------------------------------------------------------------- +#if 0 +// falls noch mal "pure virtual function called" auf dem MAC: +// Bitte MAC nicht mehr unterstuetzen +// der MPW-Linker will die immer haben, obwohl pure virtual + +#ifdef MAC +extern "C" +{ + void debugstr( char *pMsg ); +} +#endif + +SfxItemPool& SfxShell::GetPool() +{ + debugstr( "pure virtual function called: SfxShell::GetPool()" ); + SfxItemPool aPool(0,0); + return aPool; +} + +#endif + +//-------------------------------------------------------------------- + +void SfxShell::FillStatusBar( StatusBar& ) + +/* [Beschreibung] + + Mit dieser Factory-Methode kann der Applikationsprogrammierer einer + SfxShell-Subklasse eine eigene Statusbar zuweisen. Der SFx bevorzugt + jeweils die Statusbar einer weiter oben auf den <SfxDispatcher>-Stack + liegenden SfxShell. + + Die Basisimplementation ist leer und braucht nicht gerufen zu werden. + +*/ + +{ +} + +//-------------------------------------------------------------------- + +ResMgr* SfxShell::GetResMgr() const + +/* [Beschreibung] + + Diese Methode liefert den ResMgr der <Resource-DLL>, die von der + SfxShell-Instanz verwendet wird. Ist dies ein 0-Pointer, so + ist der aktuelle Resource-Manager zu verwenden. +*/ + +{ + return GetInterface()->GetResMgr(); +} + +//-------------------------------------------------------------------- + +FASTBOOL SfxShell::CanExecuteSlot_Impl( const SfxSlot &rSlot ) + +/* [Beschreibung] + + Diese Methode stellt durch Aufruf der Statusfunktion fest, + ob 'rSlot' aktuell ausgef"uhrt werden kann. +*/ +{ + // Slot-Status holen + SfxItemPool &rPool = GetPool(); + const USHORT nId = rSlot.GetWhich( rPool ); + SfxItemSet aSet(rPool, nId, nId); + SfxStateFunc pFunc = rSlot.GetStateFnc(); + CallState( pFunc, aSet ); + return aSet.GetItemState(nId) != SFX_ITEM_DISABLED; +} + +//-------------------------------------------------------------------- +#if 0 +ULONG SfxShell::ExecuteSlot +( + USHORT nSlot, // In: auszuf"uhrender Slot + USHORT nMemberId, // In: MemberId f"ur strukturierte Items + SbxVariable& rRet, // Out: Returnwert + SbxBase* pArgs // In: 0, einzelner Parameter/Parameterliste +) + +/* [Beschreibung] + + Methode zum Ausf"uhren eines <SfxSlot>s von einem SfxShellObject + (BASIC oder andere API). + + Aufrufe von APIs werden nicht recorded (ist ja auch kein <SfxDispatcher>). + + + [R"uckgabewert] + + ULONG ErrorCode +*/ + +{ + // Slot suchen + const SfxSlot *pSlot = GetInterface()->GetSlot(nSlot); + if ( !pSlot ) + return SbxERR_PROC_UNDEFINED; + + // ggf. disabled + if ( !pSlot->IsMode(SFX_SLOT_FASTCALL) && !CanExecuteSlot_Impl(*pSlot) ) + return SbERR_METHOD_FAILED; + + // "ofters ben"otigte Werte + SfxItemPool &rPool = GetPool(); + SfxMapUnit eUserMetric = SFX_APP()->GetOptions().GetUserMetric(); + + // Returnwert zum sp"ateren Aufbereiten als SbxVariable merken + BOOL bDone = FALSE; // Return nur auswerten, wenn nicht abgebrochen wurde + const SfxPoolItem *pRetItem = 0; + SbxObject *pOwnObject = GetSbxObject(); // Hack fuer #22783 + + // aktuelle Parameter oder Property (impliziter Parameter)? + if ( pArgs || pSlot->IsMode(SFX_SLOT_PROPSET) ) + { + // aktuelle Parameter in diesem ItemSet sammeln + SfxAllItemSet aSet( rPool ); + + // mehrere Parameter? + if ( pSlot->IsMode(SFX_SLOT_METHOD) ) + { + // das kann nur ein Methoden-Slot sein + DBG_ASSERT( !pArgs || pArgs->ISA(SbxArray), "not an SbxArray as arguments" ); + + // "uber die formalen Parameter iterieren + USHORT nFormalArgs = pSlot->GetFormalArgumentCount(); + USHORT nActualArgs = pArgs ? ((SbxArray*)pArgs)->Count() - 1 : 0; + USHORT nBasicArg = 0; + for ( USHORT nArg = 0; + nArg < nFormalArgs && nBasicArg < nActualArgs; + ++nArg ) + { + // formale Paramterbeschreibung besorgen + const SfxFormalArgument &rArg = pSlot->GetFormalArgument(nArg); + + // Item per Factory erzeugen + SfxPoolItem *pItem = rArg.CreateItem(); + DBG_ASSERT( pItem, "item without factory" ); + pItem->SetWhich( rPool.GetWhich(rArg.nSlotId) ); + + // Konvertieren / ggf. strukturierte Items zusammensetzen + ULONG eErr = 0; + USHORT nSubCount = rArg.pType->nAttribs; + if ( !nSubCount ) + { + // einfaches Item + SbxVariable *pSubArg = ((SbxArray*)pArgs)->Get(++nBasicArg); + eErr = rPool.SetVariable( *pItem, *pSubArg, eUserMetric ); + } + else + { + // strukturiertes Item + for ( USHORT n = 1; n <= nSubCount && !eErr; ++n ) + { + SbxVariable *pSubArg = ((SbxArray*)pArgs)->Get(++nBasicArg); + pSubArg->SetUserData( + long(rArg.pType->aAttrib[n-1].nAID) << 20 ); + eErr = rPool.SetVariable( *pItem, *pSubArg, eUserMetric ); + } + } + + // falls Item erzeugt werden konnte, an Request anh"angen + if ( 0 == eErr ) + aSet.Put( *pItem,pItem->Which() ); + delete pItem; //! Optimieren (Put mit direkter Uebernahme) + if ( 0 != eErr ) + return eErr; + } + + // nicht alle Parameter abger"aumt (zuviele)? + if ( nBasicArg < nActualArgs ) + return SbxERR_WRONG_ARGS; + } + else + { + // Instanz von SfxPoolItem-Subklasse besorgen/erzeugen + SfxPoolItem *pItem = 0; + + // Teil eines strukturiertes Items? + if ( nMemberId ) + { + // => Status-Item besorgen + const SfxPoolItem *pState = GetSlotState(nSlot); + if ( pState && !pState->ISA(SfxVoidItem) ) + pItem = pState->Clone(); + } + + // kein StatusItem oder einfaches/komplexes Item + if ( !pItem ) + { + // per Factory erzeugen + pItem = pSlot->GetType()->CreateItem(); + DBG_ASSERT( pItem, "item without factory" ); + pItem->SetWhich( rPool.GetWhich(nSlot) ); + } + + // Daten aus Variable in das Item "ubertragen + ULONG eErr = rPool.SetVariable( *pItem, rRet, eUserMetric ); + if ( 0 == eErr ) + aSet.Put( *pItem,pItem->Which() ); + delete pItem; //! Optimieren (Put mit direkter Uebernahme) + if ( 0 != eErr ) + return eErr; + } + + // via Request mit 'normaler' Execute-Methode ausf"uhren + SfxRequest aReq( nSlot, SFX_CALLMODE_API, aSet ); + aSet.ClearItem(); // pPool k"onnte in _Execute sterben + SfxExecFunc pFunc = pSlot->GetExecFnc(); + CallExec( pFunc, aReq ); + bDone = aReq.IsDone(); + pRetItem = aReq.GetReturnValue(); + } + else + { + // ohne Parameter direkt ausf"uhren + SfxRequest aReq( nSlot, SFX_CALLMODE_API, GetPool() ); +// SfxRequest aReq( nSlot, GetPool(), TRUE ); + SfxExecFunc pFunc = pSlot->GetExecFnc(); + CallExec( pFunc, aReq ); + bDone = aReq.IsDone(); + pRetItem = aReq.GetReturnValue(); + } + + // in IDL ein Return-Wert angegeben? + if ( pSlot->IsMode(SFX_SLOT_METHOD) && rRet.GetType() != SbxVOID ) + { + // ist aber kein Returnwert gesetzt worden? + if ( !pRetItem || pRetItem->ISA(SfxVoidItem) ) + { + // Ignore ohne Parameter ist erlaubt und auch normal + if ( !bDone ) + return 0; + + // sonst mu\s einer gesetzt worden sein + DBG_ERROR( "IDL hat Return-Wert, Execute-Methode setzt aber keinen!" ); + return SbxERR_CONVERSION; + } + + // Returnwert in SbxVariable packen + HACK( #22783 - lebt *this noch? ) + if ( ((SfxShellObject*)pOwnObject)->GetShell() ) + GetPool().FillVariable( *pRetItem, rRet, eUserMetric ); + else + pRetItem->FillVariable( rRet, eUserMetric, eUserMetric ); + } + + return 0; +} +#endif + +long ShellCall_Impl( void* pObj, void* pArg ) +{ + ((SfxShell* )pObj)->ExecuteSlot( *(SfxRequest*)pArg, (SfxInterface*)0L ); + return 0; +} + +/* [Beschreibung] + Asynchrones ExecuteSlot fuer das RELOAD + */ + +//-------------------------------------------------------------------- +const SfxPoolItem* SfxShell::ExecuteSlot( SfxRequest& rReq, BOOL bAsync ) +{ + if( !bAsync ) + return ExecuteSlot( rReq, (SfxInterface*)0L ); + else + { + if( !pImp->pExecuter ) + pImp->pExecuter = new AsynchronLink( + Link( this, ShellCall_Impl ) ); + pImp->pExecuter->Call( new SfxRequest( rReq ) ); + return 0; + } +} + +const SfxPoolItem* SfxShell::ExecuteSlot +( + SfxRequest &rReq, // der weiterzuleitende <SfxRequest> + const SfxInterface* pIF // default = 0 bedeutet virtuell besorgen +) + +/* [Beschreibung] + + Diese Methode erm"oglicht das Weiterleiten eines <SfxRequest> an + die angegebene Basis-<SfxShell>. + + + [Beispiel] + + In einer von SfxViewShell abgeleiteten Klasse soll SID_PRINTDOCDIRECT + abgefangen werden. Unter bestimmten Umst"anden soll vor dem Drucken + eine Abfrage erscheinen, und der Request soll ggf. abgebrochen werden. + + Dazu ist in der IDL dieser Subklasse der o.g. Slot einzutragen. Die + Execute-Methode enth"alt dann skizziert: + + void SubViewShell::Exec( SfxRequest &rReq ) + { + if ( rReq.GetSlot() == SID_PRINTDOCDIRECT ) + { + 'dialog' + if ( 'condition' ) + ExecuteSlot( rReq, SfxViewShell::GetInterface() ); + } + } + + Es braucht i.d.R. kein rReq.Done() gerufen zu werden, da das bereits + die Implementierung der SfxViewShell erledigt bzw. abgebrochen wurde. + + + [Querverweise] + + <SfxShell::GetSlotState(USHORT,const SfxInterface*,SfxItemSet*)> +*/ + +{ + if ( !pIF ) + pIF = GetInterface(); + const SfxSlot *pSlot = pIF->GetSlot(rReq.GetSlot()); + DBG_ASSERT( pSlot, "slot not supported" ); + + SfxExecFunc pFunc = pSlot->GetExecFnc(); + CallExec( pFunc, rReq ); + + return rReq.GetReturnValue(); +} + +//-------------------------------------------------------------------- + +const SfxPoolItem* SfxShell::GetSlotState +( + USHORT nSlotId, // Slot-Id des zu befragenden Slots + const SfxInterface* pIF, // default = 0 bedeutet virtuell besorgen + SfxItemSet* pStateSet // SfxItemSet der Slot-State-Methode +) + +/* [Beschreibung] + + Diese Methode liefert den Status des Slots mit der angegebenen Slot-Id + "uber das angegebene Interface. + + Ist der Slot disabled oder in dieser SfxShell (und deren Parent-Shells) + nicht bekannt, wird ein 0-Pointer zur"uckgeliefert. + + Hat der Slot keinen Status, wird ein SfxVoidItem zur"uckgeliefert. + + Der Status wird bei pStateSet != 0 gleich in diesem Set gesetzt, so + da\s <SfxShell>-Subklassen Slots-"uberladen und auch bei der + Status-Methode die Basis-Implementierung rufen k"onnen. + + + [Beispiel] + + In einer von SfxViewShell abgeleiteten Klasse soll SID_PRINTDOCDIRECT + abgefangen werden. Unter bestimmten Umst"anden soll vor dem Drucken + eine Abfrage erscheinen, und der Request soll ggf. abgebrochen werden. + + Dazu ist in der IDL dieser Subklasse der o.g. Slot einzutragen. Die + Status-Methode enth"alt dann skizziert: + + void SubViewShell::PrintState( SfxItemSet &rState ) + { + if ( rState.GetItemState( SID_PRINTDOCDIRECT ) != SFX_ITEM_UNKNOWN ) + GetSlotState( SID_PRINTDOCDIRECT, SfxViewShell::GetInterface(), + &rState ); + ... + } + + + [Querverweise] + + <SfxShell::ExecuteSlot(SfxRequest&)> +*/ + +{ + // Slot am angegebenen Interface besorgen + if ( !pIF ) + pIF = GetInterface(); + SfxItemState eState; + SfxItemPool &rPool = GetPool(); + const SfxSlot *pSlot = pIF->GetSlot(nSlotId); + if ( pSlot ) + // ggf. auf Which-Id mappen + nSlotId = pSlot->GetWhich( rPool ); + + // Item und Item-Status besorgen + const SfxPoolItem *pItem; + SfxItemSet aSet( rPool, nSlotId, nSlotId ); // pItem stirbt sonst zu fr"uh + if ( pSlot ) + { + // Status-Methode rufen + SfxStateFunc pFunc = pSlot->GetStateFnc(); + CallState( pFunc, aSet ); + eState = aSet.GetItemState( nSlotId, TRUE, &pItem ); + + // ggf. Default-Item besorgen + if ( eState == SFX_ITEM_DEFAULT ) + { + if ( SfxItemPool::IsWhich(nSlotId) ) + pItem = &rPool.GetDefaultItem(nSlotId); + else + eState = SFX_ITEM_DONTCARE; + } + } + else + eState = SFX_ITEM_UNKNOWN; + + // Item und Item-Status auswerten und ggf. in pStateSet mitpflegen + SfxPoolItem *pRetItem = 0; + if ( eState <= SFX_ITEM_DISABLED ) + { + if ( pStateSet ) + pStateSet->DisableItem(nSlotId); + return 0; + } + else if ( eState == SFX_ITEM_DONTCARE ) + { + if ( pStateSet ) + pStateSet->ClearItem(nSlotId); + pRetItem = new SfxVoidItem(0); + } + else + { + if ( pStateSet && pStateSet->Put( *pItem ) ) + return &pStateSet->Get( pItem->Which() ); + pRetItem = pItem->Clone(); + } + DeleteItemOnIdle(pRetItem); + + return pRetItem; +} + +//-------------------------------------------------------------------- + +SFX_EXEC_STUB(SfxShell, VerbExec) +SFX_STATE_STUB(SfxShell, VerbState) + + +void SfxShell::SetVerbs(const SvVerbList* pVerbs) +{ + SfxViewShell *pViewSh = PTR_CAST ( SfxViewShell, this); + + DBG_ASSERT(pViewSh, "SetVerbs nur an der ViewShell aufrufen!"); + + if (pImp->pVerbs) + { + // Zun"achst alle Statecaches dirty machen, damit keiner mehr versucht, + // die Slots zu benutzen + + SfxBindings *pBindings = + pViewSh->GetViewFrame()->GetDispatcher()->GetBindings(); + USHORT nCount = pImp->pVerbs->aSlotArr.Count(); + for (USHORT n=0; n<nCount ; n++) + { + USHORT nId = SID_VERB_START + n; + pBindings->Invalidate(nId, FALSE, TRUE); + } + + DELETEZ (pImp->pVerbs); + } + + if (pVerbs) + pImp->pVerbs = new SfxVerbList(); + + if (pVerbs) + { + USHORT nr=0; + for (USHORT n=0; n<pVerbs->Count(); n++) + { + SfxSlot *pNewSlot = new SfxSlot; + USHORT nSlotId = SID_VERB_START + nr++; + DBG_ASSERT(nSlotId <= SID_VERB_END, "Zuviele Verben!"); + if (nSlotId > SID_VERB_END) + break; + + pNewSlot->nSlotId = nSlotId; + pNewSlot->nGroupId = 0; + + // Verb-Slots m"ussen asynchron ausgef"uhrt werden, da sie w"ahrend + // des Ausf"uhrens zerst"ort werden k"onnten + pNewSlot->nFlags = SFX_SLOT_ASYNCHRON; + pNewSlot->nMasterSlotId = 0; + pNewSlot->nValue = 0; + pNewSlot->fnExec = SFX_STUB_PTR(SfxShell,VerbExec); + pNewSlot->fnState = SFX_STUB_PTR(SfxShell,VerbState); + pNewSlot->pType = 0; HACK(SFX_TYPE(SfxVoidItem)) + pNewSlot->pName = U2S((*pVerbs)[n].GetName()).getStr(); + pNewSlot->pLinkedSlot = 0; + pNewSlot->nArgDefCount = 0; + pNewSlot->pFirstArgDef = 0; + pNewSlot->pUnoName = 0; + + if (pImp->pVerbs->aSlotArr.Count()) + { + SfxSlot *pSlot = (pImp->pVerbs->aSlotArr)[0]; + pNewSlot->pNextSlot = pSlot->pNextSlot; + pSlot->pNextSlot = pNewSlot; + } + else + pNewSlot->pNextSlot = pNewSlot; + + pImp->pVerbs->aSlotArr.Insert(pNewSlot, n); + pImp->pVerbs->aVerbList.Insert((*pVerbs)[n], n); + } + } + + if (pViewSh) + { + // Der Status von SID_OBJECT wird im Controller direkt an der Shell + // abgeholt, es reicht also, ein neues StatusUpdate anzuregen + SfxBindings *pBindings = pViewSh->GetViewFrame()->GetDispatcher()-> + GetBindings(); + pBindings->Invalidate( SID_OBJECT, TRUE, TRUE ); + } +} + +//-------------------------------------------------------------------- + +const SvVerbList* SfxShell::GetVerbs() const +{ + return pImp->pVerbs ? &pImp->pVerbs->aVerbList : 0; +} + +//-------------------------------------------------------------------- + +void SfxShell::VerbExec(SfxRequest& rReq) +{ + USHORT nId = rReq.GetSlot(); + SfxViewShell *pViewShell = SfxViewShell::Current(); + const SvVerbList* pList = pViewShell->GetVerbs(); + + for (USHORT n=0; n<pList->Count(); n++) + { + if (nId == SID_VERB_START + n) + { + pViewShell->DoVerb((*pList)[n].GetId()); + rReq.Done(); + return; + } + } +} + +//-------------------------------------------------------------------- + +void SfxShell::VerbState(SfxItemSet &rSet) +{ +} + +//-------------------------------------------------------------------- + +const SfxSlot* SfxShell::GetVerbSlot_Impl(USHORT nId) const +{ +// DBG_ASSERT(pImp->pVerbs, "Keine Verben bekannt!"); + if (!pImp->pVerbs) + return 0; + + const SvVerbList& rList = pImp->pVerbs->aVerbList; + + DBG_ASSERT(nId >= SID_VERB_START && nId <= SID_VERB_END,"Falsche VerbId!"); + USHORT nIndex = nId - SID_VERB_START; + DBG_ASSERT(nIndex < rList.Count(),"Falsche VerbId!"); + + if (nIndex < rList.Count()) + return pImp->pVerbs->aSlotArr[nIndex]; + else + return 0; +} + +//-------------------------------------------------------------------- + +void SfxShell::SetHelpId(ULONG nId) +{ + pImp->nHelpId = nId; +} + +//-------------------------------------------------------------------- + +ULONG SfxShell::GetHelpId() const +{ + return pImp->nHelpId; +} + +//-------------------------------------------------------------------- + +SfxObjectShell* SfxShell::GetObjectShell() +{ + if ( GetViewShell() ) + return GetViewShell()->GetViewFrame()->GetObjectShell(); + else + return NULL; +} + +//-------------------------------------------------------------------- + +SfxSlotPool& SfxShell::GetSlotPool_Impl() const +{ + return SFX_APP()->GetSlotPool( GetFrame() ); +} + +BOOL SfxShell::HasUIFeature( ULONG ) +{ + return FALSE; +} + +long DispatcherUpdate_Impl( void* pObj, void* pArg ) +{ + ((SfxDispatcher*) pArg)->Update_Impl( TRUE ); + return 0; +} + +void SfxShell::UIFeatureChanged() +{ + SfxViewFrame *pFrame = GetFrame(); + if ( pFrame && pFrame->IsVisible() ) + { + // Auch dann Update erzwingen, wenn Dispatcher schon geupdated ist, + // sonst bleibt evtl. irgendwas in den gebunkerten Tools stecken. + // Asynchron aufrufen, um Rekursionen zu vermeiden + if ( !pImp->pUpdater ) + pImp->pUpdater = new AsynchronLink( Link( this, DispatcherUpdate_Impl ) ); + + // Mehrfachaufrufe gestattet + pImp->pUpdater->Call( pFrame->GetDispatcher(), TRUE ); + } +} + +void SfxShell::SetDisableFlags( ULONG nFlags ) +{ + pImp->nDisableFlags = nFlags; +} + +ULONG SfxShell::GetDisableFlags() const +{ + return pImp->nDisableFlags; +} + +SfxItemSet* SfxShell::CreateItemSet( USHORT nId ) +{ + return NULL; +} + +void SfxShell::ApplyItemSet( USHORT nId, const SfxItemSet& rSet ) +{ +} + +void SfxShell::SetViewShell_Impl( SfxViewShell* pView ) +{ + pImp->pViewSh = pView; +} + + + diff --git a/sfx2/source/control/srchitem.cxx b/sfx2/source/control/srchitem.cxx new file mode 100644 index 000000000000..b9ce85cd593a --- /dev/null +++ b/sfx2/source/control/srchitem.cxx @@ -0,0 +1,306 @@ +/************************************************************************* + * + * $RCSfile: srchitem.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +// include --------------------------------------------------------------- + +#ifndef __SBX_SBXVARIABLE_HXX +#include <svtools/sbxvar.hxx> +#endif + +#ifndef _COM_SUN_STAR_UTIL_XREPLACEABLE_HPP_ +#include <com/sun/star/util/XReplaceable.hpp> +#endif +#ifndef _COM_SUN_STAR_UTIL_XSEARCHABLE_HPP_ +#include <com/sun/star/util/XSearchable.hpp> +#endif +#ifndef _COM_SUN_STAR_UTIL_XSEARCHDESCRIPTOR_HPP_ +#include <com/sun/star/util/XSearchDescriptor.hpp> +#endif +#ifndef _COM_SUN_STAR_UTIL_XPROPERTYREPLACE_HPP_ +#include <com/sun/star/util/XPropertyReplace.hpp> +#endif +#ifndef _COM_SUN_STAR_UTIL_XREPLACEDESCRIPTOR_HPP_ +#include <com/sun/star/util/XReplaceDescriptor.hpp> +#endif +#include <svtools/memberid.hrc> +//ASDBG #include <usr/uno.hxx> + +#pragma hdrstop + +#define _SVX_SRCHITEM_CXX + +#include "sfxsids.hrc" +#define ITEMID_SEARCH SID_SEARCH_ITEM +#include "srchitem.hxx" + +#include <sfxuno.hxx> + +// STATIC DATA ----------------------------------------------------------- + +TYPEINIT1_AUTOFACTORY(SvxSearchItem, SfxPoolItem); + +// ----------------------------------------------------------------------- + +SvxSearchItem::SvxSearchItem( const sal_uInt16 nId ) : + + SfxPoolItem( nId ), + + nCommand ( 0 ), + aSearchString () , + aReplaceString (), + bWordOnly ( sal_False ), + bExact ( sal_False ), + bBackward ( sal_False ), + bSelection ( sal_False ), + bRegExp ( sal_False ), + bPattern ( sal_False ), + bContent ( sal_False ), + eFamily ( SFX_STYLE_FAMILY_PARA ), + bRowDirection ( sal_True ), + bAllTables ( sal_False ), + nCellType ( SVX_SEARCHIN_FORMULA ), + nAppFlag ( SVX_SEARCHAPP_WRITER ), + bLevenshtein ( sal_False ), + bLEVRelaxed ( sal_True ), + nLEVOther ( 2 ), + nLEVShorter ( 2 ), + nLEVLonger ( 2 ) +{ +} + +// ----------------------------------------------------------------------- + +SvxSearchItem::SvxSearchItem( const SvxSearchItem& rItem ) : + + SfxPoolItem ( rItem ), + + nCommand ( rItem.nCommand ), + aSearchString ( rItem.aSearchString ), + aReplaceString ( rItem.aReplaceString ), + bWordOnly ( rItem.bWordOnly ), + bExact ( rItem.bExact ), + bBackward ( rItem.bBackward ), + bSelection ( rItem.bSelection ), + bRegExp ( rItem.bRegExp ), + bPattern ( rItem.bPattern ), + bContent ( rItem.bContent ), + eFamily ( rItem.eFamily ), + bRowDirection ( rItem.bRowDirection ), + bAllTables ( rItem.bAllTables ), + nCellType ( rItem.nCellType ), + nAppFlag ( rItem.nAppFlag ), + bLevenshtein ( rItem.bLevenshtein ), + bLEVRelaxed ( rItem.bLEVRelaxed ), + nLEVOther ( rItem.nLEVOther ), + nLEVShorter ( rItem.nLEVShorter ), + nLEVLonger ( rItem.nLEVLonger ) +{ +} + +// ----------------------------------------------------------------------- + +int SvxSearchItem::operator==( const SfxPoolItem& rItem ) const +{ + DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal which or type" ); + + return ( nCommand == ( (SvxSearchItem&)rItem ).nCommand ) && + ( aSearchString == ( (SvxSearchItem&)rItem ).aSearchString ) && + ( aReplaceString == ( (SvxSearchItem&)rItem ).aReplaceString ) && + ( bWordOnly == ( (SvxSearchItem&)rItem ).bWordOnly ) && + ( bExact == ( (SvxSearchItem&)rItem ).bExact ) && + ( bBackward == ( (SvxSearchItem&)rItem ).bBackward ) && + ( bSelection == ( (SvxSearchItem&)rItem ).bSelection ) && + ( bRegExp == ( (SvxSearchItem&)rItem ).bRegExp ) && + ( bPattern == ( (SvxSearchItem&)rItem ).bPattern ) && + ( bContent == ( (SvxSearchItem&)rItem ).bContent ) && + ( eFamily == ( (SvxSearchItem&)rItem ).eFamily ) && + ( bRowDirection == ( (SvxSearchItem&)rItem ).bRowDirection ) && + ( bAllTables == ( (SvxSearchItem&)rItem ).bAllTables ) && + ( nCellType == ( (SvxSearchItem&)rItem ).nCellType ) && + ( nAppFlag == ( (SvxSearchItem&)rItem ).nAppFlag ) && + ( bLevenshtein == ( (SvxSearchItem&)rItem ).bLevenshtein ) && + ( bLEVRelaxed == ( (SvxSearchItem&)rItem ).bLEVRelaxed ) && + ( nLEVOther == ( (SvxSearchItem&)rItem ).nLEVOther ) && + ( nLEVShorter == ( (SvxSearchItem&)rItem ).nLEVShorter ) && + ( nLEVLonger == ( (SvxSearchItem&)rItem ).nLEVLonger ); +} + + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxSearchItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit eCoreUnit, + SfxMapUnit ePresUnit, + XubString& rText, + const International * +) const +{ +/* + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText = SVX_RESSTR(RID_SVXITEMS_SEARCHCMD_BEGIN + nCommand); + rText += cpDelim; + rText += aSearchString; + rText += cpDelim; + rText += aReplaceString; + rText += cpDelim; + rText += ::GetBoolString( bWordOnly ); + rText += cpDelim; + rText += ::GetBoolString( bExact ); + rText += cpDelim; + rText += ::GetBoolString( bBackward ); + rText += cpDelim; + rText += ::GetBoolString( bSelection ); + rText += cpDelim; + rText += ::GetBoolString( bRegExp ); + rText += cpDelim; + rText += ::GetBoolString( bPattern ); + rText += cpDelim; + rText += ::GetBoolString( bContent ); + rText += cpDelim; + rText += SVX_RESSTR(RID_SVXITEMS_SEARCHSTYLE_BEGIN + (sal_uInt16)eFamily ); + rText += cpDelim; + rText += ::GetBoolString( bRowDirection ); + rText += cpDelim; + rText += ::GetBoolString( bAllTables ); + rText += cpDelim; + rText += SVX_RESSTR(RID_SVXITEMS_SEARCHIN_BEGIN + nCellType); + rText += cpDelim; + rText += SVX_RESSTR(RID_SVXITEMS_SEARCHAPP_BEGIN + nAppFlag); + return ePres; + } + } + */ + return SFX_ITEM_PRESENTATION_NONE; +} + +void SvxSearchItem::GetFromDescriptor( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XSearchDescriptor >& rDescr ) +{ + SetSearchString( rDescr->getSearchString() ); + ::com::sun::star::uno::Any aAny = rDescr->getPropertyValue( DEFINE_CONST_UNICODE("SearchWords") ); + sal_Bool bTemp ; + aAny >>= bTemp ; + SetWordOnly( bTemp ); + aAny = rDescr->getPropertyValue( DEFINE_CONST_UNICODE("SearchCaseSensitive") ); + aAny >>= bTemp ; + SetExact( bTemp ); + aAny = rDescr->getPropertyValue( DEFINE_CONST_UNICODE("SearchBackwards") ); + aAny >>= bTemp ; + SetBackward( bTemp ); + aAny = rDescr->getPropertyValue( DEFINE_CONST_UNICODE("SearchInSelection") ); + aAny >>= bTemp ; + SetSelection( bTemp ); + aAny = rDescr->getPropertyValue( DEFINE_CONST_UNICODE("SearchRegularExpression") ); + aAny >>= bTemp ; + SetRegExp( bTemp ); + aAny = rDescr->getPropertyValue( DEFINE_CONST_UNICODE("SearchSimilarity") ); + aAny >>= bTemp ; + SetLevenshtein( bTemp ); + aAny = rDescr->getPropertyValue( DEFINE_CONST_UNICODE("SearchSimilarityRelax") ); + aAny >>= bTemp ; + SetLEVRelaxed( bTemp ); + aAny = rDescr->getPropertyValue( DEFINE_CONST_UNICODE("SearchSimilarityExchange") ); + sal_Int16 nTemp ; + aAny >>= nTemp ; + SetLEVOther( nTemp ); + aAny = rDescr->getPropertyValue( DEFINE_CONST_UNICODE("SearchSimilarityRemove") ); + aAny >>= nTemp ; + SetLEVShorter( nTemp ); + aAny = rDescr->getPropertyValue( DEFINE_CONST_UNICODE("SearchSimilarityAdd") ); + aAny >>= nTemp ; + SetLEVLonger( nTemp ); +} + +void SvxSearchItem::SetToDescriptor( ::com::sun::star::uno::Reference< ::com::sun::star::util::XSearchDescriptor > & rDescr ) +{ + rDescr->setSearchString( GetSearchString() ); + ::com::sun::star::uno::Any aAny; + aAny <<= GetWordOnly() ; + rDescr->setPropertyValue( DEFINE_CONST_UNICODE("SearchWords"), aAny ); + aAny <<= GetExact() ; + rDescr->setPropertyValue( DEFINE_CONST_UNICODE("SearchCaseSensitive"), aAny ); + aAny <<= GetBackward() ; + rDescr->setPropertyValue( DEFINE_CONST_UNICODE("SearchBackwards"), aAny ); + aAny <<= GetSelection() ; + rDescr->setPropertyValue( DEFINE_CONST_UNICODE("SearchInSelection"), aAny ); + aAny <<= GetRegExp() ; + rDescr->setPropertyValue( DEFINE_CONST_UNICODE("SearchRegularExpression"), aAny ); + aAny <<= IsLevenshtein() ; + rDescr->setPropertyValue( DEFINE_CONST_UNICODE("SearchSimilarity"), aAny ); + aAny <<= IsLEVRelaxed() ; + rDescr->setPropertyValue( DEFINE_CONST_UNICODE("SearchSimilarityRelax"), aAny ); + aAny <<= GetLEVOther() ; + rDescr->setPropertyValue( DEFINE_CONST_UNICODE("SearchSimilarityExchange"), aAny ); + aAny <<= GetLEVShorter() ; + rDescr->setPropertyValue( DEFINE_CONST_UNICODE("SearchSimilarityRemove"), aAny ); + aAny <<= GetLEVLonger() ; + rDescr->setPropertyValue( DEFINE_CONST_UNICODE("SearchSimilarityAdd"), aAny ); +} + + diff --git a/sfx2/source/control/statcach.cxx b/sfx2/source/control/statcach.cxx new file mode 100644 index 000000000000..d563da2d0005 --- /dev/null +++ b/sfx2/source/control/statcach.cxx @@ -0,0 +1,577 @@ +/************************************************************************* + * + * $RCSfile: statcach.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <string> // HACK: prevent conflict between STLPORT and Workshop headers + +#ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_ +#include <com/sun/star/util/XURLTransformer.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XCONTROLLER_HPP_ +#include <com/sun/star/frame/XController.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XFRAMEACTIONLISTENER_HPP_ +#include <com/sun/star/frame/XFrameActionListener.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XCOMPONENTLOADER_HPP_ +#include <com/sun/star/frame/XComponentLoader.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XFRAME_HPP_ +#include <com/sun/star/frame/XFrame.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_FRAMEACTIONEVENT_HPP_ +#include <com/sun/star/frame/FrameActionEvent.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_FRAMEACTION_HPP_ +#include <com/sun/star/frame/FrameAction.hpp> +#endif +#ifndef _CPPUHELPER_WEAK_HXX_ +#include <cppuhelper/weak.hxx> +#endif +#include <svtools/eitem.hxx> +#include <svtools/intitem.hxx> +#include <svtools/stritem.hxx> +#include <unotools/processfactory.hxx> + +#pragma hdrstop + +#include "statcach.hxx" +#include "msg.hxx" +#include "ctrlitem.hxx" +#include "dispatch.hxx" +#include "sfxtypes.hxx" +#include "sfxuno.hxx" +#include "unoctitm.hxx" + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; + +//==================================================================== + +DBG_NAME(SfxStateCache); +DBG_NAME(SfxStateCacheSetState); + +SFX_IMPL_XINTERFACE_2( BindDispatch_Impl, OWeakObject, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener ) +SFX_IMPL_XTYPEPROVIDER_2( BindDispatch_Impl, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener ) + +//----------------------------------------------------------------------------- +BindDispatch_Impl::BindDispatch_Impl( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > & rDisp, const ::com::sun::star::util::URL& rURL, SfxStateCache *pStateCache ) + : xDisp( rDisp ) + , aURL( rURL ) + , pCache( pStateCache ) +{ + aStatus.IsEnabled = sal_True; +} + +void SAL_CALL BindDispatch_Impl::disposing( const ::com::sun::star::lang::EventObject& rEvent ) throw( ::com::sun::star::uno::RuntimeException ) +{ + if ( xDisp.is() ) + { + xDisp->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, ::com::sun::star::util::URL() ); + xDisp = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > (); + } +} + +void SAL_CALL BindDispatch_Impl::statusChanged( const ::com::sun::star::frame::FeatureStateEvent& rEvent ) throw( ::com::sun::star::uno::RuntimeException ) +{ + aStatus = rEvent; + if ( !pCache ) + return; + + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > xRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY ); + if ( aStatus.Requery ) + pCache->Invalidate( sal_True ); + else + { + pCache->Invalidate( sal_False ); + if ( !aStatus.IsEnabled ) + pCache->SetState_Impl( SFX_ITEM_DISABLED, NULL ); + else + { + sal_uInt16 nId = pCache->GetId(); + SfxItemState eState = SFX_ITEM_AVAILABLE; + SfxPoolItem *pItem=NULL; + ::com::sun::star::uno::Any aAny = aStatus.State; + ::com::sun::star::uno::Type pType = aAny.getValueType(); + + if ( pType == ::getBooleanCppuType() ) + { + sal_Bool bTemp ; + aAny >>= bTemp ; + pItem = new SfxBoolItem( nId, bTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt16*)0) ) + { + sal_uInt16 nTemp ; + aAny >>= nTemp ; + pItem = new SfxUInt16Item( nId, nTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt32*)0) ) + { + sal_uInt32 nTemp ; + aAny >>= nTemp ; + pItem = new SfxUInt32Item( nId, nTemp ); + } + else if ( pType == ::getCppuType((const ::rtl::OUString*)0) ) + { + ::rtl::OUString sTemp ; + aAny >>= sTemp ; + pItem = new SfxStringItem( nId, sTemp ); + } + else + pItem = new SfxVoidItem( nId ); + pCache->SetState_Impl( eState, pItem ); + delete pItem; + } + } +} + +void BindDispatch_Impl::Release() +{ + if ( xDisp.is() ) + { + xDisp->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, ::com::sun::star::util::URL() ); + xDisp = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > (); + } + + pCache = NULL; + release(); +} + +const ::com::sun::star::frame::FeatureStateEvent& BindDispatch_Impl::GetStatus() const +{ + return aStatus; +} + +void BindDispatch_Impl::Dispatch( sal_Bool bForceSynchron ) +{ + if ( xDisp.is() && aStatus.IsEnabled ) + if ( bForceSynchron ) + { + ::com::sun::star::uno::Sequence < ::com::sun::star::beans::PropertyValue > aProps(1); + aProps.getArray()[0].Name = DEFINE_CONST_UNICODE("SynchronMode"); + aProps.getArray()[0].Value <<= sal_True ; + xDisp->dispatch( aURL, aProps ); + } + else + xDisp->dispatch( aURL, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >() ); +} + +//-------------------------------------------------------------------- + +/* Dieser Konstruktor fuer einen ungueltigen Cache, der sich also + bei der ersten Anfrage zun"achst updated. + */ + +SfxStateCache::SfxStateCache( sal_uInt16 nFuncId ): + nId(nFuncId), + pController(0), + pLastItem( 0 ), + eLastState( 0 ), + pDispatch( 0 ) +{ + DBG_MEMTEST(); + DBG_CTOR(SfxStateCache, 0); + bCtrlDirty = sal_True; + bSlotDirty = sal_True; + bItemDirty = sal_True; +} + +//-------------------------------------------------------------------- + +/* Der Destruktor pr"uft per Assertion, ob noch Controller angemeldet + sind. + */ + +SfxStateCache::~SfxStateCache() +{ + DBG_MEMTEST(); + DBG_DTOR(SfxStateCache, 0); + DBG_ASSERT( pController == 0, "es sind noch Controller angemeldet" ); + if ( !IsInvalidItem(pLastItem) ) + delete pLastItem; + if ( pDispatch ) + { + pDispatch->Release(); + pDispatch = NULL; + } +} + +//-------------------------------------------------------------------- +// invalidates the cache (next request will force update) +void SfxStateCache::Invalidate( sal_Bool bWithMsg ) +{ + bCtrlDirty = sal_True; + if ( bWithMsg ) + { + bSlotDirty = sal_True; + aSlotServ.SetSlot( 0 ); + if ( pDispatch ) + { + pDispatch->Release(); + pDispatch = NULL; + } + } +} + +//-------------------------------------------------------------------- + +// gets the corresponding function from the dispatcher or the cache + +const SfxSlotServer* SfxStateCache::GetSlotServer( SfxDispatcher &rDispat , const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & xProv ) +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxStateCache, 0); + + if ( bSlotDirty ) + { + if ( xProv.is() ) + { + DBG_ASSERT( !pDispatch, "Altes Dispatch nicht entfernt!" ); + +//(mba)/compview + const SfxSlot* pSlot = 0;//SfxComponentViewShell::GetUnoSlot( nId ); + ::com::sun::star::util::URL aURL; + String aName( pSlot ? String::CreateFromAscii(pSlot->GetUnoName()) : String() ); + String aCmd; + if ( aName.Len() ) + { + aCmd = DEFINE_CONST_UNICODE(".uno:"); + aCmd += aName; + } + else + { + aCmd = DEFINE_CONST_UNICODE("slot:"); + aCmd += String::CreateFromInt32( nId ); + } + + aURL.Complete = aCmd; + Reference < XURLTransformer > xTrans( ::utl::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 = 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 = (SfxOfficeDispatch*)(nImplementation); + } + + if ( pDisp ) + { + // The intercepting object is a SFX component + // Get the shell that is the slotserver of this component + SfxDispatcher *pDispatcher = pDisp->GetDispatcher_Impl(); + pDispatcher->_FindServer( nId, aSlotServ, sal_False ); + SfxShell* pShell = pDispatcher->GetShell( aSlotServ.GetShellLevel() ); + + // Check if this shell is active on the active dispatcher + sal_uInt16 nLevel = rDispat.GetShellLevel( *pShell ); + if ( nLevel != USHRT_MAX ) + { + // so we can use this shell direct without StarONE connection + aSlotServ.SetShellLevel( nLevel ); + bSlotDirty = sal_False; + bCtrlDirty = sal_True; + + //MI: wozu das? bItemDirty = sal_True; + return aSlotServ.GetSlot()? &aSlotServ: 0; + } + else + { + pDispatch = new BindDispatch_Impl( xDisp, aURL, this ); + pDispatch->acquire(); + + // flags must be set before adding StatusListener because the dispatch object will set the state + bSlotDirty = sal_False; + bCtrlDirty = sal_True; + xDisp->addStatusListener( pDispatch, aURL ); + aSlotServ.SetSlot(0); + return NULL; + } + } + else + { + pDispatch = new BindDispatch_Impl( xDisp, aURL, this ); + pDispatch->acquire(); + + // flags must be set before adding StatusListener because the dispatch object will set the state + bSlotDirty = sal_False; + bCtrlDirty = sal_True; + xDisp->addStatusListener( pDispatch, aURL ); + aSlotServ.SetSlot(0); + return NULL; + } + } + } + +// if ( !rDispat._TryIntercept_Impl( nId, aSlotServ, sal_False ) ) + rDispat._FindServer(nId, aSlotServ, sal_False); + bSlotDirty = sal_False; + bCtrlDirty = sal_True; + //MI: wozu das? bItemDirty = sal_True; + } + + return aSlotServ.GetSlot()? &aSlotServ: 0; +} + + +//-------------------------------------------------------------------- + +// Status setzen in allen Controllern + +void SfxStateCache::SetState +( + SfxItemState eState, // <SfxItemState> von 'pState' + const SfxPoolItem* pState // Status des Slots, ggf. 0 oder -1 +) + +/* [Beschreibung] + + Diese Methode verteilt die Status auf alle an dieser SID gebundenen + <SfxControllerItem>s. Ist der Wert derselbe wie zuvor und wurde in- + zwischen weder ein Controller angemeldet, noch ein Controller invalidiert, + dann wird kein Wert weitergeleitet. Dadurch wird z.B. Flackern in + ListBoxen vermieden. +*/ + +{ + if ( pDispatch ) + return; + SetState_Impl( eState, pState ); +} + + +void SfxStateCache::SetState_Impl +( + SfxItemState eState, // <SfxItemState> von 'pState' + const SfxPoolItem* pState // Status des Slots, ggf. 0 oder -1 +) +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxStateCache, 0); + + // wenn zwischen Enter- und LeaveRegistrations ein hartes Update kommt + // k"onnen zwischenzeitlich auch Cached ohne Controller exisitieren + if ( !pController ) + return; + + DBG_ASSERT( pController->GetId()==nId, "Cache mit falschem ControllerItem" ); + DBG_ASSERT( !bSlotDirty, "setting state of dirty message" ); + DBG_ASSERT( bCtrlDirty || + ( aSlotServ.GetSlot() && aSlotServ.GetSlot()->IsMode(SFX_SLOT_VOLATILE) ), + "setting state of non dirty controller" ); + DBG_ASSERT( SfxControllerItem::GetItemState(pState) == eState, + "invalid SfxItemState" ); + DBG_PROFSTART(SfxStateCacheSetState); + + // m"ussen die Controller "uberhaupt benachrichtigt werden? + FASTBOOL bNotify = bItemDirty; + if ( !bItemDirty ) + { + FASTBOOL bBothAvailable = pLastItem && pState && + !IsInvalidItem(pState) && !IsInvalidItem(pLastItem); + DBG_ASSERT( !bBothAvailable || pState != pLastItem, "setting state with own item" ); + if ( bBothAvailable ) + bNotify = pState->Type() != pLastItem->Type() || + *pState != *pLastItem; + else + bNotify = ( pState != pLastItem ) || ( eState != eLastState ); + } + + if ( bNotify ) + { + // Controller updaten + for ( SfxControllerItem *pCtrl = pController; + pCtrl; + pCtrl = pCtrl->GetItemLink() ) + pCtrl->StateChanged( nId, eState, pState ); + + // neuen Wert merken + if ( !IsInvalidItem(pLastItem) ) + DELETEZ(pLastItem); + if ( pState && !IsInvalidItem(pState) ) + pLastItem = pState->Clone(); + else + pLastItem = 0; + eLastState = eState; + bItemDirty = sal_False; + } + + bCtrlDirty = sal_False; + DBG_PROFSTOP(SfxStateCacheSetState); +} + + +//-------------------------------------------------------------------- + +// alten Status in allen Controllern nochmal setzen + +void SfxStateCache::SetCachedState() +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxStateCache, 0); + DBG_ASSERT( pController, "Cache ohne ControllerItem" ); + DBG_ASSERT( pController->GetId()==nId, "Cache mit falschem ControllerItem" ); + DBG_PROFSTART(SfxStateCacheSetState); + + // nur updaten wenn cached item vorhanden und auch verarbeitbar + // (Wenn der State gesendet wird, mu\s sichergestellt sein, da\s ein + // Slotserver vorhanden ist, s. SfxControllerItem::GetCoreMetric() ) + if ( !bItemDirty && !bSlotDirty ) + { + // Controller updaten + for ( SfxControllerItem *pCtrl = pController; + pCtrl; + pCtrl = pCtrl->GetItemLink() ) + pCtrl->StateChanged( nId, eLastState, pLastItem ); + + // Controller sind jetzt ok + bCtrlDirty = sal_True; + } + + DBG_PROFSTOP(SfxStateCacheSetState); +} + + +//-------------------------------------------------------------------- + +// FloatingWindows in allen Controls mit dieser Id zerstoeren + +void SfxStateCache::DeleteFloatingWindows() +{ + DBG_MEMTEST(); + DBG_CHKTHIS(SfxStateCache, 0); + + SfxControllerItem *pNextCtrl=0; + for ( SfxControllerItem *pCtrl=pController; pCtrl; pCtrl=pNextCtrl ) + { + DBG_TRACE((ByteString("pCtrl: ").Append(ByteString::CreateFromInt32((sal_uInt32)pCtrl))).GetBuffer()); + pNextCtrl = pCtrl->GetItemLink(); + pCtrl->DeleteFloatingWindow(); + } +} + +sal_Bool SfxStateCache::UpdateDispatch( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > & xProv ) +{ + if ( bSlotDirty && xProv.is() ) + { + DBG_ASSERT( !pDispatch, "Altes Dispatch nicht entfernt!" ); + +//(mba)/compview + const SfxSlot* pSlot = 0;//SfxComponentViewShell::GetUnoSlot( nId ); + ::com::sun::star::util::URL aURL; + String aName( pSlot ? String::CreateFromAscii(pSlot->GetUnoName()) : String() ); + String aCmd; + if ( aName.Len() ) + { + aCmd = DEFINE_CONST_UNICODE(".uno:"); + aCmd += aName; + } + else + { + aCmd = DEFINE_CONST_UNICODE("slot:"); + aCmd += String::CreateFromInt32( nId ); + } + + aURL.Complete = aCmd; + Reference < XURLTransformer > xTrans( ::utl::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 = 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 = (SfxOfficeDispatch*)(nImplementation); + } + + if ( pDisp && !pDisp->IsInterceptDispatch() ) + return sal_False; + pDispatch = new BindDispatch_Impl( xDisp, aURL, this ); + pDispatch->acquire(); + bSlotDirty = sal_False; + bCtrlDirty = sal_True; + xDisp->addStatusListener( pDispatch, aURL ); + aSlotServ.SetSlot(0); + } + } + + return ( pDispatch != NULL ); +} + +::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > SfxStateCache::GetDispatch() const +{ + if ( pDispatch ) + return pDispatch->xDisp; + return ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > (); +} + +void SfxStateCache::Dispatch( sal_Bool bForceSynchron ) +{ + if ( pDispatch ) + pDispatch->Dispatch( bForceSynchron ); +} + + diff --git a/sfx2/source/control/unoctitm.cxx b/sfx2/source/control/unoctitm.cxx new file mode 100644 index 000000000000..ff821be8732f --- /dev/null +++ b/sfx2/source/control/unoctitm.cxx @@ -0,0 +1,560 @@ +/************************************************************************* + * + * $RCSfile: unoctitm.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:52:29 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <tools/debug.hxx> + +#ifndef _SFXENUMITEM_HXX //autogen +#include <svtools/eitem.hxx> +#endif +#ifndef _SFXSTRITEM_HXX //autogen +#include <svtools/stritem.hxx> +#endif +#include <svtools/intitem.hxx> +#include <svtools/itemset.hxx> + +#ifndef _COM_SUN_STAR_UTIL_XURLTRANSFORMER_HPP_ +#include <com/sun/star/util/XURLTransformer.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XCONTROLLER_HPP_ +#include <com/sun/star/frame/XController.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XFRAMEACTIONLISTENER_HPP_ +#include <com/sun/star/frame/XFrameActionListener.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XCOMPONENTLOADER_HPP_ +#include <com/sun/star/frame/XComponentLoader.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_XFRAME_HPP_ +#include <com/sun/star/frame/XFrame.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_FRAMEACTIONEVENT_HPP_ +#include <com/sun/star/frame/FrameActionEvent.hpp> +#endif +#ifndef _COM_SUN_STAR_FRAME_FRAMEACTION_HPP_ +#include <com/sun/star/frame/FrameAction.hpp> +#endif +#include <unotools/processfactory.hxx> + +#include "unoctitm.hxx" +#include "viewfrm.hxx" +#include "frame.hxx" +#include "ctrlitem.hxx" +#include "sfxuno.hxx" +#include "bindings.hxx" +#include "dispatch.hxx" +#include "sfxsids.hrc" + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +//long nOfficeDispatchCount = 0; + +SFX_IMPL_XINTERFACE_2( SfxUnoControllerItem, OWeakObject, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener ) +SFX_IMPL_XTYPEPROVIDER_2( SfxUnoControllerItem, ::com::sun::star::frame::XStatusListener, ::com::sun::star::lang::XEventListener ) + +SfxUnoControllerItem::SfxUnoControllerItem( SfxControllerItem *pItem, SfxBindings& rBind, const String& rCmd ) + : pCtrlItem( pItem ) + , pBindings( &rBind ) +{ + DBG_ASSERT( !pCtrlItem || !pCtrlItem->IsBound(), "ControllerItem fehlerhaft!" ); + + aCommand.Complete = rCmd; + Reference < XURLTransformer > xTrans( ::utl::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer" )), UNO_QUERY ); + xTrans->parseStrict( aCommand ); + pBindings->RegisterUnoController_Impl( this ); +} + +SfxUnoControllerItem::~SfxUnoControllerItem() +{ + // tell bindings to forget this controller ( if still connected ) + if ( pBindings ) + pBindings->ReleaseUnoController_Impl( this ); +} + +void SfxUnoControllerItem::UnBind() +{ + // connection to SfxControllerItem is lost + pCtrlItem = NULL; + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY ); + ReleaseDispatch(); +} + +void SAL_CALL SfxUnoControllerItem::statusChanged(const ::com::sun::star::frame::FeatureStateEvent& rEvent) throw ( ::com::sun::star::uno::RuntimeException ) +{ + DBG_ASSERT( pCtrlItem, "Dispatch hat den StatusListener nicht entfern!" ); + + if ( rEvent.Requery ) + { + // Fehler kann nur passieren, wenn das alte Dispatch fehlerhaft implementiert + // ist, also removeStatusListener nicht gefunzt hat. Aber sowas soll + // ja vorkommen ... + // Also besser vor ReleaseDispatch gegen Abflug sch"utzen! + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY ); + ReleaseDispatch(); + if ( pCtrlItem ) + GetNewDispatch(); // asynchron ?? + } + else if ( pCtrlItem ) + { + // pass new status to the SfxControllerItem + SfxItemState eState = SFX_ITEM_DISABLED; + SfxPoolItem* pItem = NULL; + if ( rEvent.IsEnabled ) + { + eState = SFX_ITEM_AVAILABLE; + ::com::sun::star::uno::Type pType = rEvent.State.getValueType(); + + if ( pType == ::getBooleanCppuType() ) + { + sal_Bool bTemp ; + rEvent.State >>= bTemp ; + pItem = new SfxBoolItem( pCtrlItem->GetId(), bTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt16*)0) ) + { + sal_uInt16 nTemp ; + rEvent.State >>= nTemp ; + pItem = new SfxUInt16Item( pCtrlItem->GetId(), nTemp ); + } + else if ( pType == ::getCppuType((const sal_uInt32*)0) ) + { + sal_uInt32 nTemp ; + rEvent.State >>= nTemp ; + pItem = new SfxUInt32Item( pCtrlItem->GetId(), nTemp ); + } + else if ( pType == ::getCppuType((const ::rtl::OUString*)0) ) + { + ::rtl::OUString sTemp ; + rEvent.State >>= sTemp ; + pItem = new SfxStringItem( pCtrlItem->GetId(), sTemp ); + } + else + pItem = new SfxVoidItem( pCtrlItem->GetId() ); + } + + pCtrlItem->StateChanged( pCtrlItem->GetId(), eState, pItem ); + delete pItem; + } +} + +void SAL_CALL SfxUnoControllerItem::disposing( const ::com::sun::star::lang::EventObject& rEvent ) throw ( ::com::sun::star::uno::RuntimeException ) +{ + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY ); + ReleaseDispatch(); +} + +void SfxUnoControllerItem::ReleaseDispatch() +{ + if ( xDispatch.is() ) + { + xDispatch->removeStatusListener( (::com::sun::star::frame::XStatusListener*) this, aCommand ); + xDispatch = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > (); + } +} + +void SfxUnoControllerItem::GetNewDispatch() +{ + if ( !pBindings ) + { + // Bindings released + DBG_ERROR( "Tried to get dispatch, but no Bindings!" ); + return; + } + + // forget old dispatch + xDispatch = ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > (); + + // no arms, no cookies ! + if ( !pBindings->GetDispatcher_Impl() || !pBindings->GetDispatcher_Impl()->GetFrame() ) + return; + + SfxFrame *pFrame = pBindings->GetDispatcher_Impl()->GetFrame()->GetFrame(); + SfxFrame *pParent = pFrame->GetParentFrame(); + if ( pParent ) + // parent may intercept + xDispatch = TryGetDispatch( pParent ); + + if ( !xDispatch.is() ) + { + // no interception + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame = pFrame->GetFrameInterface(); + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv( xFrame, ::com::sun::star::uno::UNO_QUERY ); + if ( xProv.is() ) + xDispatch = xProv->queryDispatch( aCommand, ::rtl::OUString(), 0 ); + } + + if ( xDispatch.is() ) + xDispatch->addStatusListener( (::com::sun::star::frame::XStatusListener*) this, aCommand ); + else if ( pCtrlItem ) + pCtrlItem->StateChanged( pCtrlItem->GetId(), SFX_ITEM_DISABLED, NULL ); +} + +::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > SfxUnoControllerItem::TryGetDispatch( SfxFrame *pFrame ) +{ + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDisp; + SfxFrame *pParent = pFrame->GetParentFrame(); + if ( pParent ) + // parent may intercept + xDisp = TryGetDispatch( pParent ); + + // only components may intercept + if ( !xDisp.is() && pFrame->HasComponent() ) + { + // no interception + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame = pFrame->GetFrameInterface(); + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatchProvider > xProv( xFrame, ::com::sun::star::uno::UNO_QUERY ); + if ( xProv.is() ) + xDisp = xProv->queryDispatch( aCommand, ::rtl::OUString(), 0 ); + } + + return xDisp; +} + +void SfxUnoControllerItem::Execute() +{ + // dispatch the resource + if ( xDispatch.is() ) + xDispatch->dispatch( aCommand, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >() ); +} + +void SfxUnoControllerItem::ReleaseBindings() +{ + // connection to binding is lost; so forget the binding and the dispatch + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > aRef( (::cppu::OWeakObject*)this, ::com::sun::star::uno::UNO_QUERY ); + ReleaseDispatch(); + if ( pBindings ) + pBindings->ReleaseUnoController_Impl( this ); + pBindings = NULL; +} + +void SfxStatusDispatcher::ReleaseAll() +{ + ::com::sun::star::lang::EventObject aObject; + aObject.Source = (::cppu::OWeakObject*) this; + aListeners.disposeAndClear( aObject ); +} + +void SAL_CALL SfxStatusDispatcher::dispatch( const ::com::sun::star::util::URL&, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& ) throw ( ::com::sun::star::uno::RuntimeException ) +{ +} + +SFX_IMPL_XINTERFACE_1( SfxStatusDispatcher, OWeakObject, ::com::sun::star::frame::XDispatch ) +SFX_IMPL_XTYPEPROVIDER_1( SfxStatusDispatcher, ::com::sun::star::frame::XDispatch ) +//IMPLNAME "com.sun.star.comp.sfx2.StatusDispatcher", + +SfxStatusDispatcher::SfxStatusDispatcher() + : aListeners( aMutex ) +{ +} + +void SAL_CALL SfxStatusDispatcher::addStatusListener(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > & aListener, const ::com::sun::star::util::URL& aURL) throw ( ::com::sun::star::uno::RuntimeException ) +{ + aListeners.addInterface( aURL.Complete, aListener ); + if ( aURL.Complete.compareToAscii(".uno:LifeTime")==0 ) + { + ::com::sun::star::frame::FeatureStateEvent aEvent; + aEvent.FeatureURL = aURL; + aEvent.Source = (::com::sun::star::frame::XDispatch*) this; + aEvent.IsEnabled = sal_True; + aEvent.Requery = sal_False; + aListener->statusChanged( aEvent ); + } +} + +void SAL_CALL SfxStatusDispatcher::removeStatusListener( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > & aListener, const ::com::sun::star::util::URL& aURL ) throw ( ::com::sun::star::uno::RuntimeException ) +{ + aListeners.removeInterface( aURL.Complete, aListener ); +} + +SFX_IMPL_XINTERFACE_1( SfxOfficeDispatch, SfxStatusDispatcher, ::com::sun::star::lang::XUnoTunnel ) +SFX_IMPL_XTYPEPROVIDER_2( SfxOfficeDispatch, ::com::sun::star::frame::XDispatch, ::com::sun::star::lang::XUnoTunnel ) + + +//------------------------------------------------------------------------- +// XUnoTunnel +sal_Int64 SAL_CALL SfxOfficeDispatch::getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException) +{ + if ( aIdentifier == impl_getStaticIdentifier() ) + return (sal_Int64)this; + else + return 0; +} + +/* ASDBG +void* SfxOfficeDispatch::getImplementation(Reflection *p) +{ + if( p == ::getCppuType((const SfxOfficeDispatch*)0) ) + return this; + else + return ::cppu::OWeakObject::getImplementation(p); + +} + +Reflection* ::getCppuType((const SfxOfficeDispatch*)0) +{ + static StandardClassReflection aRefl( + 0, + createStandardClass( + "SfxOfficeDispatch", ::cppu::OWeakObject::get::cppu::OWeakObjectIdlClass(), + 1, + ::getCppuType((const ::com::sun::star::frame::XDispatch*)0) ) ); + return &aRefl; +} +*/ + +SfxOfficeDispatch::SfxOfficeDispatch( SfxBindings& rBindings, SfxDispatcher* pDispat, sal_uInt16 nSlotId, const ::com::sun::star::util::URL& rURL, sal_Bool bInter ) + : bIntercept( bInter ) +{ +// nOfficeDispatchCount++; + + // this object is an adapter that shows a ::com::sun::star::frame::XDispatch-Interface to the outside and uses a SfxControllerItem to monitor a state + pControllerItem = new SfxDispatchController_Impl( this, rBindings, pDispat, nSlotId, rURL, bInter ); +} + +SfxOfficeDispatch::~SfxOfficeDispatch() +{ +// --nOfficeDispatchCount; + + if ( pControllerItem ) + { + // when dispatch object is released, destroy its connection to this object and destroy it + pControllerItem->UnBindController(); + delete pControllerItem; + } +} + +void SAL_CALL SfxOfficeDispatch::dispatch( const ::com::sun::star::util::URL& aURL, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs ) throw ( ::com::sun::star::uno::RuntimeException ) +{ + // ControllerItem is the Impl class + if ( pControllerItem ) + pControllerItem->dispatch( aURL, aArgs ); +} + +void SAL_CALL SfxOfficeDispatch::addStatusListener(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > & aListener, const ::com::sun::star::util::URL& aURL) throw ( ::com::sun::star::uno::RuntimeException ) +{ + GetListeners().addInterface( aURL.Complete, aListener ); + if ( pControllerItem ) + { + // ControllerItem is the Impl class + pControllerItem->addStatusListener( aListener, aURL ); + } +} + +SfxDispatcher* SfxOfficeDispatch::GetDispatcher_Impl() +{ + return pControllerItem->GetDispatcher(); +} + +SfxDispatchController_Impl::SfxDispatchController_Impl( SfxOfficeDispatch* pDisp, SfxBindings& rBindings, SfxDispatcher* pDispat, sal_uInt16 nSlotId, const ::com::sun::star::util::URL& rURL, sal_Bool bInter ) + : pDispatch( pDisp ) + , aDispatchURL( rURL ) + , pBindings( &rBindings ) + , pDispatcher( pDispat ) + , pLastState( 0 ) + , nSlot( nSlotId ) +{ +} + +SfxDispatchController_Impl::~SfxDispatchController_Impl() +{ + if ( pLastState && !IsInvalidItem( pLastState ) ) + delete pLastState; + + if ( pDispatch ) + { + // disconnect + pDispatch->pControllerItem = NULL; + + // force all listeners to release the dispatch object + ::com::sun::star::lang::EventObject aObject; + aObject.Source = (::cppu::OWeakObject*) pDispatch; + pDispatch->GetListeners().disposeAndClear( aObject ); + } +} + +void SfxDispatchController_Impl::UnBindController() +{ + pDispatch = NULL; + if ( IsBound() ) + { + GetBindings().ENTERREGISTRATIONS(); + SfxControllerItem::UnBind(); + GetBindings().LEAVEREGISTRATIONS(); + } +} + +void SAL_CALL SfxDispatchController_Impl::dispatch( const ::com::sun::star::util::URL& aURL, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs ) throw ( ::com::sun::star::uno::RuntimeException ) +{ + if ( pDispatch && aURL == aDispatchURL ) + { + if ( !GetId() ) + { + pBindings->ENTERREGISTRATIONS(); + Bind( nSlot, pBindings ); + pBindings->LEAVEREGISTRATIONS(); + } + + SfxAllItemSet aSet( SFX_APP()->GetPool() ); + TransformParameters( GetId(), aArgs, aSet ); + aSet.Put( SfxBoolItem( SID_INTERCEPTOR, sal_False ) ); + if ( !pDispatcher ) + pDispatcher = GetBindings().GetDispatcher_Impl(); + + SfxCallMode nCall = SFX_CALLMODE_SLOT; + sal_uInt16 nCount = aArgs.getLength(); + const ::com::sun::star::beans::PropertyValue* pPropsVal = aArgs.getConstArray(); + for ( sal_uInt16 n=0; n<nCount; n++ ) + { + const ::com::sun::star::beans::PropertyValue& rProp = pPropsVal[n]; + String aName = rProp.Name; + sal_Bool bTemp ; + if ( aName.EqualsAscii("SynchronMode") && (rProp.Value >>= bTemp) ) + { + nCall = SFX_CALLMODE_SYNCHRON; + break; + } + } + pDispatcher->Execute( GetId(), nCall, aSet ); + } +} + +SfxDispatcher* SfxDispatchController_Impl::GetDispatcher() +{ + if ( !pDispatcher ) + pDispatcher = GetBindings().GetDispatcher_Impl(); + return pDispatcher; +} + +void SAL_CALL SfxDispatchController_Impl::addStatusListener(const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XStatusListener > & aListener, const ::com::sun::star::util::URL& aURL) throw ( ::com::sun::star::uno::RuntimeException ) +{ + if ( !pDispatch ) + return; + + if ( !GetId() ) + { + pBindings->ENTERREGISTRATIONS(); + Bind( nSlot, pBindings ); + pBindings->LEAVEREGISTRATIONS(); + } + + const SfxPoolItem *pItem = 0; + if ( !pDispatcher ) + pDispatcher = GetBindings().GetDispatcher_Impl(); + SfxItemState eState = pDispatcher->QueryState( GetId(), pItem ); + ::com::sun::star::uno::Any aState; + if ( pItem ) + pItem->QueryValue( aState ); + + ::com::sun::star::frame::FeatureStateEvent aEvent; + aEvent.FeatureURL = aURL; + aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch; + aEvent.IsEnabled = eState != SFX_ITEM_DISABLED; + aEvent.Requery = sal_False; + aEvent.State = aState; + + aListener->statusChanged( aEvent ); +} + +void SfxDispatchController_Impl::StateChanged( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) +{ + if ( !pDispatch ) + return; + + if ( pDispatch->IsInterceptDispatch() ) + { + // If this Controller is made for an interception, the state can't be set from outside + // because this would be the state of the interceptor itself! + if ( !pDispatcher ) + pDispatcher = GetBindings().GetDispatcher_Impl(); + eState = pDispatcher->QueryState( GetId(), pState ); + } + + // Bindings instance notifies controller about a state change, listeners must be notified also + sal_Bool bNotify = sal_True; + sal_Bool bBothAvailable = pLastState && pState && !IsInvalidItem(pLastState) && !IsInvalidItem(pState); + if ( bBothAvailable ) + bNotify = pState->Type() != pLastState->Type() || *pState != *pLastState; + else + bNotify = ( pLastState != pState ); + if ( pLastState && !IsInvalidItem( pLastState ) ) + delete pLastState; + pLastState = ( pState && !IsInvalidItem(pState) ) ? pState->Clone() : pState; + + ::cppu::OInterfaceContainerHelper* pContnr = pDispatch->GetListeners().getContainer ( aDispatchURL.Complete ); + if ( bNotify && pContnr ) + { + ::com::sun::star::uno::Any aState; + if ( pState ) + pState->QueryValue( aState ); + + ::com::sun::star::frame::FeatureStateEvent aEvent; + aEvent.FeatureURL = aDispatchURL; + aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch; + aEvent.IsEnabled = eState != SFX_ITEM_DISABLED; + aEvent.Requery = sal_False; + aEvent.State = aState; + + ::cppu::OInterfaceIteratorHelper aIt( *pContnr ); + while( aIt.hasMoreElements() ) + ((::com::sun::star::frame::XStatusListener *)aIt.next())->statusChanged( aEvent ); + } +} + + |