| /************************************************************** |
| * |
| * 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 <tools/stream.hxx> |
| #include <vcl/sound.hxx> |
| #include <basic/sbx.hxx> |
| #include <basic/sbxbase.hxx> |
| #include "sbxres.hxx" |
| #include <svl/brdcst.hxx> |
| |
| 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( !this, "Ungueltige SBX-Klasse" ); |
| } |
| 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( !this, "Ungueltige SBX-Klasse" ); |
| } |
| 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( !this, "Ungueltige SBX-Klasse" ); |
| } |
| 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( !this, "Ungueltige SBX-Klasse" ); |
| } |
| } |
| 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( !this, "Ungueltige SBX-Klasse" ); |
| } |
| } |
| 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( !this, "Ungueltige SBX-Klasse" ); |
| } |
| 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 << "<too deep>" << 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() : "<unnamed>" ) << "', " |
| << "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() : "<unnamed>" ) << "'"; |
| } |
| 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 <SbxObject>-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; |
| } |
| |