Update ooo320-m1
[ooovba.git] / basic / source / sbx / sbxobj.cxx
blob7f8584d88934b3fb9265dffd6422937963ab469a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: sbxobj.cxx,v $
10 * $Revision: 1.9 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_basic.hxx"
33 #include <tools/stream.hxx>
34 #include <vcl/sound.hxx>
35 #include <basic/sbx.hxx>
36 #include <basic/sbxbase.hxx>
37 #include "sbxres.hxx"
38 #include <svtools/brdcst.hxx>
40 TYPEINIT1(SbxMethod,SbxVariable)
41 TYPEINIT1(SbxProperty,SbxVariable)
42 TYPEINIT2(SbxObject,SbxVariable,SfxListener)
44 static const char* pNameProp; // Name-Property
45 static const char* pParentProp; // Parent-Property
47 static USHORT nNameHash = 0, nParentHash = 0;
49 /////////////////////////////////////////////////////////////////////////
51 /////////////////////////////////////////////////////////////////////////
53 SbxObject::SbxObject( const XubString& rClass )
54 : SbxVariable( SbxOBJECT ), aClassName( rClass )
56 aData.pObj = this;
57 if( !nNameHash )
59 pNameProp = GetSbxRes( STRING_NAMEPROP );
60 pParentProp = GetSbxRes( STRING_PARENTPROP );
61 nNameHash = MakeHashCode( String::CreateFromAscii( pNameProp ) );
62 nParentHash = MakeHashCode( String::CreateFromAscii( pParentProp ) );
64 SbxObject::Clear();
65 SbxObject::SetName( rClass );
68 SbxObject::SbxObject( const SbxObject& rObj )
69 : SvRefBase( rObj ), SbxVariable( rObj.GetType() ),
70 SfxListener( rObj )
72 *this = rObj;
75 SbxObject& SbxObject::operator=( const SbxObject& r )
77 if( &r != this )
79 SbxVariable::operator=( r );
80 aClassName = r.aClassName;
81 pMethods = new SbxArray;
82 pProps = new SbxArray;
83 pObjs = new SbxArray( SbxOBJECT );
84 // Die Arrays werden kopiert, die Inhalte uebernommen
85 *pMethods = *r.pMethods;
86 *pProps = *r.pProps;
87 *pObjs = *r.pObjs;
88 // Da die Variablen uebernommen wurden, ist dies OK
89 pDfltProp = r.pDfltProp;
90 SetName( r.GetName() );
91 SetFlags( r.GetFlags() );
92 SetModified( TRUE );
94 return *this;
97 static void CheckParentsOnDelete( SbxObject* pObj, SbxArray* p )
99 for( USHORT i = 0; i < p->Count(); i++ )
101 SbxVariableRef& rRef = p->GetRef( i );
102 if( rRef->IsBroadcaster() )
103 pObj->EndListening( rRef->GetBroadcaster(), TRUE );
104 // Hat das Element mehr als eine Referenz und noch einen Listener?
105 if( rRef->GetRefCount() > 1 )
107 rRef->SetParent( NULL );
108 DBG_ASSERT( !rRef->IsBroadcaster() || rRef->GetBroadcaster().GetListenerCount(), "Object element with dangling parent" );
113 SbxObject::~SbxObject()
115 CheckParentsOnDelete( this, pProps );
116 CheckParentsOnDelete( this, pMethods );
117 CheckParentsOnDelete( this, pObjs );
120 SbxDataType SbxObject::GetType() const
122 return SbxOBJECT;
125 SbxClassType SbxObject::GetClass() const
127 return SbxCLASS_OBJECT;
130 void SbxObject::Clear()
132 pMethods = new SbxArray;
133 pProps = new SbxArray;
134 pObjs = new SbxArray( SbxOBJECT );
135 SbxVariable* p;
136 p = Make( String::CreateFromAscii( pNameProp ), SbxCLASS_PROPERTY, SbxSTRING );
137 p->SetFlag( SBX_DONTSTORE );
138 p = Make( String::CreateFromAscii( pParentProp ), SbxCLASS_PROPERTY, SbxOBJECT );
139 p->ResetFlag( SBX_WRITE );
140 p->SetFlag( SBX_DONTSTORE );
141 pDfltProp = NULL;
142 SetModified( FALSE );
145 void SbxObject::SFX_NOTIFY( SfxBroadcaster&, const TypeId&,
146 const SfxHint& rHint, const TypeId& )
148 const SbxHint* p = PTR_CAST(SbxHint,&rHint);
149 if( p )
151 ULONG nId = p->GetId();
152 BOOL bRead = BOOL( nId == SBX_HINT_DATAWANTED );
153 BOOL bWrite = BOOL( nId == SBX_HINT_DATACHANGED );
154 SbxVariable* pVar = p->GetVar();
155 if( bRead || bWrite )
157 XubString aVarName( pVar->GetName() );
158 USHORT nHash_ = MakeHashCode( aVarName );
159 if( nHash_ == nNameHash
160 && aVarName.EqualsIgnoreCaseAscii( pNameProp ) )
162 if( bRead )
163 pVar->PutString( GetName() );
164 else
165 SetName( pVar->GetString() );
167 else if( nHash_ == nParentHash
168 && aVarName.EqualsIgnoreCaseAscii( pParentProp ) )
170 SbxObject* p_ = GetParent();
171 if( !p_ )
172 p_ = this;
173 pVar->PutObject( p_ );
179 BOOL SbxObject::IsClass( const XubString& rName ) const
181 return BOOL( aClassName.EqualsIgnoreCaseAscii( rName ) );
184 SbxVariable* SbxObject::FindUserData( UINT32 nData )
186 if( !GetAll( SbxCLASS_DONTCARE ) )
187 return NULL;
189 SbxVariable* pRes = pMethods->FindUserData( nData );
190 if( !pRes )
191 pRes = pProps->FindUserData( nData );
192 if( !pRes )
193 pRes = pObjs->FindUserData( nData );
194 // Search in den Parents?
195 if( !pRes && IsSet( SBX_GBLSEARCH ) )
197 SbxObject* pCur = this;
198 while( !pRes && pCur->pParent )
200 // Ich selbst bin schon durchsucht worden!
201 USHORT nOwn = pCur->GetFlags();
202 pCur->ResetFlag( SBX_EXTSEARCH );
203 // Ich suche bereits global!
204 USHORT nPar = pCur->pParent->GetFlags();
205 pCur->pParent->ResetFlag( SBX_GBLSEARCH );
206 pRes = pCur->pParent->FindUserData( nData );
207 pCur->SetFlags( nOwn );
208 pCur->pParent->SetFlags( nPar );
209 pCur = pCur->pParent;
212 return pRes;
215 SbxVariable* SbxObject::Find( const XubString& rName, SbxClassType t )
217 #ifdef DBG_UTIL
218 static USHORT nLvl = 0;
219 static const char* pCls[] =
220 { "DontCare","Array","Value","Variable","Method","Property","Object" };
221 ByteString aNameStr1( (const UniString&)rName, RTL_TEXTENCODING_ASCII_US );
222 ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
223 DbgOutf( "SBX: Search %.*s %s %s in %s",
224 nLvl++, " ",
225 ( t >= SbxCLASS_DONTCARE && t <= SbxCLASS_OBJECT )
226 ? pCls[ t-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() );
227 #endif
229 if( !GetAll( t ) )
230 return NULL;
231 SbxVariable* pRes = NULL;
232 pObjs->SetFlag( SBX_EXTSEARCH );
233 if( t == SbxCLASS_DONTCARE )
235 pRes = pMethods->Find( rName, SbxCLASS_METHOD );
236 if( !pRes )
237 pRes = pProps->Find( rName, SbxCLASS_PROPERTY );
238 if( !pRes )
239 pRes = pObjs->Find( rName, t );
241 else
243 SbxArray* pArray = NULL;
244 switch( t )
246 case SbxCLASS_VARIABLE:
247 case SbxCLASS_PROPERTY: pArray = pProps; break;
248 case SbxCLASS_METHOD: pArray = pMethods; break;
249 case SbxCLASS_OBJECT: pArray = pObjs; break;
250 default:
251 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
253 if( pArray )
254 pRes = pArray->Find( rName, t );
256 // Extended Search im Objekt-Array?
257 // Fuer Objekte und DontCare ist das Objektarray bereits
258 // durchsucht worden
259 if( !pRes && ( t == SbxCLASS_METHOD || t == SbxCLASS_PROPERTY ) )
260 pRes = pObjs->Find( rName, t );
261 // Search in den Parents?
262 if( !pRes && IsSet( SBX_GBLSEARCH ) )
264 SbxObject* pCur = this;
265 while( !pRes && pCur->pParent )
267 // Ich selbst bin schon durchsucht worden!
268 USHORT nOwn = pCur->GetFlags();
269 pCur->ResetFlag( SBX_EXTSEARCH );
270 // Ich suche bereits global!
271 USHORT nPar = pCur->pParent->GetFlags();
272 pCur->pParent->ResetFlag( SBX_GBLSEARCH );
273 pRes = pCur->pParent->Find( rName, t );
274 pCur->SetFlags( nOwn );
275 pCur->pParent->SetFlags( nPar );
276 pCur = pCur->pParent;
279 #ifdef DBG_UTIL
280 nLvl--;
281 if( pRes )
283 ByteString aNameStr3( (const UniString&)rName, RTL_TEXTENCODING_ASCII_US );
284 ByteString aNameStr4( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
285 DbgOutf( "SBX: Found %.*s %s in %s",
286 nLvl, " ", aNameStr3.GetBuffer(), aNameStr4.GetBuffer() );
288 #endif
289 return pRes;
292 // Kurzform: Die Parent-Kette wird durchsucht
293 // Das ganze rekursiv, da Call() ueberladen sein kann
294 // Qualified Names sind zugelassen
296 BOOL SbxObject::Call( const XubString& rName, SbxArray* pParam )
298 SbxVariable* pMeth = FindQualified( rName, SbxCLASS_DONTCARE);
299 if( pMeth && pMeth->ISA(SbxMethod) )
301 // FindQualified() koennte schon zugeschlagen haben!
302 if( pParam )
303 pMeth->SetParameters( pParam );
304 pMeth->Broadcast( SBX_HINT_DATAWANTED );
305 pMeth->SetParameters( NULL );
306 return TRUE;
308 SetError( SbxERR_NO_METHOD );
309 return FALSE;
312 SbxProperty* SbxObject::GetDfltProperty()
314 if ( !pDfltProp && aDfltPropName.Len() )
316 pDfltProp = (SbxProperty*) Find( aDfltPropName, SbxCLASS_PROPERTY );
317 if( !pDfltProp )
318 pDfltProp = (SbxProperty*) Make( aDfltPropName, SbxCLASS_PROPERTY, SbxVARIANT );
320 return pDfltProp;
322 void SbxObject::SetDfltProperty( const XubString& rName )
324 if ( rName != aDfltPropName )
325 pDfltProp = NULL;
326 aDfltPropName = rName;
327 SetModified( TRUE );
330 void SbxObject::SetDfltProperty( SbxProperty* p )
332 if( p )
334 USHORT n;
335 SbxArray* pArray = FindVar( p, n );
336 pArray->Put( p, n );
337 if( p->GetParent() != this )
338 p->SetParent( this );
339 Broadcast( SBX_HINT_OBJECTCHANGED );
341 pDfltProp = p;
342 SetModified( TRUE );
345 // Suchen einer bereits vorhandenen Variablen. Falls sie gefunden wurde,
346 // wird der Index gesetzt, sonst wird der Count des Arrays geliefert.
347 // In jedem Fall wird das korrekte Array geliefert.
349 SbxArray* SbxObject::FindVar( SbxVariable* pVar, USHORT& nArrayIdx )
351 SbxArray* pArray = NULL;
352 if( pVar ) switch( pVar->GetClass() )
354 case SbxCLASS_VARIABLE:
355 case SbxCLASS_PROPERTY: pArray = pProps; break;
356 case SbxCLASS_METHOD: pArray = pMethods; break;
357 case SbxCLASS_OBJECT: pArray = pObjs; break;
358 default:
359 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
361 if( pArray )
363 nArrayIdx = pArray->Count();
364 // ist die Variable per Name vorhanden?
365 pArray->ResetFlag( SBX_EXTSEARCH );
366 SbxVariable* pOld = pArray->Find( pVar->GetName(), pVar->GetClass() );
367 if( pOld )
368 for( USHORT i = 0; i < pArray->Count(); i++ )
370 SbxVariableRef& rRef = pArray->GetRef( i );
371 if( (SbxVariable*) rRef == pOld )
373 nArrayIdx = i; break;
377 return pArray;
380 // Falls ein neues Objekt eingerichtet wird, wird es, falls es bereits
381 // eines mit diesem Namen gibt, indiziert.
383 SbxVariable* SbxObject::Make( const XubString& rName, SbxClassType ct, SbxDataType dt )
385 // Ist das Objekt bereits vorhanden?
386 SbxArray* pArray = NULL;
387 switch( ct )
389 case SbxCLASS_VARIABLE:
390 case SbxCLASS_PROPERTY: pArray = pProps; break;
391 case SbxCLASS_METHOD: pArray = pMethods; break;
392 case SbxCLASS_OBJECT: pArray = pObjs; break;
393 default:
394 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
396 if( !pArray )
397 return NULL;
398 // Collections duerfen gleichnamige Objekte enthalten
399 if( !( ct == SbxCLASS_OBJECT && ISA(SbxCollection) ) )
401 SbxVariable* pRes = pArray->Find( rName, ct );
402 if( pRes )
404 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus
405 #ifdef DBG_UTIL
406 if( pRes->GetHashCode() != nNameHash
407 && pRes->GetHashCode() != nParentHash )
409 XubString aMsg( "SBX-Element \"" );
410 aMsg += pRes->GetName();
411 aMsg += "\"\n in Objekt \"";
412 aMsg += GetName();
413 aMsg += "\" bereits vorhanden";
414 DbgError( (const char*)aMsg.GetStr() );
416 #endif
418 return pRes;
421 SbxVariable* pVar = NULL;
422 switch( ct )
424 case SbxCLASS_VARIABLE:
425 case SbxCLASS_PROPERTY:
426 pVar = new SbxProperty( rName, dt );
427 break;
428 case SbxCLASS_METHOD:
429 pVar = new SbxMethod( rName, dt );
430 break;
431 case SbxCLASS_OBJECT:
432 pVar = CreateObject( rName );
433 break;
434 default: break;
436 pVar->SetParent( this );
437 pArray->Put( pVar, pArray->Count() );
438 SetModified( TRUE );
439 // Das Objekt lauscht immer
440 StartListening( pVar->GetBroadcaster(), TRUE );
441 Broadcast( SBX_HINT_OBJECTCHANGED );
442 return pVar;
445 SbxObject* SbxObject::MakeObject( const XubString& rName, const XubString& rClass )
447 // Ist das Objekt bereits vorhanden?
448 if( !ISA(SbxCollection) )
450 SbxVariable* pRes = pObjs->Find( rName, SbxCLASS_OBJECT );
451 if( pRes )
453 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus
454 #ifdef DBG_UTIL
455 if( pRes->GetHashCode() != nNameHash
456 && pRes->GetHashCode() != nParentHash )
458 XubString aMsg( "SBX-Objekt \"" );
459 aMsg += pRes->GetName();
460 aMsg += "\"\n in Objekt \"";
461 aMsg += GetName();
462 aMsg += "\" bereits vorhanden";
463 DbgError( (const char*)aMsg.GetStr() );
465 #endif
467 return PTR_CAST(SbxObject,pRes);
470 SbxObject* pVar = CreateObject( rClass );
471 if( pVar )
473 pVar->SetName( rName );
474 pVar->SetParent( this );
475 pObjs->Put( pVar, pObjs->Count() );
476 SetModified( TRUE );
477 // Das Objekt lauscht immer
478 StartListening( pVar->GetBroadcaster(), TRUE );
479 Broadcast( SBX_HINT_OBJECTCHANGED );
481 return pVar;
484 void SbxObject::Insert( SbxVariable* pVar )
486 USHORT nIdx;
487 SbxArray* pArray = FindVar( pVar, nIdx );
488 if( pArray )
490 // Hinein damit. Man sollte allerdings auf die Pointer aufpassen!
491 if( nIdx < pArray->Count() )
493 // dann gibt es dieses Element bereits
494 // Bei Collections duerfen gleichnamige Objekte hinein
495 if( pArray == pObjs && ISA(SbxCollection) )
496 nIdx = pArray->Count();
497 else
499 SbxVariable* pOld = pArray->Get( nIdx );
500 // schon drin: ueberschreiben
501 if( pOld == pVar )
502 return;
504 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus
505 #ifdef DBG_UTIL
506 if( pOld->GetHashCode() != nNameHash
507 && pOld->GetHashCode() != nParentHash )
509 XubString aMsg( "SBX-Element \"" );
510 aMsg += pVar->GetName();
511 aMsg += "\"\n in Objekt \"";
512 aMsg += GetName();
513 aMsg += "\" bereits vorhanden";
514 DbgError( (const char*)aMsg.GetStr() );
516 #endif
518 EndListening( pOld->GetBroadcaster(), TRUE );
519 if( pVar->GetClass() == SbxCLASS_PROPERTY )
521 if( pOld == pDfltProp )
522 pDfltProp = (SbxProperty*) pVar;
526 StartListening( pVar->GetBroadcaster(), TRUE );
527 pArray->Put( pVar, nIdx );
528 if( pVar->GetParent() != this )
529 pVar->SetParent( this );
530 SetModified( TRUE );
531 Broadcast( SBX_HINT_OBJECTCHANGED );
532 #ifdef DBG_UTIL
533 static const char* pCls[] =
534 { "DontCare","Array","Value","Variable","Method","Property","Object" };
535 XubString aVarName( pVar->GetName() );
536 if ( !aVarName.Len() && pVar->ISA(SbxObject) )
537 aVarName = PTR_CAST(SbxObject,pVar)->GetClassName();
538 ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US );
539 ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
540 DbgOutf( "SBX: Insert %s %s in %s",
541 ( pVar->GetClass() >= SbxCLASS_DONTCARE &&
542 pVar->GetClass() <= SbxCLASS_OBJECT )
543 ? pCls[ pVar->GetClass()-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() );
544 #endif
548 // AB 23.4.1997, Optimierung, Einfuegen ohne Ueberpruefung auf doppelte
549 // Eintraege und ohne Broadcasts, wird nur in SO2/auto.cxx genutzt
550 void SbxObject::QuickInsert( SbxVariable* pVar )
552 SbxArray* pArray = NULL;
553 if( pVar )
555 switch( pVar->GetClass() )
557 case SbxCLASS_VARIABLE:
558 case SbxCLASS_PROPERTY: pArray = pProps; break;
559 case SbxCLASS_METHOD: pArray = pMethods; break;
560 case SbxCLASS_OBJECT: pArray = pObjs; break;
561 default:
562 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
565 if( pArray )
567 StartListening( pVar->GetBroadcaster(), TRUE );
568 pArray->Put( pVar, pArray->Count() );
569 if( pVar->GetParent() != this )
570 pVar->SetParent( this );
571 SetModified( TRUE );
572 #ifdef DBG_UTIL
573 static const char* pCls[] =
574 { "DontCare","Array","Value","Variable","Method","Property","Object" };
575 XubString aVarName( pVar->GetName() );
576 if ( !aVarName.Len() && pVar->ISA(SbxObject) )
577 aVarName = PTR_CAST(SbxObject,pVar)->GetClassName();
578 ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US );
579 ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
580 DbgOutf( "SBX: Insert %s %s in %s",
581 ( pVar->GetClass() >= SbxCLASS_DONTCARE &&
582 pVar->GetClass() <= SbxCLASS_OBJECT )
583 ? pCls[ pVar->GetClass()-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() );
584 #endif
588 // AB 23.3.1997, Spezial-Methode, gleichnamige Controls zulassen
589 void SbxObject::VCPtrInsert( SbxVariable* pVar )
591 SbxArray* pArray = NULL;
592 if( pVar )
594 switch( pVar->GetClass() )
596 case SbxCLASS_VARIABLE:
597 case SbxCLASS_PROPERTY: pArray = pProps; break;
598 case SbxCLASS_METHOD: pArray = pMethods; break;
599 case SbxCLASS_OBJECT: pArray = pObjs; break;
600 default:
601 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
604 if( pArray )
606 StartListening( pVar->GetBroadcaster(), TRUE );
607 pArray->Put( pVar, pArray->Count() );
608 if( pVar->GetParent() != this )
609 pVar->SetParent( this );
610 SetModified( TRUE );
611 Broadcast( SBX_HINT_OBJECTCHANGED );
615 void SbxObject::Remove( const XubString& rName, SbxClassType t )
617 Remove( SbxObject::Find( rName, t ) );
620 void SbxObject::Remove( SbxVariable* pVar )
622 USHORT nIdx;
623 SbxArray* pArray = FindVar( pVar, nIdx );
624 if( pArray && nIdx < pArray->Count() )
626 #ifdef DBG_UTIL
627 XubString aVarName( pVar->GetName() );
628 if ( !aVarName.Len() && pVar->ISA(SbxObject) )
629 aVarName = PTR_CAST(SbxObject,pVar)->GetClassName();
630 ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US );
631 ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
632 #endif
633 SbxVariableRef pVar_ = pArray->Get( nIdx );
634 if( pVar_->IsBroadcaster() )
635 EndListening( pVar_->GetBroadcaster(), TRUE );
636 if( (SbxVariable*) pVar_ == pDfltProp )
637 pDfltProp = NULL;
638 pArray->Remove( nIdx );
639 if( pVar_->GetParent() == this )
640 pVar_->SetParent( NULL );
641 SetModified( TRUE );
642 Broadcast( SBX_HINT_OBJECTCHANGED );
646 // AB 23.3.1997, Loeschen per Pointer fuer Controls (doppelte Namen!)
647 void SbxObject::VCPtrRemove( SbxVariable* pVar )
649 USHORT nIdx;
650 // Neu FindVar-Methode, sonst identisch mit normaler Methode
651 SbxArray* pArray = VCPtrFindVar( pVar, nIdx );
652 if( pArray && nIdx < pArray->Count() )
654 SbxVariableRef xVar = pArray->Get( nIdx );
655 if( xVar->IsBroadcaster() )
656 EndListening( xVar->GetBroadcaster(), TRUE );
657 if( (SbxVariable*) xVar == pDfltProp )
658 pDfltProp = NULL;
659 pArray->Remove( nIdx );
660 if( xVar->GetParent() == this )
661 xVar->SetParent( NULL );
662 SetModified( TRUE );
663 Broadcast( SBX_HINT_OBJECTCHANGED );
667 // AB 23.3.1997, Zugehoerige Spezial-Methode, nur ueber Pointer suchen
668 SbxArray* SbxObject::VCPtrFindVar( SbxVariable* pVar, USHORT& nArrayIdx )
670 SbxArray* pArray = NULL;
671 if( pVar ) switch( pVar->GetClass() )
673 case SbxCLASS_VARIABLE:
674 case SbxCLASS_PROPERTY: pArray = pProps; break;
675 case SbxCLASS_METHOD: pArray = pMethods; break;
676 case SbxCLASS_OBJECT: pArray = pObjs; break;
677 default:
678 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
680 if( pArray )
682 nArrayIdx = pArray->Count();
683 for( USHORT i = 0; i < pArray->Count(); i++ )
685 SbxVariableRef& rRef = pArray->GetRef( i );
686 if( (SbxVariable*) rRef == pVar )
688 nArrayIdx = i; break;
692 return pArray;
697 void SbxObject::SetPos( SbxVariable* pVar, USHORT nPos )
699 USHORT nIdx;
700 SbxArray* pArray = FindVar( pVar, nIdx );
701 if( pArray )
703 if( nPos >= pArray->Count() )
704 nPos = pArray->Count() - 1;
705 if( nIdx < ( pArray->Count() - 1 ) )
707 SbxVariableRef refVar = pArray->Get( nIdx );
708 pArray->Remove( nIdx );
709 pArray->Insert( refVar, nPos );
712 // SetModified( TRUE );
713 // Broadcast( SBX_HINT_OBJECTCHANGED );
716 static BOOL LoadArray( SvStream& rStrm, SbxObject* pThis, SbxArray* pArray )
718 SbxArrayRef p = (SbxArray*) SbxBase::Load( rStrm );
719 if( !p.Is() )
720 return FALSE;
721 for( USHORT i = 0; i < p->Count(); i++ )
723 SbxVariableRef& r = p->GetRef( i );
724 SbxVariable* pVar = r;
725 if( pVar )
727 pVar->SetParent( pThis );
728 pThis->StartListening( pVar->GetBroadcaster(), TRUE );
731 pArray->Merge( p );
732 return TRUE;
735 // Der Load eines Objekts ist additiv!
737 BOOL SbxObject::LoadData( SvStream& rStrm, USHORT nVer )
739 // Hilfe fuer das Einlesen alter Objekte: einfach TRUE zurueck,
740 // LoadPrivateData() muss Default-Zustand herstellen
741 if( !nVer )
742 return TRUE;
744 pDfltProp = NULL;
745 if( !SbxVariable::LoadData( rStrm, nVer ) )
746 return FALSE;
747 // Wenn kein fremdes Objekt enthalten ist, uns selbst eintragen
748 if( aData.eType == SbxOBJECT && !aData.pObj )
749 aData.pObj = this;
750 sal_uInt32 nSize;
751 XubString aDfltProp;
752 rStrm.ReadByteString( aClassName, RTL_TEXTENCODING_ASCII_US );
753 rStrm.ReadByteString( aDfltProp, RTL_TEXTENCODING_ASCII_US );
754 ULONG nPos = rStrm.Tell();
755 rStrm >> nSize;
756 if( !LoadPrivateData( rStrm, nVer ) )
757 return FALSE;
758 ULONG nNewPos = rStrm.Tell();
759 nPos += nSize;
760 DBG_ASSERT( nPos >= nNewPos, "SBX: Zu viele Daten eingelesen" );
761 if( nPos != nNewPos )
762 rStrm.Seek( nPos );
763 if( !LoadArray( rStrm, this, pMethods )
764 || !LoadArray( rStrm, this, pProps )
765 || !LoadArray( rStrm, this, pObjs ) )
766 return FALSE;
767 // Properties setzen
768 if( aDfltProp.Len() )
769 pDfltProp = (SbxProperty*) pProps->Find( aDfltProp, SbxCLASS_PROPERTY );
770 SetModified( FALSE );
771 return TRUE;
774 BOOL SbxObject::StoreData( SvStream& rStrm ) const
776 if( !SbxVariable::StoreData( rStrm ) )
777 return FALSE;
778 XubString aDfltProp;
779 if( pDfltProp )
780 aDfltProp = pDfltProp->GetName();
781 rStrm.WriteByteString( aClassName, RTL_TEXTENCODING_ASCII_US );
782 rStrm.WriteByteString( aDfltProp, RTL_TEXTENCODING_ASCII_US );
783 ULONG nPos = rStrm.Tell();
784 rStrm << (UINT32) 0L;
785 if( !StorePrivateData( rStrm ) )
786 return FALSE;
787 ULONG nNew = rStrm.Tell();
788 rStrm.Seek( nPos );
789 rStrm << (UINT32) ( nNew - nPos );
790 rStrm.Seek( nNew );
791 if( !pMethods->Store( rStrm ) )
792 return FALSE;
793 if( !pProps->Store( rStrm ) )
794 return FALSE;
795 if( !pObjs->Store( rStrm ) )
796 return FALSE;
797 ((SbxObject*) this)->SetModified( FALSE );
798 return TRUE;
801 XubString SbxObject::GenerateSource( const XubString &rLinePrefix,
802 const SbxObject* )
804 // Properties in einem String einsammeln
805 XubString aSource;
806 SbxArrayRef xProps( GetProperties() );
807 FASTBOOL bLineFeed = FALSE;
808 for ( USHORT nProp = 0; nProp < xProps->Count(); ++nProp )
810 SbxPropertyRef xProp = (SbxProperty*) xProps->Get(nProp);
811 XubString aPropName( xProp->GetName() );
812 if ( xProp->CanWrite()
813 && !( xProp->GetHashCode() == nNameHash
814 && aPropName.EqualsIgnoreCaseAscii( pNameProp ) ) )
816 // ausser vor dem ersten Property immer einen Umbruch einfuegen
817 if ( bLineFeed )
818 aSource.AppendAscii( "\n" );
819 else
820 bLineFeed = TRUE;
822 aSource += rLinePrefix;
823 aSource += '.';
824 aSource += aPropName;
825 aSource.AppendAscii( " = " );
827 // den Property-Wert textuell darstellen
828 switch ( xProp->GetType() )
830 case SbxEMPTY:
831 case SbxNULL:
832 // kein Wert
833 break;
835 case SbxSTRING:
837 // Strings in Anf"uhrungszeichen
838 aSource.AppendAscii( "\"" );
839 aSource += xProp->GetString();
840 aSource.AppendAscii( "\"" );
841 break;
844 default:
846 // sonstiges wie z.B. Zahlen direkt
847 aSource += xProp->GetString();
848 break;
853 return aSource;
856 static BOOL CollectAttrs( const SbxBase* p, XubString& rRes )
858 XubString aAttrs;
859 if( p->IsHidden() )
860 aAttrs.AssignAscii( "Hidden" );
861 if( p->IsSet( SBX_EXTSEARCH ) )
863 if( aAttrs.Len() )
864 aAttrs += ',';
865 aAttrs.AppendAscii( "ExtSearch" );
867 if( !p->IsVisible() )
869 if( aAttrs.Len() )
870 aAttrs += ',';
871 aAttrs.AppendAscii( "Invisible" );
873 if( p->IsSet( SBX_DONTSTORE ) )
875 if( aAttrs.Len() )
876 aAttrs += ',';
877 aAttrs.AppendAscii( "DontStore" );
879 if( aAttrs.Len() )
881 rRes.AssignAscii( " (" );
882 rRes += aAttrs;
883 rRes += ')';
884 return TRUE;
886 else
888 rRes.Erase();
889 return FALSE;
893 void SbxObject::Dump( SvStream& rStrm, BOOL bFill )
895 // Einr"uckung
896 static USHORT nLevel = 0;
897 if ( nLevel > 10 )
899 rStrm << "<too deep>" << endl;
900 return;
902 ++nLevel;
903 String aIndent;
904 for ( USHORT n = 1; n < nLevel; ++n )
905 aIndent.AppendAscii( " " );
907 // ggf. Objekt vervollst"andigen
908 if ( bFill )
909 GetAll( SbxCLASS_DONTCARE );
911 // Daten des Objekts selbst ausgeben
912 ByteString aNameStr( (const UniString&)GetName(), RTL_TEXTENCODING_ASCII_US );
913 ByteString aClassNameStr( (const UniString&)aClassName, RTL_TEXTENCODING_ASCII_US );
914 rStrm << "Object( "
915 << ByteString::CreateFromInt64( (ULONG) this ).GetBuffer() << "=='"
916 << ( aNameStr.Len() ? aNameStr.GetBuffer() : "<unnamed>" ) << "', "
917 << "of class '" << aClassNameStr.GetBuffer() << "', "
918 << "counts "
919 << ByteString::CreateFromInt64( GetRefCount() ).GetBuffer()
920 << " refs, ";
921 if ( GetParent() )
923 ByteString aParentNameStr( (const UniString&)GetName(), RTL_TEXTENCODING_ASCII_US );
924 rStrm << "in parent "
925 << ByteString::CreateFromInt64( (ULONG) GetParent() ).GetBuffer()
926 << "=='" << ( aParentNameStr.Len() ? aParentNameStr.GetBuffer() : "<unnamed>" ) << "'";
928 else
929 rStrm << "no parent ";
930 rStrm << " )" << endl;
931 ByteString aIndentNameStr( (const UniString&)aIndent, RTL_TEXTENCODING_ASCII_US );
932 rStrm << aIndentNameStr.GetBuffer() << "{" << endl;
934 // Flags
935 XubString aAttrs;
936 if( CollectAttrs( this, aAttrs ) )
938 ByteString aAttrStr( (const UniString&)aAttrs, RTL_TEXTENCODING_ASCII_US );
939 rStrm << aIndentNameStr.GetBuffer() << "- Flags: " << aAttrStr.GetBuffer() << endl;
942 // Methods
943 rStrm << aIndentNameStr.GetBuffer() << "- Methods:" << endl;
944 for( USHORT i = 0; i < pMethods->Count(); i++ )
946 SbxVariableRef& r = pMethods->GetRef( i );
947 SbxVariable* pVar = r;
948 if( pVar )
950 XubString aLine( aIndent );
951 aLine.AppendAscii( " - " );
952 aLine += pVar->GetName( SbxNAME_SHORT_TYPES );
953 XubString aAttrs2;
954 if( CollectAttrs( pVar, aAttrs2 ) )
955 aLine += aAttrs2;
956 if( !pVar->IsA( TYPE(SbxMethod) ) )
957 aLine.AppendAscii( " !! Not a Method !!" );
958 rStrm.WriteByteString( aLine, RTL_TEXTENCODING_ASCII_US );
960 // bei Object-Methods auch das Object ausgeben
961 if ( pVar->GetValues_Impl().eType == SbxOBJECT &&
962 pVar->GetValues_Impl().pObj &&
963 pVar->GetValues_Impl().pObj != this &&
964 pVar->GetValues_Impl().pObj != GetParent() )
966 rStrm << " contains ";
967 ((SbxObject*) pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill );
969 else
970 rStrm << endl;
974 // Properties
975 rStrm << aIndentNameStr.GetBuffer() << "- Properties:" << endl;
977 for( USHORT i = 0; i < pProps->Count(); i++ )
979 SbxVariableRef& r = pProps->GetRef( i );
980 SbxVariable* pVar = r;
981 if( pVar )
983 XubString aLine( aIndent );
984 aLine.AppendAscii( " - " );
985 aLine += pVar->GetName( SbxNAME_SHORT_TYPES );
986 XubString aAttrs3;
987 if( CollectAttrs( pVar, aAttrs3 ) )
988 aLine += aAttrs3;
989 if( !pVar->IsA( TYPE(SbxProperty) ) )
990 aLine.AppendAscii( " !! Not a Property !!" );
991 rStrm.WriteByteString( aLine, RTL_TEXTENCODING_ASCII_US );
993 // bei Object-Properties auch das Object ausgeben
994 if ( pVar->GetValues_Impl().eType == SbxOBJECT &&
995 pVar->GetValues_Impl().pObj &&
996 pVar->GetValues_Impl().pObj != this &&
997 pVar->GetValues_Impl().pObj != GetParent() )
999 rStrm << " contains ";
1000 ((SbxObject*) pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill );
1002 else
1003 rStrm << endl;
1008 // Objects
1009 rStrm << aIndentNameStr.GetBuffer() << "- Objects:" << endl;
1011 for( USHORT i = 0; i < pObjs->Count(); i++ )
1013 SbxVariableRef& r = pObjs->GetRef( i );
1014 SbxVariable* pVar = r;
1015 if ( pVar )
1017 rStrm << aIndentNameStr.GetBuffer() << " - Sub";
1018 if ( pVar->ISA(SbxObject) )
1019 ((SbxObject*) pVar)->Dump( rStrm, bFill );
1020 else if ( pVar->ISA(SbxVariable) )
1021 ((SbxVariable*) pVar)->Dump( rStrm, bFill );
1026 rStrm << aIndentNameStr.GetBuffer() << "}" << endl << endl;
1027 --nLevel;
1030 SvDispatch* SbxObject::GetSvDispatch()
1032 return NULL;
1035 BOOL SbxMethod::Run( SbxValues* pValues )
1037 SbxValues aRes;
1038 if( !pValues )
1039 pValues = &aRes;
1040 pValues->eType = SbxVARIANT;
1041 return Get( *pValues );
1044 SbxClassType SbxMethod::GetClass() const
1046 return SbxCLASS_METHOD;
1049 SbxClassType SbxProperty::GetClass() const
1051 return SbxCLASS_PROPERTY;
1054 void SbxObject::GarbageCollection( ULONG nObjects )
1056 /* [Beschreibung]
1058 Diese statische Methode durchsucht die n"achsten 'nObjects' der zur Zeit
1059 existierenden <SbxObject>-Instanzen nach zyklischen Referenzen, die sich
1060 nur noch selbst am Leben erhalten. Ist 'nObjects==0', dann werden
1061 alle existierenden durchsucht.
1063 zur Zeit nur implementiert: Object -> Parent-Property -> Parent -> Object
1067 (void)nObjects;
1069 static BOOL bInGarbageCollection = FALSE;
1070 if ( bInGarbageCollection )
1071 return;
1072 bInGarbageCollection = TRUE;
1074 #if 0
1075 // erstes Object dieser Runde anspringen
1076 BOOL bAll = !nObjects;
1077 if ( bAll )
1078 rObjects.First();
1079 SbxObject *pObj = rObjects.GetCurObject();
1080 if ( !pObj )
1081 pObj = rObjects.First();
1083 while ( pObj && 0 != nObjects-- )
1085 // hat der Parent nur noch 1 Ref-Count?
1086 SbxObject *pParent = PTR_CAST( SbxObject, pObj->GetParent() );
1087 if ( pParent && 1 == pParent->GetRefCount() )
1089 // dann alle Properies des Objects durchsuchen
1090 SbxArray *pProps = pObj->GetProperties();
1091 for ( USHORT n = 0; n < pProps->Count(); ++n )
1093 // verweist die Property auf den Parent des Object?
1094 SbxVariable *pProp = pProps->Get(n);
1095 const SbxValues &rValues = pProp->GetValues_Impl();
1096 if ( SbxOBJECT == rValues.eType &&
1097 pParent == rValues.pObj )
1099 #ifdef DBG_UTIL
1100 DbgOutf( "SBX: %s.%s with Object %s was garbage",
1101 pObj->GetName().GetStr(),
1102 pProp->GetName().GetStr(),
1103 pParent->GetName().GetStr() );
1104 #endif
1105 // dann freigeben
1106 pProp->SbxValue::Clear();
1107 Sound::Beep();
1108 break;
1113 // zum n"achsten
1114 pObj = rObjects.Next();
1115 if ( !bAll && !pObj )
1116 pObj = rObjects.First();
1118 #endif
1120 // AB 28.10. Zur 507a vorerst raus, da SfxBroadcaster::Enable() wegfaellt
1121 #if 0
1122 #ifdef DBG_UTIL
1123 SbxVarList_Impl &rVars = GetSbxData_Impl()->aVars;
1124 DbgOutf( "SBX: garbage collector done, %lu objects remainding",
1125 rVars.Count() );
1126 if ( rVars.Count() > 200 && rVars.Count() < 210 )
1128 SvFileStream aStream( "d:\\tmp\\dump.sbx", STREAM_STD_WRITE );
1129 SfxBroadcaster::Enable(FALSE);
1130 for ( ULONG n = 0; n < rVars.Count(); ++n )
1132 SbxVariable *pVar = rVars.GetObject(n);
1133 SbxObject *pObj = PTR_CAST(SbxObject, pVar);
1134 USHORT nFlags = pVar->GetFlags();
1135 pVar->SetFlag(SBX_NO_BROADCAST);
1136 if ( pObj )
1137 pObj->Dump(aStream);
1138 else if ( !pVar->GetParent() || !pVar->GetParent()->ISA(SbxObject) )
1139 pVar->Dump(aStream);
1140 pVar->SetFlags(nFlags);
1142 SfxBroadcaster::Enable(TRUE);
1144 #endif
1145 #endif
1146 bInGarbageCollection = FALSE;