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
SbxObject(const XubString & rClass)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
SbxObject(const SbxObject & rObj)61 SbxObject::SbxObject( const SbxObject& rObj )
62 : SvRefBase( rObj ), SbxVariable( rObj.GetType() ),
63 SfxListener( rObj )
64 {
65 *this = rObj;
66 }
67
operator =(const SbxObject & r)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
CheckParentsOnDelete(SbxObject * pObj,SbxArray * p)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
~SbxObject()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
GetType() const116 SbxDataType SbxObject::GetType() const
117 {
118 return SbxOBJECT;
119 }
120
GetClass() const121 SbxClassType SbxObject::GetClass() const
122 {
123 return SbxCLASS_OBJECT;
124 }
125
Clear()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
SFX_NOTIFY(SfxBroadcaster &,const TypeId &,const SfxHint & rHint,const TypeId &)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
IsClass(const XubString & rName) const175 sal_Bool SbxObject::IsClass( const XubString& rName ) const
176 {
177 return sal_Bool( aClassName.EqualsIgnoreCaseAscii( rName ) );
178 }
179
FindUserData(sal_uInt32 nData)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
Find(const XubString & rName,SbxClassType t)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( sal_False, "Invalid SBX class" );
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
Call(const XubString & rName,SbxArray * pParam)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
GetDfltProperty()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 }
SetDfltProperty(const XubString & rName)318 void SbxObject::SetDfltProperty( const XubString& rName )
319 {
320 if ( rName != aDfltPropName )
321 pDfltProp = NULL;
322 aDfltPropName = rName;
323 SetModified( sal_True );
324 }
325
SetDfltProperty(SbxProperty * p)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
FindVar(SbxVariable * pVar,sal_uInt16 & nArrayIdx)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( sal_False, "Invalid SBX class" );
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
Make(const XubString & rName,SbxClassType ct,SbxDataType dt,bool bIsRuntimeFunction)379 SbxVariable* SbxObject::Make( const XubString& rName, SbxClassType ct, SbxDataType dt, bool bIsRuntimeFunction )
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( sal_False, "Invalid SBX class" );
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, bIsRuntimeFunction );
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
MakeObject(const XubString & rName,const XubString & rClass)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
Insert(SbxVariable * pVar)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
QuickInsert(SbxVariable * pVar)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( sal_False, "Invalid SBX class" );
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
VCPtrInsert(SbxVariable * pVar)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( sal_False, "Invalid SBX class" );
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
Remove(const XubString & rName,SbxClassType t)611 void SbxObject::Remove( const XubString& rName, SbxClassType t )
612 {
613 Remove( SbxObject::Find( rName, t ) );
614 }
615
Remove(SbxVariable * pVar)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!)
VCPtrRemove(SbxVariable * pVar)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
VCPtrFindVar(SbxVariable * pVar,sal_uInt16 & nArrayIdx)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( sal_False, "Invalid SBX class" );
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
SetPos(SbxVariable * pVar,sal_uInt16 nPos)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
LoadArray(SvStream & rStrm,SbxObject * pThis,SbxArray * pArray)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
LoadData(SvStream & rStrm,sal_uInt16 nVer)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
StoreData(SvStream & rStrm) const770 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
GenerateSource(const XubString & rLinePrefix,const SbxObject *)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
CollectAttrs(const SbxBase * p,XubString & rRes)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
Dump(SvStream & rStrm,sal_Bool bFill)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
GetSvDispatch()1026 SvDispatch* SbxObject::GetSvDispatch()
1027 {
1028 return NULL;
1029 }
1030
Run(SbxValues * pValues)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
GetClass() const1040 SbxClassType SbxMethod::GetClass() const
1041 {
1042 return SbxCLASS_METHOD;
1043 }
1044
GetClass() const1045 SbxClassType SbxProperty::GetClass() const
1046 {
1047 return SbxCLASS_PROPERTY;
1048 }
1049
GarbageCollection(sal_uIntPtr nObjects)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