/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_basic.hxx" #include #include #include #include #include "sbxres.hxx" #include TYPEINIT1(SbxMethod,SbxVariable) TYPEINIT1(SbxProperty,SbxVariable) TYPEINIT2(SbxObject,SbxVariable,SfxListener) static const char* pNameProp; // Name-Property static const char* pParentProp; // Parent-Property static sal_uInt16 nNameHash = 0, nParentHash = 0; ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// SbxObject::SbxObject( const XubString& rClass ) : SbxVariable( SbxOBJECT ), aClassName( rClass ) { aData.pObj = this; if( !nNameHash ) { pNameProp = GetSbxRes( STRING_NAMEPROP ); pParentProp = GetSbxRes( STRING_PARENTPROP ); nNameHash = MakeHashCode( String::CreateFromAscii( pNameProp ) ); nParentHash = MakeHashCode( String::CreateFromAscii( pParentProp ) ); } SbxObject::Clear(); SbxObject::SetName( rClass ); } SbxObject::SbxObject( const SbxObject& rObj ) : SvRefBase( rObj ), SbxVariable( rObj.GetType() ), SfxListener( rObj ) { *this = rObj; } SbxObject& SbxObject::operator=( const SbxObject& r ) { if( &r != this ) { SbxVariable::operator=( r ); aClassName = r.aClassName; pMethods = new SbxArray; pProps = new SbxArray; pObjs = new SbxArray( SbxOBJECT ); // Die Arrays werden kopiert, die Inhalte uebernommen *pMethods = *r.pMethods; *pProps = *r.pProps; *pObjs = *r.pObjs; // Da die Variablen uebernommen wurden, ist dies OK pDfltProp = r.pDfltProp; SetName( r.GetName() ); SetFlags( r.GetFlags() ); SetModified( sal_True ); } return *this; } static void CheckParentsOnDelete( SbxObject* pObj, SbxArray* p ) { for( sal_uInt16 i = 0; i < p->Count(); i++ ) { SbxVariableRef& rRef = p->GetRef( i ); if( rRef->IsBroadcaster() ) pObj->EndListening( rRef->GetBroadcaster(), sal_True ); // Hat das Element mehr als eine Referenz und noch einen Listener? if( rRef->GetRefCount() > 1 ) { rRef->SetParent( NULL ); DBG_ASSERT( !rRef->IsBroadcaster() || rRef->GetBroadcaster().GetListenerCount(), "Object element with dangling parent" ); } } } SbxObject::~SbxObject() { CheckParentsOnDelete( this, pProps ); CheckParentsOnDelete( this, pMethods ); CheckParentsOnDelete( this, pObjs ); // avoid handling in ~SbxVariable as SBX_DIM_AS_NEW == SBX_GBLSEARCH ResetFlag( SBX_DIM_AS_NEW ); } SbxDataType SbxObject::GetType() const { return SbxOBJECT; } SbxClassType SbxObject::GetClass() const { return SbxCLASS_OBJECT; } void SbxObject::Clear() { pMethods = new SbxArray; pProps = new SbxArray; pObjs = new SbxArray( SbxOBJECT ); SbxVariable* p; p = Make( String::CreateFromAscii( pNameProp ), SbxCLASS_PROPERTY, SbxSTRING ); p->SetFlag( SBX_DONTSTORE ); p = Make( String::CreateFromAscii( pParentProp ), SbxCLASS_PROPERTY, SbxOBJECT ); p->ResetFlag( SBX_WRITE ); p->SetFlag( SBX_DONTSTORE ); pDfltProp = NULL; SetModified( sal_False ); } void SbxObject::SFX_NOTIFY( SfxBroadcaster&, const TypeId&, const SfxHint& rHint, const TypeId& ) { const SbxHint* p = PTR_CAST(SbxHint,&rHint); if( p ) { sal_uIntPtr nId = p->GetId(); sal_Bool bRead = sal_Bool( nId == SBX_HINT_DATAWANTED ); sal_Bool bWrite = sal_Bool( nId == SBX_HINT_DATACHANGED ); SbxVariable* pVar = p->GetVar(); if( bRead || bWrite ) { XubString aVarName( pVar->GetName() ); sal_uInt16 nHash_ = MakeHashCode( aVarName ); if( nHash_ == nNameHash && aVarName.EqualsIgnoreCaseAscii( pNameProp ) ) { if( bRead ) pVar->PutString( GetName() ); else SetName( pVar->GetString() ); } else if( nHash_ == nParentHash && aVarName.EqualsIgnoreCaseAscii( pParentProp ) ) { SbxObject* p_ = GetParent(); if( !p_ ) p_ = this; pVar->PutObject( p_ ); } } } } sal_Bool SbxObject::IsClass( const XubString& rName ) const { return sal_Bool( aClassName.EqualsIgnoreCaseAscii( rName ) ); } SbxVariable* SbxObject::FindUserData( sal_uInt32 nData ) { if( !GetAll( SbxCLASS_DONTCARE ) ) return NULL; SbxVariable* pRes = pMethods->FindUserData( nData ); if( !pRes ) pRes = pProps->FindUserData( nData ); if( !pRes ) pRes = pObjs->FindUserData( nData ); // Search in den Parents? if( !pRes && IsSet( SBX_GBLSEARCH ) ) { SbxObject* pCur = this; while( !pRes && pCur->pParent ) { // Ich selbst bin schon durchsucht worden! sal_uInt16 nOwn = pCur->GetFlags(); pCur->ResetFlag( SBX_EXTSEARCH ); // Ich suche bereits global! sal_uInt16 nPar = pCur->pParent->GetFlags(); pCur->pParent->ResetFlag( SBX_GBLSEARCH ); pRes = pCur->pParent->FindUserData( nData ); pCur->SetFlags( nOwn ); pCur->pParent->SetFlags( nPar ); pCur = pCur->pParent; } } return pRes; } SbxVariable* SbxObject::Find( const XubString& rName, SbxClassType t ) { #ifdef DBG_UTIL static sal_uInt16 nLvl = 0; static const char* pCls[] = { "DontCare","Array","Value","Variable","Method","Property","Object" }; ByteString aNameStr1( (const UniString&)rName, RTL_TEXTENCODING_ASCII_US ); ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); DbgOutf( "SBX: Search %.*s %s %s in %s", nLvl++, " ", ( t >= SbxCLASS_DONTCARE && t <= SbxCLASS_OBJECT ) ? pCls[ t-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() ); #endif if( !GetAll( t ) ) return NULL; SbxVariable* pRes = NULL; pObjs->SetFlag( SBX_EXTSEARCH ); if( t == SbxCLASS_DONTCARE ) { pRes = pMethods->Find( rName, SbxCLASS_METHOD ); if( !pRes ) pRes = pProps->Find( rName, SbxCLASS_PROPERTY ); if( !pRes ) pRes = pObjs->Find( rName, t ); } else { SbxArray* pArray = NULL; switch( t ) { case SbxCLASS_VARIABLE: case SbxCLASS_PROPERTY: pArray = pProps; break; case SbxCLASS_METHOD: pArray = pMethods; break; case SbxCLASS_OBJECT: pArray = pObjs; break; default: DBG_ASSERT( sal_False, "Invalid SBX class" ); } if( pArray ) pRes = pArray->Find( rName, t ); } // Extended Search im Objekt-Array? // Fuer Objekte und DontCare ist das Objektarray bereits // durchsucht worden if( !pRes && ( t == SbxCLASS_METHOD || t == SbxCLASS_PROPERTY ) ) pRes = pObjs->Find( rName, t ); // Search in den Parents? if( !pRes && IsSet( SBX_GBLSEARCH ) ) { SbxObject* pCur = this; while( !pRes && pCur->pParent ) { // Ich selbst bin schon durchsucht worden! sal_uInt16 nOwn = pCur->GetFlags(); pCur->ResetFlag( SBX_EXTSEARCH ); // Ich suche bereits global! sal_uInt16 nPar = pCur->pParent->GetFlags(); pCur->pParent->ResetFlag( SBX_GBLSEARCH ); pRes = pCur->pParent->Find( rName, t ); pCur->SetFlags( nOwn ); pCur->pParent->SetFlags( nPar ); pCur = pCur->pParent; } } #ifdef DBG_UTIL nLvl--; if( pRes ) { ByteString aNameStr3( (const UniString&)rName, RTL_TEXTENCODING_ASCII_US ); ByteString aNameStr4( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); DbgOutf( "SBX: Found %.*s %s in %s", nLvl, " ", aNameStr3.GetBuffer(), aNameStr4.GetBuffer() ); } #endif return pRes; } // Kurzform: Die Parent-Kette wird durchsucht // Das ganze rekursiv, da Call() ueberladen sein kann // Qualified Names sind zugelassen sal_Bool SbxObject::Call( const XubString& rName, SbxArray* pParam ) { SbxVariable* pMeth = FindQualified( rName, SbxCLASS_DONTCARE); if( pMeth && pMeth->ISA(SbxMethod) ) { // FindQualified() koennte schon zugeschlagen haben! if( pParam ) pMeth->SetParameters( pParam ); pMeth->Broadcast( SBX_HINT_DATAWANTED ); pMeth->SetParameters( NULL ); return sal_True; } SetError( SbxERR_NO_METHOD ); return sal_False; } SbxProperty* SbxObject::GetDfltProperty() { if ( !pDfltProp && aDfltPropName.Len() ) { pDfltProp = (SbxProperty*) Find( aDfltPropName, SbxCLASS_PROPERTY ); if( !pDfltProp ) pDfltProp = (SbxProperty*) Make( aDfltPropName, SbxCLASS_PROPERTY, SbxVARIANT ); } return pDfltProp; } void SbxObject::SetDfltProperty( const XubString& rName ) { if ( rName != aDfltPropName ) pDfltProp = NULL; aDfltPropName = rName; SetModified( sal_True ); } void SbxObject::SetDfltProperty( SbxProperty* p ) { if( p ) { sal_uInt16 n; SbxArray* pArray = FindVar( p, n ); pArray->Put( p, n ); if( p->GetParent() != this ) p->SetParent( this ); Broadcast( SBX_HINT_OBJECTCHANGED ); } pDfltProp = p; SetModified( sal_True ); } // Suchen einer bereits vorhandenen Variablen. Falls sie gefunden wurde, // wird der Index gesetzt, sonst wird der Count des Arrays geliefert. // In jedem Fall wird das korrekte Array geliefert. SbxArray* SbxObject::FindVar( SbxVariable* pVar, sal_uInt16& nArrayIdx ) { SbxArray* pArray = NULL; if( pVar ) switch( pVar->GetClass() ) { case SbxCLASS_VARIABLE: case SbxCLASS_PROPERTY: pArray = pProps; break; case SbxCLASS_METHOD: pArray = pMethods; break; case SbxCLASS_OBJECT: pArray = pObjs; break; default: DBG_ASSERT( sal_False, "Invalid SBX class" ); } if( pArray ) { nArrayIdx = pArray->Count(); // ist die Variable per Name vorhanden? pArray->ResetFlag( SBX_EXTSEARCH ); SbxVariable* pOld = pArray->Find( pVar->GetName(), pVar->GetClass() ); if( pOld ) for( sal_uInt16 i = 0; i < pArray->Count(); i++ ) { SbxVariableRef& rRef = pArray->GetRef( i ); if( (SbxVariable*) rRef == pOld ) { nArrayIdx = i; break; } } } return pArray; } // Falls ein neues Objekt eingerichtet wird, wird es, falls es bereits // eines mit diesem Namen gibt, indiziert. SbxVariable* SbxObject::Make( const XubString& rName, SbxClassType ct, SbxDataType dt, bool bIsRuntimeFunction ) { // Ist das Objekt bereits vorhanden? SbxArray* pArray = NULL; switch( ct ) { case SbxCLASS_VARIABLE: case SbxCLASS_PROPERTY: pArray = pProps; break; case SbxCLASS_METHOD: pArray = pMethods; break; case SbxCLASS_OBJECT: pArray = pObjs; break; default: DBG_ASSERT( sal_False, "Invalid SBX class" ); } if( !pArray ) return NULL; // Collections duerfen gleichnamige Objekte enthalten if( !( ct == SbxCLASS_OBJECT && ISA(SbxCollection) ) ) { SbxVariable* pRes = pArray->Find( rName, ct ); if( pRes ) { /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus #ifdef DBG_UTIL if( pRes->GetHashCode() != nNameHash && pRes->GetHashCode() != nParentHash ) { XubString aMsg( "SBX-Element \"" ); aMsg += pRes->GetName(); aMsg += "\"\n in Objekt \""; aMsg += GetName(); aMsg += "\" bereits vorhanden"; DbgError( (const char*)aMsg.GetStr() ); } #endif */ return pRes; } } SbxVariable* pVar = NULL; switch( ct ) { case SbxCLASS_VARIABLE: case SbxCLASS_PROPERTY: pVar = new SbxProperty( rName, dt ); break; case SbxCLASS_METHOD: pVar = new SbxMethod( rName, dt, bIsRuntimeFunction ); break; case SbxCLASS_OBJECT: pVar = CreateObject( rName ); break; default: break; } pVar->SetParent( this ); pArray->Put( pVar, pArray->Count() ); SetModified( sal_True ); // Das Objekt lauscht immer StartListening( pVar->GetBroadcaster(), sal_True ); Broadcast( SBX_HINT_OBJECTCHANGED ); return pVar; } SbxObject* SbxObject::MakeObject( const XubString& rName, const XubString& rClass ) { // Ist das Objekt bereits vorhanden? if( !ISA(SbxCollection) ) { SbxVariable* pRes = pObjs->Find( rName, SbxCLASS_OBJECT ); if( pRes ) { /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus #ifdef DBG_UTIL if( pRes->GetHashCode() != nNameHash && pRes->GetHashCode() != nParentHash ) { XubString aMsg( "SBX-Objekt \"" ); aMsg += pRes->GetName(); aMsg += "\"\n in Objekt \""; aMsg += GetName(); aMsg += "\" bereits vorhanden"; DbgError( (const char*)aMsg.GetStr() ); } #endif */ return PTR_CAST(SbxObject,pRes); } } SbxObject* pVar = CreateObject( rClass ); if( pVar ) { pVar->SetName( rName ); pVar->SetParent( this ); pObjs->Put( pVar, pObjs->Count() ); SetModified( sal_True ); // Das Objekt lauscht immer StartListening( pVar->GetBroadcaster(), sal_True ); Broadcast( SBX_HINT_OBJECTCHANGED ); } return pVar; } void SbxObject::Insert( SbxVariable* pVar ) { sal_uInt16 nIdx; SbxArray* pArray = FindVar( pVar, nIdx ); if( pArray ) { // Hinein damit. Man sollte allerdings auf die Pointer aufpassen! if( nIdx < pArray->Count() ) { // dann gibt es dieses Element bereits // Bei Collections duerfen gleichnamige Objekte hinein if( pArray == pObjs && ISA(SbxCollection) ) nIdx = pArray->Count(); else { SbxVariable* pOld = pArray->Get( nIdx ); // schon drin: ueberschreiben if( pOld == pVar ) return; /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus #ifdef DBG_UTIL if( pOld->GetHashCode() != nNameHash && pOld->GetHashCode() != nParentHash ) { XubString aMsg( "SBX-Element \"" ); aMsg += pVar->GetName(); aMsg += "\"\n in Objekt \""; aMsg += GetName(); aMsg += "\" bereits vorhanden"; DbgError( (const char*)aMsg.GetStr() ); } #endif */ EndListening( pOld->GetBroadcaster(), sal_True ); if( pVar->GetClass() == SbxCLASS_PROPERTY ) { if( pOld == pDfltProp ) pDfltProp = (SbxProperty*) pVar; } } } StartListening( pVar->GetBroadcaster(), sal_True ); pArray->Put( pVar, nIdx ); if( pVar->GetParent() != this ) pVar->SetParent( this ); SetModified( sal_True ); Broadcast( SBX_HINT_OBJECTCHANGED ); #ifdef DBG_UTIL static const char* pCls[] = { "DontCare","Array","Value","Variable","Method","Property","Object" }; XubString aVarName( pVar->GetName() ); if ( !aVarName.Len() && pVar->ISA(SbxObject) ) aVarName = PTR_CAST(SbxObject,pVar)->GetClassName(); ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US ); ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); DbgOutf( "SBX: Insert %s %s in %s", ( pVar->GetClass() >= SbxCLASS_DONTCARE && pVar->GetClass() <= SbxCLASS_OBJECT ) ? pCls[ pVar->GetClass()-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() ); #endif } } // AB 23.4.1997, Optimierung, Einfuegen ohne Ueberpruefung auf doppelte // Eintraege und ohne Broadcasts, wird nur in SO2/auto.cxx genutzt void SbxObject::QuickInsert( SbxVariable* pVar ) { SbxArray* pArray = NULL; if( pVar ) { switch( pVar->GetClass() ) { case SbxCLASS_VARIABLE: case SbxCLASS_PROPERTY: pArray = pProps; break; case SbxCLASS_METHOD: pArray = pMethods; break; case SbxCLASS_OBJECT: pArray = pObjs; break; default: DBG_ASSERT( sal_False, "Invalid SBX class" ); } } if( pArray ) { StartListening( pVar->GetBroadcaster(), sal_True ); pArray->Put( pVar, pArray->Count() ); if( pVar->GetParent() != this ) pVar->SetParent( this ); SetModified( sal_True ); #ifdef DBG_UTIL static const char* pCls[] = { "DontCare","Array","Value","Variable","Method","Property","Object" }; XubString aVarName( pVar->GetName() ); if ( !aVarName.Len() && pVar->ISA(SbxObject) ) aVarName = PTR_CAST(SbxObject,pVar)->GetClassName(); ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US ); ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); DbgOutf( "SBX: Insert %s %s in %s", ( pVar->GetClass() >= SbxCLASS_DONTCARE && pVar->GetClass() <= SbxCLASS_OBJECT ) ? pCls[ pVar->GetClass()-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() ); #endif } } // AB 23.3.1997, Spezial-Methode, gleichnamige Controls zulassen void SbxObject::VCPtrInsert( SbxVariable* pVar ) { SbxArray* pArray = NULL; if( pVar ) { switch( pVar->GetClass() ) { case SbxCLASS_VARIABLE: case SbxCLASS_PROPERTY: pArray = pProps; break; case SbxCLASS_METHOD: pArray = pMethods; break; case SbxCLASS_OBJECT: pArray = pObjs; break; default: DBG_ASSERT( sal_False, "Invalid SBX class" ); } } if( pArray ) { StartListening( pVar->GetBroadcaster(), sal_True ); pArray->Put( pVar, pArray->Count() ); if( pVar->GetParent() != this ) pVar->SetParent( this ); SetModified( sal_True ); Broadcast( SBX_HINT_OBJECTCHANGED ); } } void SbxObject::Remove( const XubString& rName, SbxClassType t ) { Remove( SbxObject::Find( rName, t ) ); } void SbxObject::Remove( SbxVariable* pVar ) { sal_uInt16 nIdx; SbxArray* pArray = FindVar( pVar, nIdx ); if( pArray && nIdx < pArray->Count() ) { #ifdef DBG_UTIL XubString aVarName( pVar->GetName() ); if ( !aVarName.Len() && pVar->ISA(SbxObject) ) aVarName = PTR_CAST(SbxObject,pVar)->GetClassName(); ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US ); ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); #endif SbxVariableRef pVar_ = pArray->Get( nIdx ); if( pVar_->IsBroadcaster() ) EndListening( pVar_->GetBroadcaster(), sal_True ); if( (SbxVariable*) pVar_ == pDfltProp ) pDfltProp = NULL; pArray->Remove( nIdx ); if( pVar_->GetParent() == this ) pVar_->SetParent( NULL ); SetModified( sal_True ); Broadcast( SBX_HINT_OBJECTCHANGED ); } } // AB 23.3.1997, Loeschen per Pointer fuer Controls (doppelte Namen!) void SbxObject::VCPtrRemove( SbxVariable* pVar ) { sal_uInt16 nIdx; // Neu FindVar-Methode, sonst identisch mit normaler Methode SbxArray* pArray = VCPtrFindVar( pVar, nIdx ); if( pArray && nIdx < pArray->Count() ) { SbxVariableRef xVar = pArray->Get( nIdx ); if( xVar->IsBroadcaster() ) EndListening( xVar->GetBroadcaster(), sal_True ); if( (SbxVariable*) xVar == pDfltProp ) pDfltProp = NULL; pArray->Remove( nIdx ); if( xVar->GetParent() == this ) xVar->SetParent( NULL ); SetModified( sal_True ); Broadcast( SBX_HINT_OBJECTCHANGED ); } } // AB 23.3.1997, Zugehoerige Spezial-Methode, nur ueber Pointer suchen SbxArray* SbxObject::VCPtrFindVar( SbxVariable* pVar, sal_uInt16& nArrayIdx ) { SbxArray* pArray = NULL; if( pVar ) switch( pVar->GetClass() ) { case SbxCLASS_VARIABLE: case SbxCLASS_PROPERTY: pArray = pProps; break; case SbxCLASS_METHOD: pArray = pMethods; break; case SbxCLASS_OBJECT: pArray = pObjs; break; default: DBG_ASSERT( sal_False, "Invalid SBX class" ); } if( pArray ) { nArrayIdx = pArray->Count(); for( sal_uInt16 i = 0; i < pArray->Count(); i++ ) { SbxVariableRef& rRef = pArray->GetRef( i ); if( (SbxVariable*) rRef == pVar ) { nArrayIdx = i; break; } } } return pArray; } void SbxObject::SetPos( SbxVariable* pVar, sal_uInt16 nPos ) { sal_uInt16 nIdx; SbxArray* pArray = FindVar( pVar, nIdx ); if( pArray ) { if( nPos >= pArray->Count() ) nPos = pArray->Count() - 1; if( nIdx < ( pArray->Count() - 1 ) ) { SbxVariableRef refVar = pArray->Get( nIdx ); pArray->Remove( nIdx ); pArray->Insert( refVar, nPos ); } } // SetModified( sal_True ); // Broadcast( SBX_HINT_OBJECTCHANGED ); } static sal_Bool LoadArray( SvStream& rStrm, SbxObject* pThis, SbxArray* pArray ) { SbxArrayRef p = (SbxArray*) SbxBase::Load( rStrm ); if( !p.Is() ) return sal_False; for( sal_uInt16 i = 0; i < p->Count(); i++ ) { SbxVariableRef& r = p->GetRef( i ); SbxVariable* pVar = r; if( pVar ) { pVar->SetParent( pThis ); pThis->StartListening( pVar->GetBroadcaster(), sal_True ); } } pArray->Merge( p ); return sal_True; } // Der Load eines Objekts ist additiv! sal_Bool SbxObject::LoadData( SvStream& rStrm, sal_uInt16 nVer ) { // Hilfe fuer das Einlesen alter Objekte: einfach sal_True zurueck, // LoadPrivateData() muss Default-Zustand herstellen if( !nVer ) return sal_True; pDfltProp = NULL; if( !SbxVariable::LoadData( rStrm, nVer ) ) return sal_False; // Wenn kein fremdes Objekt enthalten ist, uns selbst eintragen if( aData.eType == SbxOBJECT && !aData.pObj ) aData.pObj = this; sal_uInt32 nSize; XubString aDfltProp; rStrm.ReadByteString( aClassName, RTL_TEXTENCODING_ASCII_US ); rStrm.ReadByteString( aDfltProp, RTL_TEXTENCODING_ASCII_US ); sal_uIntPtr nPos = rStrm.Tell(); rStrm >> nSize; if( !LoadPrivateData( rStrm, nVer ) ) return sal_False; sal_uIntPtr nNewPos = rStrm.Tell(); nPos += nSize; DBG_ASSERT( nPos >= nNewPos, "SBX: Zu viele Daten eingelesen" ); if( nPos != nNewPos ) rStrm.Seek( nPos ); if( !LoadArray( rStrm, this, pMethods ) || !LoadArray( rStrm, this, pProps ) || !LoadArray( rStrm, this, pObjs ) ) return sal_False; // Properties setzen if( aDfltProp.Len() ) pDfltProp = (SbxProperty*) pProps->Find( aDfltProp, SbxCLASS_PROPERTY ); SetModified( sal_False ); return sal_True; } sal_Bool SbxObject::StoreData( SvStream& rStrm ) const { if( !SbxVariable::StoreData( rStrm ) ) return sal_False; XubString aDfltProp; if( pDfltProp ) aDfltProp = pDfltProp->GetName(); rStrm.WriteByteString( aClassName, RTL_TEXTENCODING_ASCII_US ); rStrm.WriteByteString( aDfltProp, RTL_TEXTENCODING_ASCII_US ); sal_uIntPtr nPos = rStrm.Tell(); rStrm << (sal_uInt32) 0L; if( !StorePrivateData( rStrm ) ) return sal_False; sal_uIntPtr nNew = rStrm.Tell(); rStrm.Seek( nPos ); rStrm << (sal_uInt32) ( nNew - nPos ); rStrm.Seek( nNew ); if( !pMethods->Store( rStrm ) ) return sal_False; if( !pProps->Store( rStrm ) ) return sal_False; if( !pObjs->Store( rStrm ) ) return sal_False; ((SbxObject*) this)->SetModified( sal_False ); return sal_True; } XubString SbxObject::GenerateSource( const XubString &rLinePrefix, const SbxObject* ) { // Properties in einem String einsammeln XubString aSource; SbxArrayRef xProps( GetProperties() ); bool bLineFeed = false; for ( sal_uInt16 nProp = 0; nProp < xProps->Count(); ++nProp ) { SbxPropertyRef xProp = (SbxProperty*) xProps->Get(nProp); XubString aPropName( xProp->GetName() ); if ( xProp->CanWrite() && !( xProp->GetHashCode() == nNameHash && aPropName.EqualsIgnoreCaseAscii( pNameProp ) ) ) { // ausser vor dem ersten Property immer einen Umbruch einfuegen if ( bLineFeed ) aSource.AppendAscii( "\n" ); else bLineFeed = true; aSource += rLinePrefix; aSource += '.'; aSource += aPropName; aSource.AppendAscii( " = " ); // den Property-Wert textuell darstellen switch ( xProp->GetType() ) { case SbxEMPTY: case SbxNULL: // kein Wert break; case SbxSTRING: { // Strings in Anf"uhrungszeichen aSource.AppendAscii( "\"" ); aSource += xProp->GetString(); aSource.AppendAscii( "\"" ); break; } default: { // sonstiges wie z.B. Zahlen direkt aSource += xProp->GetString(); break; } } } } return aSource; } static sal_Bool CollectAttrs( const SbxBase* p, XubString& rRes ) { XubString aAttrs; if( p->IsHidden() ) aAttrs.AssignAscii( "Hidden" ); if( p->IsSet( SBX_EXTSEARCH ) ) { if( aAttrs.Len() ) aAttrs += ','; aAttrs.AppendAscii( "ExtSearch" ); } if( !p->IsVisible() ) { if( aAttrs.Len() ) aAttrs += ','; aAttrs.AppendAscii( "Invisible" ); } if( p->IsSet( SBX_DONTSTORE ) ) { if( aAttrs.Len() ) aAttrs += ','; aAttrs.AppendAscii( "DontStore" ); } if( aAttrs.Len() ) { rRes.AssignAscii( " (" ); rRes += aAttrs; rRes += ')'; return sal_True; } else { rRes.Erase(); return sal_False; } } void SbxObject::Dump( SvStream& rStrm, sal_Bool bFill ) { // Einr"uckung static sal_uInt16 nLevel = 0; if ( nLevel > 10 ) { rStrm << "" << endl; return; } ++nLevel; String aIndent; for ( sal_uInt16 n = 1; n < nLevel; ++n ) aIndent.AppendAscii( " " ); // ggf. Objekt vervollst"andigen if ( bFill ) GetAll( SbxCLASS_DONTCARE ); // Daten des Objekts selbst ausgeben ByteString aNameStr( (const UniString&)GetName(), RTL_TEXTENCODING_ASCII_US ); ByteString aClassNameStr( (const UniString&)aClassName, RTL_TEXTENCODING_ASCII_US ); rStrm << "Object( " << ByteString::CreateFromInt64( (sal_uIntPtr) this ).GetBuffer() << "=='" << ( aNameStr.Len() ? aNameStr.GetBuffer() : "" ) << "', " << "of class '" << aClassNameStr.GetBuffer() << "', " << "counts " << ByteString::CreateFromInt64( GetRefCount() ).GetBuffer() << " refs, "; if ( GetParent() ) { ByteString aParentNameStr( (const UniString&)GetName(), RTL_TEXTENCODING_ASCII_US ); rStrm << "in parent " << ByteString::CreateFromInt64( (sal_uIntPtr) GetParent() ).GetBuffer() << "=='" << ( aParentNameStr.Len() ? aParentNameStr.GetBuffer() : "" ) << "'"; } else rStrm << "no parent "; rStrm << " )" << endl; ByteString aIndentNameStr( (const UniString&)aIndent, RTL_TEXTENCODING_ASCII_US ); rStrm << aIndentNameStr.GetBuffer() << "{" << endl; // Flags XubString aAttrs; if( CollectAttrs( this, aAttrs ) ) { ByteString aAttrStr( (const UniString&)aAttrs, RTL_TEXTENCODING_ASCII_US ); rStrm << aIndentNameStr.GetBuffer() << "- Flags: " << aAttrStr.GetBuffer() << endl; } // Methods rStrm << aIndentNameStr.GetBuffer() << "- Methods:" << endl; for( sal_uInt16 i = 0; i < pMethods->Count(); i++ ) { SbxVariableRef& r = pMethods->GetRef( i ); SbxVariable* pVar = r; if( pVar ) { XubString aLine( aIndent ); aLine.AppendAscii( " - " ); aLine += pVar->GetName( SbxNAME_SHORT_TYPES ); XubString aAttrs2; if( CollectAttrs( pVar, aAttrs2 ) ) aLine += aAttrs2; if( !pVar->IsA( TYPE(SbxMethod) ) ) aLine.AppendAscii( " !! Not a Method !!" ); rStrm.WriteByteString( aLine, RTL_TEXTENCODING_ASCII_US ); // bei Object-Methods auch das Object ausgeben if ( pVar->GetValues_Impl().eType == SbxOBJECT && pVar->GetValues_Impl().pObj && pVar->GetValues_Impl().pObj != this && pVar->GetValues_Impl().pObj != GetParent() ) { rStrm << " contains "; ((SbxObject*) pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill ); } else rStrm << endl; } } // Properties rStrm << aIndentNameStr.GetBuffer() << "- Properties:" << endl; { for( sal_uInt16 i = 0; i < pProps->Count(); i++ ) { SbxVariableRef& r = pProps->GetRef( i ); SbxVariable* pVar = r; if( pVar ) { XubString aLine( aIndent ); aLine.AppendAscii( " - " ); aLine += pVar->GetName( SbxNAME_SHORT_TYPES ); XubString aAttrs3; if( CollectAttrs( pVar, aAttrs3 ) ) aLine += aAttrs3; if( !pVar->IsA( TYPE(SbxProperty) ) ) aLine.AppendAscii( " !! Not a Property !!" ); rStrm.WriteByteString( aLine, RTL_TEXTENCODING_ASCII_US ); // bei Object-Properties auch das Object ausgeben if ( pVar->GetValues_Impl().eType == SbxOBJECT && pVar->GetValues_Impl().pObj && pVar->GetValues_Impl().pObj != this && pVar->GetValues_Impl().pObj != GetParent() ) { rStrm << " contains "; ((SbxObject*) pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill ); } else rStrm << endl; } } } // Objects rStrm << aIndentNameStr.GetBuffer() << "- Objects:" << endl; { for( sal_uInt16 i = 0; i < pObjs->Count(); i++ ) { SbxVariableRef& r = pObjs->GetRef( i ); SbxVariable* pVar = r; if ( pVar ) { rStrm << aIndentNameStr.GetBuffer() << " - Sub"; if ( pVar->ISA(SbxObject) ) ((SbxObject*) pVar)->Dump( rStrm, bFill ); else if ( pVar->ISA(SbxVariable) ) ((SbxVariable*) pVar)->Dump( rStrm, bFill ); } } } rStrm << aIndentNameStr.GetBuffer() << "}" << endl << endl; --nLevel; } SvDispatch* SbxObject::GetSvDispatch() { return NULL; } sal_Bool SbxMethod::Run( SbxValues* pValues ) { SbxValues aRes; if( !pValues ) pValues = &aRes; pValues->eType = SbxVARIANT; return Get( *pValues ); } SbxClassType SbxMethod::GetClass() const { return SbxCLASS_METHOD; } SbxClassType SbxProperty::GetClass() const { return SbxCLASS_PROPERTY; } void SbxObject::GarbageCollection( sal_uIntPtr nObjects ) /* [Beschreibung] Diese statische Methode durchsucht die n"achsten 'nObjects' der zur Zeit existierenden -Instanzen nach zyklischen Referenzen, die sich nur noch selbst am Leben erhalten. Ist 'nObjects==0', dann werden alle existierenden durchsucht. zur Zeit nur implementiert: Object -> Parent-Property -> Parent -> Object */ { (void)nObjects; static sal_Bool bInGarbageCollection = sal_False; if ( bInGarbageCollection ) return; bInGarbageCollection = sal_True; #if 0 // erstes Object dieser Runde anspringen sal_Bool bAll = !nObjects; if ( bAll ) rObjects.First(); SbxObject *pObj = rObjects.GetCurObject(); if ( !pObj ) pObj = rObjects.First(); while ( pObj && 0 != nObjects-- ) { // hat der Parent nur noch 1 Ref-Count? SbxObject *pParent = PTR_CAST( SbxObject, pObj->GetParent() ); if ( pParent && 1 == pParent->GetRefCount() ) { // dann alle Properies des Objects durchsuchen SbxArray *pProps = pObj->GetProperties(); for ( sal_uInt16 n = 0; n < pProps->Count(); ++n ) { // verweist die Property auf den Parent des Object? SbxVariable *pProp = pProps->Get(n); const SbxValues &rValues = pProp->GetValues_Impl(); if ( SbxOBJECT == rValues.eType && pParent == rValues.pObj ) { #ifdef DBG_UTIL DbgOutf( "SBX: %s.%s with Object %s was garbage", pObj->GetName().GetStr(), pProp->GetName().GetStr(), pParent->GetName().GetStr() ); #endif // dann freigeben pProp->SbxValue::Clear(); Sound::Beep(); break; } } } // zum n"achsten pObj = rObjects.Next(); if ( !bAll && !pObj ) pObj = rObjects.First(); } #endif // AB 28.10. Zur 507a vorerst raus, da SfxBroadcaster::Enable() wegfaellt #if 0 #ifdef DBG_UTIL SbxVarList_Impl &rVars = GetSbxData_Impl()->aVars; DbgOutf( "SBX: garbage collector done, %lu objects remainding", rVars.Count() ); if ( rVars.Count() > 200 && rVars.Count() < 210 ) { SvFileStream aStream( "d:\\tmp\\dump.sbx", STREAM_STD_WRITE ); SfxBroadcaster::Enable(sal_False); for ( sal_uIntPtr n = 0; n < rVars.Count(); ++n ) { SbxVariable *pVar = rVars.GetObject(n); SbxObject *pObj = PTR_CAST(SbxObject, pVar); sal_uInt16 nFlags = pVar->GetFlags(); pVar->SetFlag(SBX_NO_BROADCAST); if ( pObj ) pObj->Dump(aStream); else if ( !pVar->GetParent() || !pVar->GetParent()->ISA(SbxObject) ) pVar->Dump(aStream); pVar->SetFlags(nFlags); } SfxBroadcaster::Enable(sal_True); } #endif #endif bInGarbageCollection = sal_False; }