xref: /trunk/main/basic/source/sbx/sbxobj.cxx (revision e1f63238)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basic.hxx"
26 #include <tools/stream.hxx>
27 #include <vcl/sound.hxx>
28 #include <basic/sbx.hxx>
29 #include <basic/sbxbase.hxx>
30 #include "sbxres.hxx"
31 #include <svl/brdcst.hxx>
32 
33 TYPEINIT1(SbxMethod,SbxVariable)
34 TYPEINIT1(SbxProperty,SbxVariable)
35 TYPEINIT2(SbxObject,SbxVariable,SfxListener)
36 
37 static const char* pNameProp;				// Name-Property
38 static const char* pParentProp;				// Parent-Property
39 
40 static sal_uInt16 nNameHash = 0, nParentHash = 0;
41 
42 /////////////////////////////////////////////////////////////////////////
43 
44 /////////////////////////////////////////////////////////////////////////
45 
46 SbxObject::SbxObject( const XubString& rClass )
47 		 : SbxVariable( SbxOBJECT ), aClassName( rClass )
48 {
49 	aData.pObj = this;
50 	if( !nNameHash )
51 	{
52 		pNameProp = GetSbxRes( STRING_NAMEPROP );
53 		pParentProp = GetSbxRes( STRING_PARENTPROP );
54 		nNameHash = MakeHashCode( String::CreateFromAscii( pNameProp ) );
55 		nParentHash = MakeHashCode( String::CreateFromAscii( pParentProp ) );
56 	}
57 	SbxObject::Clear();
58 	SbxObject::SetName( rClass );
59 }
60 
61 SbxObject::SbxObject( const SbxObject& rObj )
62     : SvRefBase( rObj ), SbxVariable( rObj.GetType() ),
63       SfxListener( rObj )
64 {
65 	*this = rObj;
66 }
67 
68 SbxObject& SbxObject::operator=( const SbxObject& r )
69 {
70 	if( &r != this )
71 	{
72 		SbxVariable::operator=( r );
73 		aClassName = r.aClassName;
74 		pMethods   = new SbxArray;
75 		pProps     = new SbxArray;
76 		pObjs      = new SbxArray( SbxOBJECT );
77 		// Die Arrays werden kopiert, die Inhalte uebernommen
78 		*pMethods  = *r.pMethods;
79 		*pProps    = *r.pProps;
80 		*pObjs     = *r.pObjs;
81 		// Da die Variablen uebernommen wurden, ist dies OK
82 		pDfltProp  = r.pDfltProp;
83 		SetName( r.GetName() );
84 		SetFlags( r.GetFlags() );
85 		SetModified( sal_True );
86 	}
87 	return *this;
88 }
89 
90 static void CheckParentsOnDelete( SbxObject* pObj, SbxArray* p )
91 {
92 	for( sal_uInt16 i = 0; i < p->Count(); i++ )
93 	{
94 		SbxVariableRef& rRef = p->GetRef( i );
95 		if( rRef->IsBroadcaster() )
96 			pObj->EndListening( rRef->GetBroadcaster(), sal_True );
97 		// Hat das Element mehr als eine Referenz und noch einen Listener?
98 		if( rRef->GetRefCount() > 1 )
99 		{
100 			rRef->SetParent( NULL );
101 			DBG_ASSERT( !rRef->IsBroadcaster() || rRef->GetBroadcaster().GetListenerCount(), "Object element with dangling parent" );
102 		}
103 	}
104 }
105 
106 SbxObject::~SbxObject()
107 {
108 	CheckParentsOnDelete( this, pProps );
109 	CheckParentsOnDelete( this, pMethods );
110 	CheckParentsOnDelete( this, pObjs );
111 
112 	// avoid handling in ~SbxVariable as SBX_DIM_AS_NEW == SBX_GBLSEARCH
113 	ResetFlag( SBX_DIM_AS_NEW );
114 }
115 
116 SbxDataType SbxObject::GetType() const
117 {
118 	return SbxOBJECT;
119 }
120 
121 SbxClassType SbxObject::GetClass() const
122 {
123 	return SbxCLASS_OBJECT;
124 }
125 
126 void SbxObject::Clear()
127 {
128 	pMethods   = new SbxArray;
129 	pProps     = new SbxArray;
130 	pObjs      = new SbxArray( SbxOBJECT );
131 	SbxVariable* p;
132 	p = Make( String::CreateFromAscii( pNameProp ), SbxCLASS_PROPERTY, SbxSTRING );
133 	p->SetFlag( SBX_DONTSTORE );
134 	p = Make( String::CreateFromAscii( pParentProp ), SbxCLASS_PROPERTY, SbxOBJECT );
135 	p->ResetFlag( SBX_WRITE );
136 	p->SetFlag( SBX_DONTSTORE );
137 	pDfltProp  = NULL;
138 	SetModified( sal_False );
139 }
140 
141 void SbxObject::SFX_NOTIFY( SfxBroadcaster&, const TypeId&,
142 							const SfxHint& rHint, const TypeId& )
143 {
144 	const SbxHint* p = PTR_CAST(SbxHint,&rHint);
145 	if( p )
146 	{
147 		sal_uIntPtr nId = p->GetId();
148 		sal_Bool bRead  = sal_Bool( nId == SBX_HINT_DATAWANTED );
149 		sal_Bool bWrite = sal_Bool( nId == SBX_HINT_DATACHANGED );
150 		SbxVariable* pVar = p->GetVar();
151 		if( bRead || bWrite )
152 		{
153 			XubString aVarName( pVar->GetName() );
154 			sal_uInt16 nHash_ = MakeHashCode( aVarName );
155 			if( nHash_ == nNameHash
156 			 && aVarName.EqualsIgnoreCaseAscii( pNameProp ) )
157 			{
158 				if( bRead )
159 					pVar->PutString( GetName() );
160 				else
161 					SetName( pVar->GetString() );
162 			}
163 			else if( nHash_ == nParentHash
164 			 && aVarName.EqualsIgnoreCaseAscii( pParentProp ) )
165 			{
166 				SbxObject* p_ = GetParent();
167 				if( !p_ )
168 					p_ = this;
169 				pVar->PutObject( p_ );
170 			}
171 		}
172 	}
173 }
174 
175 sal_Bool SbxObject::IsClass( const XubString& rName ) const
176 {
177 	return sal_Bool( aClassName.EqualsIgnoreCaseAscii( rName ) );
178 }
179 
180 SbxVariable* SbxObject::FindUserData( sal_uInt32 nData )
181 {
182 	if( !GetAll( SbxCLASS_DONTCARE ) )
183 		return NULL;
184 
185 	SbxVariable* pRes = pMethods->FindUserData( nData );
186 	if( !pRes )
187 		pRes = pProps->FindUserData( nData );
188 	if( !pRes )
189 		pRes = pObjs->FindUserData( nData );
190 	// Search in den Parents?
191 	if( !pRes && IsSet( SBX_GBLSEARCH ) )
192 	{
193 		SbxObject* pCur = this;
194 		while( !pRes && pCur->pParent )
195 		{
196 			// Ich selbst bin schon durchsucht worden!
197 			sal_uInt16 nOwn = pCur->GetFlags();
198 			pCur->ResetFlag( SBX_EXTSEARCH );
199 			// Ich suche bereits global!
200 			sal_uInt16 nPar = pCur->pParent->GetFlags();
201 			pCur->pParent->ResetFlag( SBX_GBLSEARCH );
202 			pRes = pCur->pParent->FindUserData( nData );
203 			pCur->SetFlags( nOwn );
204 			pCur->pParent->SetFlags( nPar );
205 			pCur = pCur->pParent;
206 		}
207 	}
208 	return pRes;
209 }
210 
211 SbxVariable* SbxObject::Find( const XubString& rName, SbxClassType t )
212 {
213 #ifdef DBG_UTIL
214 	static sal_uInt16 nLvl = 0;
215 	static const char* pCls[] =
216 	{ "DontCare","Array","Value","Variable","Method","Property","Object" };
217 	ByteString aNameStr1( (const UniString&)rName, RTL_TEXTENCODING_ASCII_US );
218 	ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
219 	DbgOutf( "SBX: Search %.*s %s %s in %s",
220 		nLvl++, "                              ",
221 		( t >= SbxCLASS_DONTCARE && t <= SbxCLASS_OBJECT )
222 		 ? pCls[ t-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() );
223 #endif
224 
225 	if( !GetAll( t ) )
226 		return NULL;
227 	SbxVariable* pRes = NULL;
228 	pObjs->SetFlag( SBX_EXTSEARCH );
229 	if( t == SbxCLASS_DONTCARE )
230 	{
231 		pRes = pMethods->Find( rName, SbxCLASS_METHOD );
232 		if( !pRes )
233 			pRes = pProps->Find( rName, SbxCLASS_PROPERTY );
234 		if( !pRes )
235 			pRes = pObjs->Find( rName, t );
236 	}
237 	else
238 	{
239 		SbxArray* pArray = NULL;
240 		switch( t )
241 		{
242 			case SbxCLASS_VARIABLE:
243 			case SbxCLASS_PROPERTY: pArray = pProps;	break;
244 			case SbxCLASS_METHOD: 	pArray = pMethods;	break;
245 			case SbxCLASS_OBJECT: 	pArray = pObjs;		break;
246 			default:
247 				DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
248 		}
249 		if( pArray )
250 			pRes = pArray->Find( rName, t );
251 	}
252 	// Extended Search im Objekt-Array?
253 	// Fuer Objekte und DontCare ist das Objektarray bereits
254 	// durchsucht worden
255 	if( !pRes && ( t == SbxCLASS_METHOD || t == SbxCLASS_PROPERTY ) )
256 		pRes = pObjs->Find( rName, t );
257 	// Search in den Parents?
258 	if( !pRes && IsSet( SBX_GBLSEARCH ) )
259 	{
260 		SbxObject* pCur = this;
261 		while( !pRes && pCur->pParent )
262 		{
263 			// Ich selbst bin schon durchsucht worden!
264 			sal_uInt16 nOwn = pCur->GetFlags();
265 			pCur->ResetFlag( SBX_EXTSEARCH );
266 			// Ich suche bereits global!
267 			sal_uInt16 nPar = pCur->pParent->GetFlags();
268 			pCur->pParent->ResetFlag( SBX_GBLSEARCH );
269 			pRes = pCur->pParent->Find( rName, t );
270 			pCur->SetFlags( nOwn );
271 			pCur->pParent->SetFlags( nPar );
272 			pCur = pCur->pParent;
273 		}
274 	}
275 #ifdef DBG_UTIL
276 	nLvl--;
277 	if( pRes )
278 	{
279 		ByteString aNameStr3( (const UniString&)rName, RTL_TEXTENCODING_ASCII_US );
280 		ByteString aNameStr4( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
281 		DbgOutf( "SBX: Found %.*s %s in %s",
282 			nLvl, "                              ", aNameStr3.GetBuffer(), aNameStr4.GetBuffer() );
283 	}
284 #endif
285 	return pRes;
286 }
287 
288 // Kurzform: Die Parent-Kette wird durchsucht
289 // Das ganze rekursiv, da Call() ueberladen sein kann
290 // Qualified Names sind zugelassen
291 
292 sal_Bool SbxObject::Call( const XubString& rName, SbxArray* pParam )
293 {
294 	SbxVariable* pMeth = FindQualified( rName, SbxCLASS_DONTCARE);
295 	if( pMeth && pMeth->ISA(SbxMethod) )
296 	{
297 		// FindQualified() koennte schon zugeschlagen haben!
298 		if( pParam )
299 			pMeth->SetParameters( pParam );
300 		pMeth->Broadcast( SBX_HINT_DATAWANTED );
301 		pMeth->SetParameters( NULL );
302 		return sal_True;
303 	}
304 	SetError( SbxERR_NO_METHOD );
305 	return sal_False;
306 }
307 
308 SbxProperty* SbxObject::GetDfltProperty()
309 {
310 	if ( !pDfltProp && aDfltPropName.Len() )
311 	{
312 		pDfltProp = (SbxProperty*) Find( aDfltPropName, SbxCLASS_PROPERTY );
313 		if( !pDfltProp )
314 			pDfltProp = (SbxProperty*) Make( aDfltPropName, SbxCLASS_PROPERTY, SbxVARIANT );
315 	}
316 	return pDfltProp;
317 }
318 void SbxObject::SetDfltProperty( const XubString& rName )
319 {
320 	if ( rName != aDfltPropName )
321 		pDfltProp = NULL;
322 	aDfltPropName = rName;
323 	SetModified( sal_True );
324 }
325 
326 void SbxObject::SetDfltProperty( SbxProperty* p )
327 {
328 	if( p )
329 	{
330 		sal_uInt16 n;
331 		SbxArray* pArray = FindVar( p, n );
332 		pArray->Put( p, n );
333 		if( p->GetParent() != this )
334 			p->SetParent( this );
335 		Broadcast( SBX_HINT_OBJECTCHANGED );
336 	}
337 	pDfltProp = p;
338 	SetModified( sal_True );
339 }
340 
341 // Suchen einer bereits vorhandenen Variablen. Falls sie gefunden wurde,
342 // wird der Index gesetzt, sonst wird der Count des Arrays geliefert.
343 // In jedem Fall wird das korrekte Array geliefert.
344 
345 SbxArray* SbxObject::FindVar( SbxVariable* pVar, sal_uInt16& nArrayIdx )
346 {
347 	SbxArray* pArray = NULL;
348 	if( pVar ) switch( pVar->GetClass() )
349 	{
350 		case SbxCLASS_VARIABLE:
351 		case SbxCLASS_PROPERTY: pArray = pProps;	break;
352 		case SbxCLASS_METHOD: 	pArray = pMethods;	break;
353 		case SbxCLASS_OBJECT: 	pArray = pObjs;		break;
354 		default:
355 			DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
356 	}
357 	if( pArray )
358 	{
359 		nArrayIdx = pArray->Count();
360 		// ist die Variable per Name vorhanden?
361 		pArray->ResetFlag( SBX_EXTSEARCH );
362 		SbxVariable* pOld = pArray->Find( pVar->GetName(), pVar->GetClass() );
363 		if( pOld )
364 		  for( sal_uInt16 i = 0; i < pArray->Count(); i++ )
365 		{
366 			SbxVariableRef& rRef = pArray->GetRef( i );
367 			if( (SbxVariable*) rRef == pOld )
368 			{
369 				nArrayIdx = i; break;
370 			}
371 		}
372 	}
373 	return pArray;
374 }
375 
376 // Falls ein neues Objekt eingerichtet wird, wird es, falls es bereits
377 // eines mit diesem Namen gibt, indiziert.
378 
379 SbxVariable* SbxObject::Make( const XubString& rName, SbxClassType ct, SbxDataType dt )
380 {
381 	// Ist das Objekt bereits vorhanden?
382 	SbxArray* pArray = NULL;
383 	switch( ct )
384 	{
385 		case SbxCLASS_VARIABLE:
386 		case SbxCLASS_PROPERTY: pArray = pProps;	break;
387 		case SbxCLASS_METHOD: 	pArray = pMethods;	break;
388 		case SbxCLASS_OBJECT: 	pArray = pObjs;		break;
389 		default:
390 			DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
391 	}
392 	if( !pArray )
393 		return NULL;
394 	// Collections duerfen gleichnamige Objekte enthalten
395 	if( !( ct == SbxCLASS_OBJECT && ISA(SbxCollection) ) )
396 	{
397 		SbxVariable* pRes = pArray->Find( rName, ct );
398 		if( pRes )
399 		{
400 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus
401 #ifdef DBG_UTIL
402 			if( pRes->GetHashCode() != nNameHash
403 			 && pRes->GetHashCode() != nParentHash )
404 			{
405 				XubString aMsg( "SBX-Element \"" );
406 				aMsg += pRes->GetName();
407 				aMsg += "\"\n in Objekt \"";
408 				aMsg += GetName();
409 				aMsg += "\" bereits vorhanden";
410 				DbgError( (const char*)aMsg.GetStr() );
411 			}
412 #endif
413 */
414 			return pRes;
415 		}
416 	}
417 	SbxVariable* pVar = NULL;
418 	switch( ct )
419 	{
420 		case SbxCLASS_VARIABLE:
421 		case SbxCLASS_PROPERTY:
422 			pVar = new SbxProperty( rName, dt );
423 			break;
424 		case SbxCLASS_METHOD:
425 			pVar = new SbxMethod( rName, dt );
426 			break;
427 		case SbxCLASS_OBJECT:
428 			pVar = CreateObject( rName );
429 			break;
430 		default: break;
431 	}
432 	pVar->SetParent( this );
433 	pArray->Put( pVar, pArray->Count() );
434 	SetModified( sal_True );
435 	// Das Objekt lauscht immer
436 	StartListening( pVar->GetBroadcaster(), sal_True );
437 	Broadcast( SBX_HINT_OBJECTCHANGED );
438 	return pVar;
439 }
440 
441 SbxObject* SbxObject::MakeObject( const XubString& rName, const XubString& rClass )
442 {
443 	// Ist das Objekt bereits vorhanden?
444 	if( !ISA(SbxCollection) )
445 	{
446 		SbxVariable* pRes = pObjs->Find( rName, SbxCLASS_OBJECT );
447 		if( pRes )
448 		{
449 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus
450 #ifdef DBG_UTIL
451 			if( pRes->GetHashCode() != nNameHash
452 			 && pRes->GetHashCode() != nParentHash )
453 			{
454 				XubString aMsg( "SBX-Objekt \"" );
455 				aMsg += pRes->GetName();
456 				aMsg += "\"\n in Objekt \"";
457 				aMsg += GetName();
458 				aMsg += "\" bereits vorhanden";
459 				DbgError( (const char*)aMsg.GetStr() );
460 			}
461 #endif
462 */
463 			return PTR_CAST(SbxObject,pRes);
464 		}
465 	}
466 	SbxObject* pVar = CreateObject( rClass );
467 	if( pVar )
468 	{
469 		pVar->SetName( rName );
470 		pVar->SetParent( this );
471 		pObjs->Put( pVar, pObjs->Count() );
472 		SetModified( sal_True );
473 		// Das Objekt lauscht immer
474 		StartListening( pVar->GetBroadcaster(), sal_True );
475 		Broadcast( SBX_HINT_OBJECTCHANGED );
476 	}
477 	return pVar;
478 }
479 
480 void SbxObject::Insert( SbxVariable* pVar )
481 {
482 	sal_uInt16 nIdx;
483 	SbxArray* pArray = FindVar( pVar, nIdx );
484 	if( pArray )
485 	{
486 		// Hinein damit. Man sollte allerdings auf die Pointer aufpassen!
487 		if( nIdx < pArray->Count() )
488 		{
489 			// dann gibt es dieses Element bereits
490 			// Bei Collections duerfen gleichnamige Objekte hinein
491 			if( pArray == pObjs && ISA(SbxCollection) )
492 				nIdx = pArray->Count();
493 			else
494 			{
495 				SbxVariable* pOld = pArray->Get( nIdx );
496 				// schon drin: ueberschreiben
497 				if( pOld == pVar )
498 					return;
499 
500 /* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus
501 #ifdef DBG_UTIL
502 				if( pOld->GetHashCode() != nNameHash
503 				 && pOld->GetHashCode() != nParentHash )
504 				{
505 					XubString aMsg( "SBX-Element \"" );
506 					aMsg += pVar->GetName();
507 					aMsg += "\"\n in Objekt \"";
508 					aMsg += GetName();
509 					aMsg += "\" bereits vorhanden";
510 					DbgError( (const char*)aMsg.GetStr() );
511 				}
512 #endif
513 */
514 				EndListening( pOld->GetBroadcaster(), sal_True );
515 				if( pVar->GetClass() == SbxCLASS_PROPERTY )
516 				{
517 					if( pOld == pDfltProp )
518 						pDfltProp = (SbxProperty*) pVar;
519 				}
520 			}
521 		}
522 		StartListening( pVar->GetBroadcaster(), sal_True );
523 		pArray->Put( pVar, nIdx );
524 		if( pVar->GetParent() != this )
525 			pVar->SetParent( this );
526 		SetModified( sal_True );
527 		Broadcast( SBX_HINT_OBJECTCHANGED );
528 #ifdef DBG_UTIL
529 	static const char* pCls[] =
530 	{ "DontCare","Array","Value","Variable","Method","Property","Object" };
531 	XubString aVarName( pVar->GetName() );
532 	if ( !aVarName.Len() && pVar->ISA(SbxObject) )
533 		aVarName = PTR_CAST(SbxObject,pVar)->GetClassName();
534 	ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US );
535 	ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
536 	DbgOutf( "SBX: Insert %s %s in %s",
537 		( pVar->GetClass() >= SbxCLASS_DONTCARE &&
538 		  pVar->GetClass() <= SbxCLASS_OBJECT )
539 			? pCls[ pVar->GetClass()-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() );
540 #endif
541 	}
542 }
543 
544 // AB 23.4.1997, Optimierung, Einfuegen ohne Ueberpruefung auf doppelte
545 // Eintraege und ohne Broadcasts, wird nur in SO2/auto.cxx genutzt
546 void SbxObject::QuickInsert( SbxVariable* pVar )
547 {
548 	SbxArray* pArray = NULL;
549 	if( pVar )
550 	{
551 		switch( pVar->GetClass() )
552 		{
553 			case SbxCLASS_VARIABLE:
554 			case SbxCLASS_PROPERTY: pArray = pProps;	break;
555 			case SbxCLASS_METHOD: 	pArray = pMethods;	break;
556 			case SbxCLASS_OBJECT: 	pArray = pObjs;		break;
557 			default:
558 				DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
559 		}
560 	}
561 	if( pArray )
562 	{
563 		StartListening( pVar->GetBroadcaster(), sal_True );
564 		pArray->Put( pVar, pArray->Count() );
565 		if( pVar->GetParent() != this )
566 			pVar->SetParent( this );
567 		SetModified( sal_True );
568 #ifdef DBG_UTIL
569 	static const char* pCls[] =
570 	{ "DontCare","Array","Value","Variable","Method","Property","Object" };
571 	XubString aVarName( pVar->GetName() );
572 	if ( !aVarName.Len() && pVar->ISA(SbxObject) )
573 		aVarName = PTR_CAST(SbxObject,pVar)->GetClassName();
574 	ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US );
575 	ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
576 	DbgOutf( "SBX: Insert %s %s in %s",
577 		( pVar->GetClass() >= SbxCLASS_DONTCARE &&
578 		  pVar->GetClass() <= SbxCLASS_OBJECT )
579 			? pCls[ pVar->GetClass()-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() );
580 #endif
581 	}
582 }
583 
584 // AB 23.3.1997, Spezial-Methode, gleichnamige Controls zulassen
585 void SbxObject::VCPtrInsert( SbxVariable* pVar )
586 {
587 	SbxArray* pArray = NULL;
588 	if( pVar )
589 	{
590 		switch( pVar->GetClass() )
591 		{
592 			case SbxCLASS_VARIABLE:
593 			case SbxCLASS_PROPERTY: pArray = pProps;	break;
594 			case SbxCLASS_METHOD: 	pArray = pMethods;	break;
595 			case SbxCLASS_OBJECT: 	pArray = pObjs;		break;
596 			default:
597 				DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
598 		}
599 	}
600 	if( pArray )
601 	{
602 		StartListening( pVar->GetBroadcaster(), sal_True );
603 		pArray->Put( pVar, pArray->Count() );
604 		if( pVar->GetParent() != this )
605 			pVar->SetParent( this );
606 		SetModified( sal_True );
607 		Broadcast( SBX_HINT_OBJECTCHANGED );
608 	}
609 }
610 
611 void SbxObject::Remove( const XubString& rName, SbxClassType t )
612 {
613 	Remove( SbxObject::Find( rName, t ) );
614 }
615 
616 void SbxObject::Remove( SbxVariable* pVar )
617 {
618 	sal_uInt16 nIdx;
619 	SbxArray* pArray = FindVar( pVar, nIdx );
620 	if( pArray && nIdx < pArray->Count() )
621 	{
622 #ifdef DBG_UTIL
623 	XubString aVarName( pVar->GetName() );
624 	if ( !aVarName.Len() && pVar->ISA(SbxObject) )
625 		aVarName = PTR_CAST(SbxObject,pVar)->GetClassName();
626 	ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US );
627 	ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US );
628 #endif
629 		SbxVariableRef pVar_ = pArray->Get( nIdx );
630 		if( pVar_->IsBroadcaster() )
631 			EndListening( pVar_->GetBroadcaster(), sal_True );
632 		if( (SbxVariable*) pVar_ == pDfltProp )
633 			pDfltProp = NULL;
634 		pArray->Remove( nIdx );
635 		if( pVar_->GetParent() == this )
636 			pVar_->SetParent( NULL );
637 		SetModified( sal_True );
638 		Broadcast( SBX_HINT_OBJECTCHANGED );
639 	}
640 }
641 
642 // AB 23.3.1997, Loeschen per Pointer fuer Controls (doppelte Namen!)
643 void SbxObject::VCPtrRemove( SbxVariable* pVar )
644 {
645 	sal_uInt16 nIdx;
646 	// Neu FindVar-Methode, sonst identisch mit normaler Methode
647 	SbxArray* pArray = VCPtrFindVar( pVar, nIdx );
648 	if( pArray && nIdx < pArray->Count() )
649 	{
650 		SbxVariableRef xVar = pArray->Get( nIdx );
651 		if( xVar->IsBroadcaster() )
652 			EndListening( xVar->GetBroadcaster(), sal_True );
653 		if( (SbxVariable*) xVar == pDfltProp )
654 			pDfltProp = NULL;
655 		pArray->Remove( nIdx );
656 		if( xVar->GetParent() == this )
657 			xVar->SetParent( NULL );
658 		SetModified( sal_True );
659 		Broadcast( SBX_HINT_OBJECTCHANGED );
660 	}
661 }
662 
663 // AB 23.3.1997, Zugehoerige Spezial-Methode, nur ueber Pointer suchen
664 SbxArray* SbxObject::VCPtrFindVar( SbxVariable* pVar, sal_uInt16& nArrayIdx )
665 {
666 	SbxArray* pArray = NULL;
667 	if( pVar ) switch( pVar->GetClass() )
668 	{
669 		case SbxCLASS_VARIABLE:
670 		case SbxCLASS_PROPERTY: pArray = pProps;	break;
671 		case SbxCLASS_METHOD: 	pArray = pMethods;	break;
672 		case SbxCLASS_OBJECT: 	pArray = pObjs;		break;
673 		default:
674 			DBG_ASSERT( !this, "Ungueltige SBX-Klasse" );
675 	}
676 	if( pArray )
677 	{
678 		nArrayIdx = pArray->Count();
679 		for( sal_uInt16 i = 0; i < pArray->Count(); i++ )
680 		{
681 			SbxVariableRef& rRef = pArray->GetRef( i );
682 			if( (SbxVariable*) rRef == pVar )
683 			{
684 				nArrayIdx = i; break;
685 			}
686 		}
687 	}
688 	return pArray;
689 }
690 
691 
692 
693 void SbxObject::SetPos( SbxVariable* pVar, sal_uInt16 nPos )
694 {
695 	sal_uInt16 nIdx;
696 	SbxArray* pArray = FindVar( pVar, nIdx );
697 	if( pArray )
698 	{
699 		if( nPos >= pArray->Count() )
700 			nPos = pArray->Count() - 1;
701 		if( nIdx < ( pArray->Count() - 1 ) )
702 		{
703 			SbxVariableRef refVar = pArray->Get( nIdx );
704 			pArray->Remove( nIdx );
705 			pArray->Insert( refVar, nPos );
706 		}
707 	}
708 //	SetModified( sal_True );
709 //	Broadcast( SBX_HINT_OBJECTCHANGED );
710 }
711 
712 static sal_Bool LoadArray( SvStream& rStrm, SbxObject* pThis, SbxArray* pArray )
713 {
714 	SbxArrayRef p = (SbxArray*) SbxBase::Load( rStrm );
715 	if( !p.Is() )
716 		return sal_False;
717 	for( sal_uInt16 i = 0; i < p->Count(); i++ )
718 	{
719 		SbxVariableRef& r = p->GetRef( i );
720 		SbxVariable* pVar = r;
721 		if( pVar )
722 		{
723 			pVar->SetParent( pThis );
724 			pThis->StartListening( pVar->GetBroadcaster(), sal_True );
725 		}
726 	}
727 	pArray->Merge( p );
728 	return sal_True;
729 }
730 
731 // Der Load eines Objekts ist additiv!
732 
733 sal_Bool SbxObject::LoadData( SvStream& rStrm, sal_uInt16 nVer )
734 {
735 	// Hilfe fuer das Einlesen alter Objekte: einfach sal_True zurueck,
736 	// LoadPrivateData() muss Default-Zustand herstellen
737 	if( !nVer )
738 		return sal_True;
739 
740 	pDfltProp = NULL;
741 	if( !SbxVariable::LoadData( rStrm, nVer ) )
742 		return sal_False;
743 	// Wenn kein fremdes Objekt enthalten ist, uns selbst eintragen
744 	if( aData.eType == SbxOBJECT && !aData.pObj )
745 		aData.pObj = this;
746 	sal_uInt32 nSize;
747 	XubString aDfltProp;
748 	rStrm.ReadByteString( aClassName, RTL_TEXTENCODING_ASCII_US );
749 	rStrm.ReadByteString( aDfltProp, RTL_TEXTENCODING_ASCII_US );
750 	sal_uIntPtr nPos = rStrm.Tell();
751 	rStrm >> nSize;
752 	if( !LoadPrivateData( rStrm, nVer ) )
753 		return sal_False;
754 	sal_uIntPtr nNewPos = rStrm.Tell();
755 	nPos += nSize;
756 	DBG_ASSERT( nPos >= nNewPos, "SBX: Zu viele Daten eingelesen" );
757 	if( nPos != nNewPos )
758 		rStrm.Seek( nPos );
759 	if( !LoadArray( rStrm, this, pMethods )
760 	 || !LoadArray( rStrm, this, pProps )
761 	 || !LoadArray( rStrm, this, pObjs ) )
762 		return sal_False;
763 	// Properties setzen
764 	if( aDfltProp.Len() )
765 		pDfltProp = (SbxProperty*) pProps->Find( aDfltProp, SbxCLASS_PROPERTY );
766 	SetModified( sal_False );
767 	return sal_True;
768 }
769 
770 sal_Bool SbxObject::StoreData( SvStream& rStrm ) const
771 {
772 	if( !SbxVariable::StoreData( rStrm ) )
773 		return sal_False;
774 	XubString aDfltProp;
775 	if( pDfltProp )
776 		aDfltProp = pDfltProp->GetName();
777 	rStrm.WriteByteString( aClassName, RTL_TEXTENCODING_ASCII_US );
778 	rStrm.WriteByteString( aDfltProp, RTL_TEXTENCODING_ASCII_US );
779 	sal_uIntPtr nPos = rStrm.Tell();
780 	rStrm << (sal_uInt32) 0L;
781 	if( !StorePrivateData( rStrm ) )
782 		return sal_False;
783 	sal_uIntPtr nNew = rStrm.Tell();
784 	rStrm.Seek( nPos );
785 	rStrm << (sal_uInt32) ( nNew - nPos );
786 	rStrm.Seek( nNew );
787 	if( !pMethods->Store( rStrm ) )
788 		return sal_False;
789 	if( !pProps->Store( rStrm ) )
790 		return sal_False;
791 	if( !pObjs->Store( rStrm ) )
792 		return sal_False;
793 	((SbxObject*) this)->SetModified( sal_False );
794 	return sal_True;
795 }
796 
797 XubString SbxObject::GenerateSource( const XubString &rLinePrefix,
798 								  const SbxObject* )
799 {
800 	// Properties in einem String einsammeln
801 	XubString aSource;
802 	SbxArrayRef xProps( GetProperties() );
803 	bool bLineFeed = false;
804 	for ( sal_uInt16 nProp = 0; nProp < xProps->Count(); ++nProp )
805 	{
806 		SbxPropertyRef xProp = (SbxProperty*) xProps->Get(nProp);
807 		XubString aPropName( xProp->GetName() );
808 		if ( xProp->CanWrite()
809 		 && !( xProp->GetHashCode() == nNameHash
810 			&& aPropName.EqualsIgnoreCaseAscii( pNameProp ) ) )
811 		{
812 			// ausser vor dem ersten Property immer einen Umbruch einfuegen
813 			if ( bLineFeed )
814 				aSource.AppendAscii( "\n" );
815 			else
816 				bLineFeed = true;
817 
818 			aSource += rLinePrefix;
819 			aSource += '.';
820 			aSource += aPropName;
821 			aSource.AppendAscii( " = " );
822 
823 			// den Property-Wert textuell darstellen
824 			switch ( xProp->GetType() )
825 			{
826 				case SbxEMPTY:
827 				case SbxNULL:
828 					// kein Wert
829 					break;
830 
831 				case SbxSTRING:
832 				{
833 					// Strings in Anf"uhrungszeichen
834 					aSource.AppendAscii( "\"" );
835 					aSource += xProp->GetString();
836 					aSource.AppendAscii( "\"" );
837 					break;
838 				}
839 
840 				default:
841 				{
842 					// sonstiges wie z.B. Zahlen direkt
843 					aSource += xProp->GetString();
844 					break;
845 				}
846 			}
847 		}
848 	}
849 	return aSource;
850 }
851 
852 static sal_Bool CollectAttrs( const SbxBase* p, XubString& rRes )
853 {
854 	XubString aAttrs;
855 	if( p->IsHidden() )
856 		aAttrs.AssignAscii( "Hidden" );
857 	if( p->IsSet( SBX_EXTSEARCH ) )
858 	{
859 		if( aAttrs.Len() )
860 			aAttrs += ',';
861 		aAttrs.AppendAscii( "ExtSearch" );
862 	}
863 	if( !p->IsVisible() )
864 	{
865 		if( aAttrs.Len() )
866 			aAttrs += ',';
867 		aAttrs.AppendAscii( "Invisible" );
868 	}
869 	if( p->IsSet( SBX_DONTSTORE ) )
870 	{
871 		if( aAttrs.Len() )
872 			aAttrs += ',';
873 		aAttrs.AppendAscii( "DontStore" );
874 	}
875 	if( aAttrs.Len() )
876 	{
877 		rRes.AssignAscii( " (" );
878 		rRes += aAttrs;
879 		rRes += ')';
880 		return sal_True;
881 	}
882 	else
883 	{
884 		rRes.Erase();
885 		return sal_False;
886 	}
887 }
888 
889 void SbxObject::Dump( SvStream& rStrm, sal_Bool bFill )
890 {
891 	// Einr"uckung
892 	static sal_uInt16 nLevel = 0;
893 	if ( nLevel > 10 )
894 	{
895 		rStrm << "<too deep>" << endl;
896 		return;
897 	}
898 	++nLevel;
899 	String aIndent;
900 	for ( sal_uInt16 n = 1; n < nLevel; ++n )
901 		aIndent.AppendAscii( "    " );
902 
903 	// ggf. Objekt vervollst"andigen
904 	if ( bFill )
905 		GetAll( SbxCLASS_DONTCARE );
906 
907 	// Daten des Objekts selbst ausgeben
908 	ByteString aNameStr( (const UniString&)GetName(), RTL_TEXTENCODING_ASCII_US );
909 	ByteString aClassNameStr( (const UniString&)aClassName, RTL_TEXTENCODING_ASCII_US );
910 	rStrm << "Object( "
911           << ByteString::CreateFromInt64( (sal_uIntPtr) this ).GetBuffer() << "=='"
912           << ( aNameStr.Len() ? aNameStr.GetBuffer() : "<unnamed>" ) << "', "
913           << "of class '" << aClassNameStr.GetBuffer() << "', "
914           << "counts "
915           << ByteString::CreateFromInt64( GetRefCount() ).GetBuffer()
916           << " refs, ";
917 	if ( GetParent() )
918 	{
919 		ByteString aParentNameStr( (const UniString&)GetName(), RTL_TEXTENCODING_ASCII_US );
920 		rStrm << "in parent "
921               << ByteString::CreateFromInt64( (sal_uIntPtr) GetParent() ).GetBuffer()
922 			  << "=='" << ( aParentNameStr.Len() ? aParentNameStr.GetBuffer() : "<unnamed>" ) << "'";
923 	}
924 	else
925 		rStrm << "no parent ";
926 	rStrm << " )" << endl;
927 	ByteString aIndentNameStr( (const UniString&)aIndent, RTL_TEXTENCODING_ASCII_US );
928 	rStrm << aIndentNameStr.GetBuffer() << "{" << endl;
929 
930 	// Flags
931 	XubString aAttrs;
932 	if( CollectAttrs( this, aAttrs ) )
933 	{
934 		ByteString aAttrStr( (const UniString&)aAttrs, RTL_TEXTENCODING_ASCII_US );
935 		rStrm << aIndentNameStr.GetBuffer() << "- Flags: " << aAttrStr.GetBuffer() << endl;
936 	}
937 
938 	// Methods
939 	rStrm << aIndentNameStr.GetBuffer() << "- Methods:" << endl;
940 	for( sal_uInt16 i = 0; i < pMethods->Count(); i++ )
941 	{
942 		SbxVariableRef& r = pMethods->GetRef( i );
943 		SbxVariable* pVar = r;
944 		if( pVar )
945 		{
946 			XubString aLine( aIndent );
947 			aLine.AppendAscii( "  - " );
948 			aLine += pVar->GetName( SbxNAME_SHORT_TYPES );
949             XubString aAttrs2;
950 			if( CollectAttrs( pVar, aAttrs2 ) )
951 				aLine += aAttrs2;
952 			if( !pVar->IsA( TYPE(SbxMethod) ) )
953 				aLine.AppendAscii( "  !! Not a Method !!" );
954 			rStrm.WriteByteString( aLine, RTL_TEXTENCODING_ASCII_US );
955 
956 			// bei Object-Methods auch das Object ausgeben
957 			if ( pVar->GetValues_Impl().eType == SbxOBJECT &&
958 					pVar->GetValues_Impl().pObj &&
959 					pVar->GetValues_Impl().pObj != this &&
960 					pVar->GetValues_Impl().pObj != GetParent() )
961 			{
962 				rStrm << " contains ";
963 				((SbxObject*) pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill );
964 			}
965 			else
966 				rStrm << endl;
967 		}
968 	}
969 
970 	// Properties
971 	rStrm << aIndentNameStr.GetBuffer() << "- Properties:" << endl;
972 	{
973 		for( sal_uInt16 i = 0; i < pProps->Count(); i++ )
974 		{
975 			SbxVariableRef& r = pProps->GetRef( i );
976 			SbxVariable* pVar = r;
977 			if( pVar )
978 			{
979 				XubString aLine( aIndent );
980 				aLine.AppendAscii( "  - " );
981 				aLine += pVar->GetName( SbxNAME_SHORT_TYPES );
982 				XubString aAttrs3;
983 				if( CollectAttrs( pVar, aAttrs3 ) )
984 					aLine += aAttrs3;
985 				if( !pVar->IsA( TYPE(SbxProperty) ) )
986 					aLine.AppendAscii( "  !! Not a Property !!" );
987 				rStrm.WriteByteString( aLine, RTL_TEXTENCODING_ASCII_US );
988 
989 				// bei Object-Properties auch das Object ausgeben
990 				if ( pVar->GetValues_Impl().eType == SbxOBJECT &&
991 						pVar->GetValues_Impl().pObj &&
992 						pVar->GetValues_Impl().pObj != this &&
993 						pVar->GetValues_Impl().pObj != GetParent() )
994 				{
995 					rStrm << " contains ";
996 					((SbxObject*) pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill );
997 				}
998 				else
999 					rStrm << endl;
1000 			}
1001 		}
1002 	}
1003 
1004 	// Objects
1005 	rStrm << aIndentNameStr.GetBuffer() << "- Objects:" << endl;
1006 	{
1007 		for( sal_uInt16 i = 0; i < pObjs->Count(); i++ )
1008 		{
1009 			SbxVariableRef& r = pObjs->GetRef( i );
1010 			SbxVariable* pVar = r;
1011 			if ( pVar )
1012 			{
1013 				rStrm << aIndentNameStr.GetBuffer() << "  - Sub";
1014 				if ( pVar->ISA(SbxObject) )
1015 					((SbxObject*) pVar)->Dump( rStrm, bFill );
1016 				else if ( pVar->ISA(SbxVariable) )
1017 					((SbxVariable*) pVar)->Dump( rStrm, bFill );
1018 			}
1019 		}
1020 	}
1021 
1022 	rStrm << aIndentNameStr.GetBuffer() << "}" << endl << endl;
1023 	--nLevel;
1024 }
1025 
1026 SvDispatch* SbxObject::GetSvDispatch()
1027 {
1028 	return NULL;
1029 }
1030 
1031 sal_Bool SbxMethod::Run( SbxValues* pValues )
1032 {
1033 	SbxValues aRes;
1034 	if( !pValues )
1035 		pValues = &aRes;
1036 	pValues->eType = SbxVARIANT;
1037 	return Get( *pValues );
1038 }
1039 
1040 SbxClassType SbxMethod::GetClass() const
1041 {
1042 	return SbxCLASS_METHOD;
1043 }
1044 
1045 SbxClassType SbxProperty::GetClass() const
1046 {
1047 	return SbxCLASS_PROPERTY;
1048 }
1049 
1050 void SbxObject::GarbageCollection( sal_uIntPtr nObjects )
1051 
1052 /*	[Beschreibung]
1053 
1054 	Diese statische Methode durchsucht die n"achsten 'nObjects' der zur Zeit
1055 	existierenden <SbxObject>-Instanzen nach zyklischen Referenzen, die sich
1056 	nur noch selbst am Leben erhalten. Ist 'nObjects==0', dann werden
1057 	alle existierenden durchsucht.
1058 
1059 	zur Zeit nur implementiert: Object -> Parent-Property -> Parent -> Object
1060 */
1061 
1062 {
1063     (void)nObjects;
1064 
1065 	static sal_Bool bInGarbageCollection = sal_False;
1066 	if ( bInGarbageCollection )
1067 		return;
1068 	bInGarbageCollection = sal_True;
1069 
1070 #if 0
1071 	// erstes Object dieser Runde anspringen
1072 	sal_Bool bAll = !nObjects;
1073 	if ( bAll )
1074 		rObjects.First();
1075 	SbxObject *pObj = rObjects.GetCurObject();
1076 	if ( !pObj )
1077 		pObj = rObjects.First();
1078 
1079 	while ( pObj && 0 != nObjects-- )
1080 	{
1081 		// hat der Parent nur noch 1 Ref-Count?
1082 		SbxObject *pParent = PTR_CAST( SbxObject, pObj->GetParent() );
1083 		if ( pParent && 1 == pParent->GetRefCount() )
1084 		{
1085 			// dann alle Properies des Objects durchsuchen
1086 			SbxArray *pProps = pObj->GetProperties();
1087 			for ( sal_uInt16 n = 0; n < pProps->Count(); ++n )
1088 			{
1089 				// verweist die Property auf den Parent des Object?
1090 				SbxVariable *pProp = pProps->Get(n);
1091 				const SbxValues &rValues = pProp->GetValues_Impl();
1092 				if ( SbxOBJECT == rValues.eType &&
1093 					 pParent == rValues.pObj )
1094 				{
1095 #ifdef DBG_UTIL
1096 					DbgOutf( "SBX: %s.%s with Object %s was garbage",
1097 							 pObj->GetName().GetStr(),
1098 							 pProp->GetName().GetStr(),
1099 							 pParent->GetName().GetStr() );
1100 #endif
1101 					// dann freigeben
1102 					pProp->SbxValue::Clear();
1103 					Sound::Beep();
1104 					break;
1105 				}
1106 			}
1107 		}
1108 
1109 		// zum n"achsten
1110 		pObj = rObjects.Next();
1111 		if ( !bAll && !pObj )
1112 			pObj = rObjects.First();
1113 	}
1114 #endif
1115 
1116 // AB 28.10. Zur 507a vorerst raus, da SfxBroadcaster::Enable() wegfaellt
1117 #if 0
1118 #ifdef DBG_UTIL
1119 	SbxVarList_Impl &rVars = GetSbxData_Impl()->aVars;
1120 	DbgOutf( "SBX: garbage collector done, %lu objects remainding",
1121 			 rVars.Count() );
1122 	if ( rVars.Count() > 200 && rVars.Count() < 210 )
1123 	{
1124 		SvFileStream aStream( "d:\\tmp\\dump.sbx", STREAM_STD_WRITE );
1125 		SfxBroadcaster::Enable(sal_False);
1126 		for ( sal_uIntPtr n = 0; n < rVars.Count(); ++n )
1127 		{
1128 			SbxVariable *pVar = rVars.GetObject(n);
1129 			SbxObject *pObj = PTR_CAST(SbxObject, pVar);
1130 			sal_uInt16 nFlags = pVar->GetFlags();
1131 			pVar->SetFlag(SBX_NO_BROADCAST);
1132 			if ( pObj )
1133 				pObj->Dump(aStream);
1134 			else if ( !pVar->GetParent() || !pVar->GetParent()->ISA(SbxObject) )
1135 				pVar->Dump(aStream);
1136 			pVar->SetFlags(nFlags);
1137 		}
1138 		SfxBroadcaster::Enable(sal_True);
1139 	}
1140 #endif
1141 #endif
1142 	bInGarbageCollection = sal_False;
1143 }
1144 
1145