1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: sbxobj.cxx,v $
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>
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
)
59 pNameProp
= GetSbxRes( STRING_NAMEPROP
);
60 pParentProp
= GetSbxRes( STRING_PARENTPROP
);
61 nNameHash
= MakeHashCode( String::CreateFromAscii( pNameProp
) );
62 nParentHash
= MakeHashCode( String::CreateFromAscii( pParentProp
) );
65 SbxObject::SetName( rClass
);
68 SbxObject::SbxObject( const SbxObject
& rObj
)
69 : SvRefBase( rObj
), SbxVariable( rObj
.GetType() ),
75 SbxObject
& SbxObject::operator=( const SbxObject
& r
)
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
;
88 // Da die Variablen uebernommen wurden, ist dies OK
89 pDfltProp
= r
.pDfltProp
;
90 SetName( r
.GetName() );
91 SetFlags( r
.GetFlags() );
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
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
);
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
);
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
);
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
) )
163 pVar
->PutString( GetName() );
165 SetName( pVar
->GetString() );
167 else if( nHash_
== nParentHash
168 && aVarName
.EqualsIgnoreCaseAscii( pParentProp
) )
170 SbxObject
* p_
= GetParent();
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
) )
189 SbxVariable
* pRes
= pMethods
->FindUserData( nData
);
191 pRes
= pProps
->FindUserData( nData
);
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
;
215 SbxVariable
* SbxObject::Find( const XubString
& rName
, SbxClassType t
)
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",
225 ( t
>= SbxCLASS_DONTCARE
&& t
<= SbxCLASS_OBJECT
)
226 ? pCls
[ t
-1 ] : "Unknown class", aNameStr1
.GetBuffer(), aNameStr1
.GetBuffer() );
231 SbxVariable
* pRes
= NULL
;
232 pObjs
->SetFlag( SBX_EXTSEARCH
);
233 if( t
== SbxCLASS_DONTCARE
)
235 pRes
= pMethods
->Find( rName
, SbxCLASS_METHOD
);
237 pRes
= pProps
->Find( rName
, SbxCLASS_PROPERTY
);
239 pRes
= pObjs
->Find( rName
, t
);
243 SbxArray
* pArray
= NULL
;
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;
251 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
254 pRes
= pArray
->Find( rName
, t
);
256 // Extended Search im Objekt-Array?
257 // Fuer Objekte und DontCare ist das Objektarray bereits
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
;
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() );
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!
303 pMeth
->SetParameters( pParam
);
304 pMeth
->Broadcast( SBX_HINT_DATAWANTED
);
305 pMeth
->SetParameters( NULL
);
308 SetError( SbxERR_NO_METHOD
);
312 SbxProperty
* SbxObject::GetDfltProperty()
314 if ( !pDfltProp
&& aDfltPropName
.Len() )
316 pDfltProp
= (SbxProperty
*) Find( aDfltPropName
, SbxCLASS_PROPERTY
);
318 pDfltProp
= (SbxProperty
*) Make( aDfltPropName
, SbxCLASS_PROPERTY
, SbxVARIANT
);
322 void SbxObject::SetDfltProperty( const XubString
& rName
)
324 if ( rName
!= aDfltPropName
)
326 aDfltPropName
= rName
;
330 void SbxObject::SetDfltProperty( SbxProperty
* p
)
335 SbxArray
* pArray
= FindVar( p
, n
);
337 if( p
->GetParent() != this )
338 p
->SetParent( this );
339 Broadcast( SBX_HINT_OBJECTCHANGED
);
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;
359 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
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() );
368 for( USHORT i
= 0; i
< pArray
->Count(); i
++ )
370 SbxVariableRef
& rRef
= pArray
->GetRef( i
);
371 if( (SbxVariable
*) rRef
== pOld
)
373 nArrayIdx
= i
; break;
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
;
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;
394 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
398 // Collections duerfen gleichnamige Objekte enthalten
399 if( !( ct
== SbxCLASS_OBJECT
&& ISA(SbxCollection
) ) )
401 SbxVariable
* pRes
= pArray
->Find( rName
, ct
);
404 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus
406 if( pRes->GetHashCode() != nNameHash
407 && pRes->GetHashCode() != nParentHash )
409 XubString aMsg( "SBX-Element \"" );
410 aMsg += pRes->GetName();
411 aMsg += "\"\n in Objekt \"";
413 aMsg += "\" bereits vorhanden";
414 DbgError( (const char*)aMsg.GetStr() );
421 SbxVariable
* pVar
= NULL
;
424 case SbxCLASS_VARIABLE
:
425 case SbxCLASS_PROPERTY
:
426 pVar
= new SbxProperty( rName
, dt
);
428 case SbxCLASS_METHOD
:
429 pVar
= new SbxMethod( rName
, dt
);
431 case SbxCLASS_OBJECT
:
432 pVar
= CreateObject( rName
);
436 pVar
->SetParent( this );
437 pArray
->Put( pVar
, pArray
->Count() );
439 // Das Objekt lauscht immer
440 StartListening( pVar
->GetBroadcaster(), TRUE
);
441 Broadcast( SBX_HINT_OBJECTCHANGED
);
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
);
453 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus
455 if( pRes->GetHashCode() != nNameHash
456 && pRes->GetHashCode() != nParentHash )
458 XubString aMsg( "SBX-Objekt \"" );
459 aMsg += pRes->GetName();
460 aMsg += "\"\n in Objekt \"";
462 aMsg += "\" bereits vorhanden";
463 DbgError( (const char*)aMsg.GetStr() );
467 return PTR_CAST(SbxObject
,pRes
);
470 SbxObject
* pVar
= CreateObject( rClass
);
473 pVar
->SetName( rName
);
474 pVar
->SetParent( this );
475 pObjs
->Put( pVar
, pObjs
->Count() );
477 // Das Objekt lauscht immer
478 StartListening( pVar
->GetBroadcaster(), TRUE
);
479 Broadcast( SBX_HINT_OBJECTCHANGED
);
484 void SbxObject::Insert( SbxVariable
* pVar
)
487 SbxArray
* pArray
= FindVar( pVar
, nIdx
);
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();
499 SbxVariable
* pOld
= pArray
->Get( nIdx
);
500 // schon drin: ueberschreiben
504 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus
506 if( pOld->GetHashCode() != nNameHash
507 && pOld->GetHashCode() != nParentHash )
509 XubString aMsg( "SBX-Element \"" );
510 aMsg += pVar->GetName();
511 aMsg += "\"\n in Objekt \"";
513 aMsg += "\" bereits vorhanden";
514 DbgError( (const char*)aMsg.GetStr() );
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 );
531 Broadcast( SBX_HINT_OBJECTCHANGED
);
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() );
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
;
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;
562 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
567 StartListening( pVar
->GetBroadcaster(), TRUE
);
568 pArray
->Put( pVar
, pArray
->Count() );
569 if( pVar
->GetParent() != this )
570 pVar
->SetParent( this );
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() );
588 // AB 23.3.1997, Spezial-Methode, gleichnamige Controls zulassen
589 void SbxObject::VCPtrInsert( SbxVariable
* pVar
)
591 SbxArray
* pArray
= NULL
;
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;
601 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
606 StartListening( pVar
->GetBroadcaster(), TRUE
);
607 pArray
->Put( pVar
, pArray
->Count() );
608 if( pVar
->GetParent() != this )
609 pVar
->SetParent( this );
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
)
623 SbxArray
* pArray
= FindVar( pVar
, nIdx
);
624 if( pArray
&& nIdx
< pArray
->Count() )
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
);
633 SbxVariableRef pVar_
= pArray
->Get( nIdx
);
634 if( pVar_
->IsBroadcaster() )
635 EndListening( pVar_
->GetBroadcaster(), TRUE
);
636 if( (SbxVariable
*) pVar_
== pDfltProp
)
638 pArray
->Remove( nIdx
);
639 if( pVar_
->GetParent() == this )
640 pVar_
->SetParent( NULL
);
642 Broadcast( SBX_HINT_OBJECTCHANGED
);
646 // AB 23.3.1997, Loeschen per Pointer fuer Controls (doppelte Namen!)
647 void SbxObject::VCPtrRemove( SbxVariable
* pVar
)
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
)
659 pArray
->Remove( nIdx
);
660 if( xVar
->GetParent() == this )
661 xVar
->SetParent( NULL
);
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;
678 DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
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;
697 void SbxObject::SetPos( SbxVariable
* pVar
, USHORT nPos
)
700 SbxArray
* pArray
= FindVar( pVar
, nIdx
);
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
);
721 for( USHORT i
= 0; i
< p
->Count(); i
++ )
723 SbxVariableRef
& r
= p
->GetRef( i
);
724 SbxVariable
* pVar
= r
;
727 pVar
->SetParent( pThis
);
728 pThis
->StartListening( pVar
->GetBroadcaster(), 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
745 if( !SbxVariable::LoadData( rStrm
, nVer
) )
747 // Wenn kein fremdes Objekt enthalten ist, uns selbst eintragen
748 if( aData
.eType
== SbxOBJECT
&& !aData
.pObj
)
752 rStrm
.ReadByteString( aClassName
, RTL_TEXTENCODING_ASCII_US
);
753 rStrm
.ReadByteString( aDfltProp
, RTL_TEXTENCODING_ASCII_US
);
754 ULONG nPos
= rStrm
.Tell();
756 if( !LoadPrivateData( rStrm
, nVer
) )
758 ULONG nNewPos
= rStrm
.Tell();
760 DBG_ASSERT( nPos
>= nNewPos
, "SBX: Zu viele Daten eingelesen" );
761 if( nPos
!= nNewPos
)
763 if( !LoadArray( rStrm
, this, pMethods
)
764 || !LoadArray( rStrm
, this, pProps
)
765 || !LoadArray( rStrm
, this, pObjs
) )
768 if( aDfltProp
.Len() )
769 pDfltProp
= (SbxProperty
*) pProps
->Find( aDfltProp
, SbxCLASS_PROPERTY
);
770 SetModified( FALSE
);
774 BOOL
SbxObject::StoreData( SvStream
& rStrm
) const
776 if( !SbxVariable::StoreData( rStrm
) )
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
) )
787 ULONG nNew
= rStrm
.Tell();
789 rStrm
<< (UINT32
) ( nNew
- nPos
);
791 if( !pMethods
->Store( rStrm
) )
793 if( !pProps
->Store( rStrm
) )
795 if( !pObjs
->Store( rStrm
) )
797 ((SbxObject
*) this)->SetModified( FALSE
);
801 XubString
SbxObject::GenerateSource( const XubString
&rLinePrefix
,
804 // Properties in einem String einsammeln
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
818 aSource
.AppendAscii( "\n" );
822 aSource
+= rLinePrefix
;
824 aSource
+= aPropName
;
825 aSource
.AppendAscii( " = " );
827 // den Property-Wert textuell darstellen
828 switch ( xProp
->GetType() )
837 // Strings in Anf"uhrungszeichen
838 aSource
.AppendAscii( "\"" );
839 aSource
+= xProp
->GetString();
840 aSource
.AppendAscii( "\"" );
846 // sonstiges wie z.B. Zahlen direkt
847 aSource
+= xProp
->GetString();
856 static BOOL
CollectAttrs( const SbxBase
* p
, XubString
& rRes
)
860 aAttrs
.AssignAscii( "Hidden" );
861 if( p
->IsSet( SBX_EXTSEARCH
) )
865 aAttrs
.AppendAscii( "ExtSearch" );
867 if( !p
->IsVisible() )
871 aAttrs
.AppendAscii( "Invisible" );
873 if( p
->IsSet( SBX_DONTSTORE
) )
877 aAttrs
.AppendAscii( "DontStore" );
881 rRes
.AssignAscii( " (" );
893 void SbxObject::Dump( SvStream
& rStrm
, BOOL bFill
)
896 static USHORT nLevel
= 0;
899 rStrm
<< "<too deep>" << endl
;
904 for ( USHORT n
= 1; n
< nLevel
; ++n
)
905 aIndent
.AppendAscii( " " );
907 // ggf. Objekt vervollst"andigen
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
);
915 << ByteString::CreateFromInt64( (ULONG
) this ).GetBuffer() << "=='"
916 << ( aNameStr
.Len() ? aNameStr
.GetBuffer() : "<unnamed>" ) << "', "
917 << "of class '" << aClassNameStr
.GetBuffer() << "', "
919 << ByteString::CreateFromInt64( GetRefCount() ).GetBuffer()
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>" ) << "'";
929 rStrm
<< "no parent ";
930 rStrm
<< " )" << endl
;
931 ByteString
aIndentNameStr( (const UniString
&)aIndent
, RTL_TEXTENCODING_ASCII_US
);
932 rStrm
<< aIndentNameStr
.GetBuffer() << "{" << endl
;
936 if( CollectAttrs( this, aAttrs
) )
938 ByteString
aAttrStr( (const UniString
&)aAttrs
, RTL_TEXTENCODING_ASCII_US
);
939 rStrm
<< aIndentNameStr
.GetBuffer() << "- Flags: " << aAttrStr
.GetBuffer() << endl
;
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
;
950 XubString
aLine( aIndent
);
951 aLine
.AppendAscii( " - " );
952 aLine
+= pVar
->GetName( SbxNAME_SHORT_TYPES
);
954 if( CollectAttrs( pVar
, 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
);
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
;
983 XubString
aLine( aIndent
);
984 aLine
.AppendAscii( " - " );
985 aLine
+= pVar
->GetName( SbxNAME_SHORT_TYPES
);
987 if( CollectAttrs( pVar
, 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
);
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
;
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
;
1030 SvDispatch
* SbxObject::GetSvDispatch()
1035 BOOL
SbxMethod::Run( SbxValues
* pValues
)
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
)
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
1069 static BOOL bInGarbageCollection
= FALSE
;
1070 if ( bInGarbageCollection
)
1072 bInGarbageCollection
= TRUE
;
1075 // erstes Object dieser Runde anspringen
1076 BOOL bAll
= !nObjects
;
1079 SbxObject
*pObj
= rObjects
.GetCurObject();
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
)
1100 DbgOutf( "SBX: %s.%s with Object %s was garbage",
1101 pObj
->GetName().GetStr(),
1102 pProp
->GetName().GetStr(),
1103 pParent
->GetName().GetStr() );
1106 pProp
->SbxValue::Clear();
1114 pObj
= rObjects
.Next();
1115 if ( !bAll
&& !pObj
)
1116 pObj
= rObjects
.First();
1120 // AB 28.10. Zur 507a vorerst raus, da SfxBroadcaster::Enable() wegfaellt
1123 SbxVarList_Impl
&rVars
= GetSbxData_Impl()->aVars
;
1124 DbgOutf( "SBX: garbage collector done, %lu objects remainding",
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
);
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
);
1146 bInGarbageCollection
= FALSE
;