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, 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( !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, 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 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